JAVA Matrix-Vector-Multilication比C-Version慢100倍

时间:2012-10-21 13:28:13

标签: 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++)
        {

            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));

性能(转换&gt; 90 000顶点| Android 4.0.4 SGS II): (200次运行的中值)

JAVA-Version:   2 FPS
C-Version:    190 FPS

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:0)

AFAIK,Android Java实现是通过一个名为Dalvik的虚拟机,它具有与JVM不同的指令集,并且不使用任何just-in-time compilation技术将一些字节码动态转换为机器代码,但只是解释它们。所以Dalvik显然在CPU绑定任务上比C慢。

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

答案 2 :(得分:0)

你也应该改变你的循环。除了@ toopok4k3的答案,你应该尝试这些:

  • 转储for循环,只捕获一个ArrayIndexOutOfBounds异常。你有足够大的循环来弥补try / catch的开销。
  • 如果矩阵数组及其包含的值没有从一个循环迭代更改为下一个循环迭代,则将它们分配给循环外的常量。取消引用数组和访问成员变量的速度不如局部变量快。
  • 由于v.v_ []被多次使用,因此将其分配给局部变量并在获得下一个变量之前使用它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
}