JAVA矩阵向量乘法比C版本慢100倍

JAVA矩阵向量乘法比C版本慢100倍,java,android,c,performance,android-ndk,Java,Android,C,Performance,Android Ndk,我正在研究Android JAVA和Android NDK应用程序之间的性能差异。 我在90000多个顶点上执行了Matrix4D-Vector4D转换,作为3D图形的示例 看起来,JAVA版本几乎比C版本慢100倍。我做错什么了吗?有没有人有类似的经历 我的Java转换代码: long t1 = System.nanoTime(); for ( int i = 0; i < vCount; i++) { Vecto

我正在研究Android JAVA和Android NDK应用程序之间的性能差异。 我在90000多个顶点上执行了Matrix4D-Vector4D转换,作为3D图形的示例

看起来,JAVA版本几乎比C版本慢100倍。我做错什么了吗?有没有人有类似的经历

我的Java转换代码:

        long t1 = System.nanoTime();
        for ( int i = 0; i < vCount; i++)
        {

            Vector4 vOut = new Vector4();
            Vector4 v = vertices[i];

            vOut.v_[0] = v.v_[0] * matrix[0].v_[0];
            vOut.v_[1] = v.v_[0] * matrix[0].v_[1];
            vOut.v_[2] = v.v_[0] * matrix[0].v_[2];
            vOut.v_[3] = v.v_[0] * matrix[0].v_[3];

            vOut.v_[0] += v.v_[1] * matrix[1].v_[0];
            vOut.v_[1] += v.v_[1] * matrix[1].v_[1];
            vOut.v_[2] += v.v_[1] * matrix[1].v_[2];
            vOut.v_[3] += v.v_[1] * matrix[1].v_[3];

            vOut.v_[0] += v.v_[2] * matrix[2].v_[0];
            vOut.v_[1] += v.v_[2] * matrix[2].v_[1];
            vOut.v_[2] += v.v_[2] * matrix[2].v_[2];
            vOut.v_[3] += v.v_[2] * matrix[2].v_[3];

            vOut.v_[0] += v.v_[3] * matrix[3].v_[0];
            vOut.v_[1] += v.v_[3] * matrix[3].v_[1];
            vOut.v_[2] += v.v_[3] * matrix[3].v_[2];
            vOut.v_[3] += v.v_[3] * matrix[3].v_[3]; 

            vertices[i] = vOut;

        }
        long t2 = System.nanoTime();        
        long diff = t2 - t1;        
        double ms = (double)(diff / 1000000.0f);
        Log.w("GL2JNIView", String.format("ms %.2f ", ms));

另外,Android Java实现是通过一个名为的虚拟机实现的,该虚拟机的指令集不同于,并且不使用任何技术将某些字节码动态转换为机器码,而只是对它们进行解释。所以Dalvik在CPU限制的任务上明显比C慢


这在最近的系统中可能会发生变化。

AFAIK,Android Java实现是通过一个名为的虚拟机实现的,该虚拟机的指令集与的不同,并且不使用任何技术将某些字节码动态转换为机器码,而只是解释它们。所以Dalvik在CPU限制的任务上明显比C慢


这在最近的系统中可能会发生变化。

在每次迭代中创建一个新的矢量4。根据我自己的经验,在Android中使用新的内部循环可能会导致意外的性能问题。

每次迭代都会创建一个新的Vector4。根据我自己的经验,在Android中使用新的内部循环可能会导致意外的性能问题。

您还应该更改循环。除了@toopok4k3的答案外,您还应该尝试以下方法:

  • 转储for循环并捕获ArrayIndexOutOfBounds异常。您有一个足够大的循环来弥补try/catch的开销
  • 如果矩阵数组及其包含的值在一个循环迭代到下一个循环迭代期间没有改变,则将它们指定给循环外部的常量。取消引用数组和访问成员变量的速度不如局部变量快
  • 由于v.v_u[]使用了多次,因此将其分配给一个局部变量,并在获得下一个变量之前使用它4次
我假设以下版本中的值是双倍的

int i = 0;
try  
{
    Vector4 vOut = new Vector4();
    final double m0v0 = matrix[0].v_[0];
    final double m0v1 = matrix[0].v_[1];
    final double m0v2 = matrix[0].v_[2];
    final double m0v3 = matrix[0].v_[3];
    final double m1v0 = matrix[1].v_[0];
    final double m1v1 = matrix[1].v_[1];
    final double m1v2 = matrix[1].v_[2];
    final double m1v3 = matrix[1].v_[3];
    final double m2v0 = matrix[2].v_[0];
    final double m2v1 = matrix[2].v_[1];
    final double m2v2 = matrix[2].v_[2];
    final double m2v3 = matrix[2].v_[3];
    final double m3v0 = matrix[3].v_[0];
    final double m3v1 = matrix[3].v_[1];
    final double m3v2 = matrix[3].v_[2];
    final double m3v3 = matrix[3].v_[3];

    while (true)
    {
        Vector4 v = vertices[i];
        i++;

        double vertexVal = v.v_[0];
        vOut.v_[0] = vertexVal * m0v0;
        vOut.v_[1] = vertexVal * m0v1;
        vOut.v_[2] = vertexVal * m0v2;
        vOut.v_[3] = vertexVal * m0v3;

        vertexVal = v.v_[1];
        vOut.v_[0] += vertexVal * m1v0;
        vOut.v_[1] += vertexVal * m1v1;
        vOut.v_[2] += vertexVal * m1v2;
        vOut.v_[3] += vertexVal * m1v3;

        vertexVal = v.v_[2];
        vOut.v_[0] += vertexVal * m2v0;
        vOut.v_[1] += vertexVal * m2v1;
        vOut.v_[2] += vertexVal * m2v2;
        vOut.v_[3] += vertexVal * m2v3;

        vertexVal = v.v_[3];
        vOut.v_[0] += vertexVal * m3v0;
        vOut.v_[1] += vertexVal * m3v1;
        vOut.v_[2] += vertexVal * m3v2;
        vOut.v_[3] += vertexVal * m3v3; 

        vertices[i] = vOut;

    } 
}
catch (ArrayIndexOutOfBoundsException aioobe) 
{
    // loop is done
}

你也应该改变你的循环。除了@toopok4k3的答案外,您还应该尝试以下方法:

  • 转储for循环并捕获ArrayIndexOutOfBounds异常。您有一个足够大的循环来弥补try/catch的开销
  • 如果矩阵数组及其包含的值在一个循环迭代到下一个循环迭代期间没有改变,则将它们指定给循环外部的常量。取消引用数组和访问成员变量的速度不如局部变量快
  • 由于v.v_u[]使用了多次,因此将其分配给一个局部变量,并在获得下一个变量之前使用它4次
我假设以下版本中的值是双倍的

int i = 0;
try  
{
    Vector4 vOut = new Vector4();
    final double m0v0 = matrix[0].v_[0];
    final double m0v1 = matrix[0].v_[1];
    final double m0v2 = matrix[0].v_[2];
    final double m0v3 = matrix[0].v_[3];
    final double m1v0 = matrix[1].v_[0];
    final double m1v1 = matrix[1].v_[1];
    final double m1v2 = matrix[1].v_[2];
    final double m1v3 = matrix[1].v_[3];
    final double m2v0 = matrix[2].v_[0];
    final double m2v1 = matrix[2].v_[1];
    final double m2v2 = matrix[2].v_[2];
    final double m2v3 = matrix[2].v_[3];
    final double m3v0 = matrix[3].v_[0];
    final double m3v1 = matrix[3].v_[1];
    final double m3v2 = matrix[3].v_[2];
    final double m3v3 = matrix[3].v_[3];

    while (true)
    {
        Vector4 v = vertices[i];
        i++;

        double vertexVal = v.v_[0];
        vOut.v_[0] = vertexVal * m0v0;
        vOut.v_[1] = vertexVal * m0v1;
        vOut.v_[2] = vertexVal * m0v2;
        vOut.v_[3] = vertexVal * m0v3;

        vertexVal = v.v_[1];
        vOut.v_[0] += vertexVal * m1v0;
        vOut.v_[1] += vertexVal * m1v1;
        vOut.v_[2] += vertexVal * m1v2;
        vOut.v_[3] += vertexVal * m1v3;

        vertexVal = v.v_[2];
        vOut.v_[0] += vertexVal * m2v0;
        vOut.v_[1] += vertexVal * m2v1;
        vOut.v_[2] += vertexVal * m2v2;
        vOut.v_[3] += vertexVal * m2v3;

        vertexVal = v.v_[3];
        vOut.v_[0] += vertexVal * m3v0;
        vOut.v_[1] += vertexVal * m3v1;
        vOut.v_[2] += vertexVal * m3v2;
        vOut.v_[3] += vertexVal * m3v3; 

        vertices[i] = vOut;

    } 
}
catch (ArrayIndexOutOfBoundsException aioobe) 
{
    // loop is done
}

是的,谷歌安卓员工到处叫喊“NDK是用于性能评估操作的。”。是的,但我认为Android>4.0有JIT:这就是为什么我提到“最近的安卓系统”是对的,谷歌安卓员工到处叫喊“NDK是用于性能评估操作的。”。是的,但是我认为Android>4.0有JIT:这就是为什么我提到“最近的Android系统”谢谢。对于循环外部温度向量,我现在得到了8.3 FPS,所以这是一个问题。所以我们现在只慢了25倍!谢谢对于循环外部温度向量,我现在得到了8.3 FPS,所以这是一个问题。所以我们现在只慢了25倍!你试过使用并行数组而不是对象吗?没有,现在我只想检查单线程/核心性能。没关系,并行数组指的是将对象的每个字段放入自己的数组中,而不是使用单个对象数组,这只是一种不同的数据布局方式。所以在这个例子中,你有四个数组,矢量4的每个元素一个。你试过使用并行数组而不是对象吗?不,现在我只想检查单线程/核心性能。没关系,并行数组是指将对象的每个字段放入自己的数组中,而不是拥有一个对象数组,这只是一种不同的数据布局方式。在本例中,有四个数组,向量4的每个元素对应一个数组。