为什么添加局部变量会导致方法延迟?

时间:2014-09-16 08:21:47

标签: java android performance-testing

我最近开始阅读基准测试并为Android编写它们(用Java编写)。我知道像热身,垃圾收集器和编译器优化这样的问题,但不知道我面临的问题是否可能是由任何问题引起的。

在我的基准测试应用中,我创建了一个包含10,000个浮点变量的数组,并使用随机值对其进行初始化。 运行基准代码时:

private void runMinorBenchmarkFloat (float[] array) {
        float sum = 0;
        long startTime;
        long endTime; 

        /* Fast warm-up */
        startTime = System.nanoTime();
        for(int i=0; i<SMALL_LOOP_ITERATION_COUNT; i++)
            for(int j=0; j<TAB_SIZE; j++)
                sum += array[j];
        endTime = System.nanoTime() - startTime;
        postMessage("Warm-up for FLOAT finished in: " + endTime/1000000 + "ms.\n");

        /* Main benchmark loop */
        startTime = System.nanoTime();
        for(int i=0; i<BIG_LOOP_ITERATION_COUNT; i++)
        {
            sum = 0;
            for(int j=0; j<TAB_SIZE; j++)
                sum += array[j];
        }
        endTime = System.nanoTime() - startTime;
        postMessage("Benchmark for FLOAT finished in: " + endTime/1000000 + "ms.\n");
        postMessage("Final value: " + sum + "\n\n");
    }
在我的手机上,我有2秒的热身时间和20秒的时间用于#34;真正的&#34;循环。

现在,当我再添加两个浮点变量(sum2和sum3 - 从未在方法中使用)时:

private void runMinorBenchmarkFloat (float[] array) {
        float sum = 0, sum2 = 0, sum3 = 0; // <------- the only code change here!!!
        long startTime;
        long endTime; 

        /* Fast warm-up */
        startTime = System.nanoTime();
        for(int i=0; i<SMALL_LOOP_ITERATION_COUNT; i++)
            for(int j=0; j<TAB_SIZE; j++)
                sum += array[j];
        endTime = System.nanoTime() - startTime;
        postMessage("Warm-up for FLOAT finished in: " + endTime/1000000 + "ms.\n");

        /* Main benchmark loop */
        startTime = System.nanoTime();
        for(int i=0; i<BIG_LOOP_ITERATION_COUNT; i++)
        {
            sum = 0;
            for(int j=0; j<TAB_SIZE; j++)
                sum += array[j];
        }
        endTime = System.nanoTime() - startTime;
        postMessage("Benchmark for FLOAT finished in: " + endTime/1000000 + "ms.\n");
        postMessage("Final value: " + sum + "\n\n");
    }

执行时间从预热的2秒跳到5秒,从实际循环的20秒跳到50秒。

常数:

SMALL_LOOP_ITERATION_COUNT = 100,000 
BIG_LOOP_ITERATION_COUNT = 1,000,000

你认为这种差异可能是由对齐问题造成的(只是松散的想法)?

提前感谢您的任何答案。

编辑:

似乎每个设备上都没有出现此错误。我可以在三星Galaxy S5上重现它。 该计划的主要目标是制定一些基准。我做了四个几乎相同的函数(runMinorBenchmark____,其中 _ 是:int,short,float,double),它们仅在变量&sum;&#39;中有所不同。类型。在主要的基准测试函数中,我调用了这些函数。因为发生了上述错误,我决定将这些功能合并为一个大功能。 现在......在运行测试时我有这样的时间:  1. 37640ms。 (对于int)  2. 46728ms。 (简称)  3. 60589ms。 (浮动)  4. 34467ms。 (双倍)

我知道由于类型转换,short意味着更慢。我还认为,如果将其转换为double,浮动应该更慢(可能FPU每次都会将类型转换为double(?))。但是当我将sumFloat的变量类型从float更改为double时,float的时间与double时间相同。 我也做了这个&#34;基准&#34;在另一台似乎没有遭受这种奇怪行为的设备上,每次测试的时间几乎相同:~45000ms。 (真的没有明显的差异)。

Dalvik VM错误(?)

2 个答案:

答案 0 :(得分:2)

我拒绝相信这是你的麻烦的原因。当然编译器只是把那些未使用的变量丢掉了?你确定输入数组没有改变,或者你的常数,还是TAB_SIZE

如果您仍然确定,请通过运行此类内容并在此处粘贴输出来证明:

public void proveIt() {
    float[] inputArray = new float[10000];
    for (int i = 0; i < 10000; i++) {
        inputArray[i] = 1;
    }

    postMessage("Without declaration:");
    runMinorBenchmarkFloatA(inputArray);

    postMessage("With declaration:");
    runMinorBenchmarkFloatB(inputArray);

    postMessage("And again just to make sure...");

    postMessage("Without declaration:");
    runMinorBenchmarkFloatA(inputArray);

    postMessage("With declaration:");
    runMinorBenchmarkFloatB(inputArray);
}

long TAB_SIZE = 10000;
long SMALL_LOOP_ITERATION_COUNT = 100000;
long BIG_LOOP_ITERATION_COUNT = 1000000;

private void runMinorBenchmarkFloatA(float[] array) {
    float sum = 0;
    long startTime;
    long endTime;

    /* Fast warm-up */
    startTime = System.nanoTime();
    for (int i = 0; i < SMALL_LOOP_ITERATION_COUNT; i++)
        for (int j = 0; j < TAB_SIZE; j++)
            sum += array[j];
    endTime = System.nanoTime() - startTime;
    postMessage("Warm-up for FLOAT finished in: " + endTime
            / 1000000 + "ms.\n");

    /* Main benchmark loop */
    startTime = System.nanoTime();
    for (int i = 0; i < BIG_LOOP_ITERATION_COUNT; i++) {
        sum = 0;
        for (int j = 0; j < TAB_SIZE; j++)
            sum += array[j];
    }
    endTime = System.nanoTime() - startTime;
    postMessage("Benchmark for FLOAT finished in: " + endTime
            / 1000000 + "ms.\n");
    postMessage("Final value: " + sum + "\n\n");
}

private void runMinorBenchmarkFloatB(float[] array) {
    float sum = 0, sum2 = 0, sum3 = 0;
    long startTime;
    long endTime;

    /* Fast warm-up */
    startTime = System.nanoTime();
    for (int i = 0; i < SMALL_LOOP_ITERATION_COUNT; i++)
        for (int j = 0; j < TAB_SIZE; j++)
            sum += array[j];
    endTime = System.nanoTime() - startTime;
    postMessage("Warm-up for FLOAT finished in: " + endTime
            / 1000000 + "ms.\n");

    /* Main benchmark loop */
    startTime = System.nanoTime();
    for (int i = 0; i < BIG_LOOP_ITERATION_COUNT; i++) {
        sum = 0;
        for (int j = 0; j < TAB_SIZE; j++)
            sum += array[j];
    }
    endTime = System.nanoTime() - startTime;
    postMessage("Benchmark for FLOAT finished in: " + endTime
            / 1000000 + "ms.\n");
    postMessage("Final value: " + sum + "\n\n");
}

答案 1 :(得分:0)

  

现在,当我再添加两个浮点变量(sum2和sum3 - 从未在方法中使用)时:

float sum = 0, sum2 = 0, sum3 = 0; // <------- the only code change here!!!

但在方法中使用了sum2sum3 。它们被初始化为零。这需要时间。

如果它们没有被初始化,除了分配的堆栈帧的大小之外,生成的字节代码与它们相同和不相同,这不会影响时序。