0

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

看起来,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));

性能(变换 > 90 000 个顶点 | Android 4.0.4 SGS II):(200 次运行的中值)

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

3 回答 3

5

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

于 2012-10-21T13:34:29.703 回答
0

AFAIK,Android Java 实现是通过一个名为Dalvik的虚拟机实现的,它具有与JVM不同的指令集,并且不使用任何即时编译技术将一些字节码动态转换为机器码,而只是解释它们。所以 Dalvik 在 CPU 密集型任务上显然比 C 慢。

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

于 2012-10-21T13:32:11.270 回答
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
}
于 2012-10-25T20:02:48.470 回答