【问题标题】:Why does adding local variables causes delay in method?为什么添加局部变量会导致方法延迟?
【发布时间】:2014-11-09 21:57:17
【问题描述】:

我最近开始阅读有关基准测试并为 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 秒的“真实”循环时间。

现在,当我再添加两个浮点变量(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”类型上有所不同。在主基准函数中,我调用了这些函数。因为发生了上述错误,我决定将这些功能合并为一个大功能。 现在......在运行测试时,我有这样的时间: 1. 37640 毫秒。 (对于整数) 2. 46728 毫秒。 (简称) 3. 60589 毫秒。 (用于浮动) 4. 34467 毫秒。 (双)

我知道由于类型转换,short 意味着更慢。我还认为浮点数在将其转换为双倍的情况下应该更慢(也许 FPU 每次都会将类型转换为双倍(?))。但是,当我将 sumFloat 的变量类型从 float 更改为 double 时,float 的时间与 double 时间相同。 我还在另一台设备上做了这个“基准测试”,它似乎没有受到这种奇怪行为的影响,每次测试的时间几乎相同:~45000ms。 (真的没有明显的差异)。

Dalvik VM 错误 (?)

【问题讨论】:

  • 没有。添加两个“未使用”字段不会影响循环的实际运行时间。肯定有其他问题。
  • 我同意@TheLostMind。添加两个浮点变量应该不会显着增加您的执行时间。如您所见,CPU 可以非常快速地处理 10,000 个浮点数,因此它没有理由不能快速处理这两个。
  • 感谢您的回答。我同意你们俩的观点,但这就是真正发生的事情。你有什么想法可以进一步研究吗?
  • 假设从投票中有人尝试成功地复制此问题,任何人都可以确认这是一个可以复制的问题吗?如果是这样,这是一个很棒的问题(抱歉,我现在没有能力自己测试)。
  • 您在哪里运行这些功能?在 OnCreate() 或其他地方?我会尝试重现它。如果可以的话,你能把整个活动放上来供参考吗?

标签: java android performance-testing


【解决方案1】:

我拒绝相信这是你麻烦的原因。当然,编译器只是把那些未使用的变量扔掉了吗?你确定输入数组没有改变,或者你的常量,或者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");
}

【讨论】:

  • 好的,我在两个不同的设备上做了,结果如下: 第一个设备,之前出现问题的设备(Samsung Galaxy S5):1. 21170ms。 2. 55626 毫秒。 3. 20640 毫秒。 4. 55522ms。但在第二台设备(三星 Note)上:1. 32194ms。 2. 34008 毫秒。 3. 32171 毫秒。 4. 34359 毫秒。
【解决方案2】:

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

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

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

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

【讨论】:

  • 我认为它不会造成这么大的延误,是吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-09
  • 2012-08-30
  • 2012-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多