Android循环字节码比较

时间:2012-03-20 12:13:11

标签: android optimization loops bytecode dalvik

我一直在使用Android中的循环进行一些实验,并对结果感到困惑。

过去我在某处读过(在C ++中),如果你翻译这个循环:

for(int i = 0; i != Integer.MAX_VALUE; i++)
{
   // Do something
}

...进入这个循环:

for(int i = threshold; --i >= 0; )
{
    // Do the same
}

您可以获得显着的性能提升,因为第二个变体将产生与零的比较,由于处理器架构比第一个循环上的两个非零值之间的比较快得多。

我想知道这是否适用于Android,所以我开始编写代码并使用DEX来查看生成的Dalvik的字节码,以检查是否存在任何类型的编译器优化。

确实是结果:

0003dc: 1201                                   |000e: const/4 v1, #int 0 // #0  
0003de: 1402 ffff ff7f                         |000f: const v2, #float NaN // #7fffffff 
0003e4: 3321 5000                              |0012: if-ne v1, v2, 0062 // +0050 

000434: 1401 ffff ff7f                         |003a: const v1, #float NaN // #7fffffff
00043a: d801 01ff                              |003d: add-int/lit8 v1, v1, #int -1 // #ff 
00043e: 3b01 2800                              |003f: if-gez v1, 0067 // +0028 

(这与0062和0067的代码无关,因为我只关心自己的循环)。

好吧,但是我们可以清楚地看到编译器/转换器没有引入优化,因为两个循环语法都有不同的生成字节码。

现在已经设置了上下文,并且我证明了进行测试是有用的,是时候了解问题:

“我已经分析了上面的代码并发现无论循环执行的顺序如何,第一个总是花费比第二个更多的时间,我在这里缺少什么?”

像JIT编译那样对我做一些优化吗?

我希望两个循环的行为都不同,因为生成的字节码不一样。

非常感谢在这个问题上给予启发的任何努力。

2 个答案:

答案 0 :(得分:2)

我有以下想法。首先,dalvik字节码不是直接在处理器上执行的 - 它仍然是字节码,应该转换为本机代码。

其次,让我们考虑为什么C ++(x86平台)中的第二种情况会比第一种情况更快:

  1. 因此,在第一种情况下,您将获得如下代码:inc (i),然后是 比较两个值处理器将从中减去第一个值 秒并检查结果是否等于0(使用jz指令或类似的东西)。
  2. 在第二种情况下,处理器将dec (i),然后结果值将与0(使用jz)进行比较。
  3. 因此,您可以看到一条指令的第二种情况更短。我想在ARM处理器中也会出现同样的情况,这就是为什么第二个循环比第一个循环快。

答案 1 :(得分:1)

在第一个程序集中,if-ne指令比较两个值(v1和v2)并根据结果跳转。这比仅仅将一个值与零比较慢,就像在第二种情况下if-gez指令那样。但也许我误解了你的问题,你的意思是两个循环都在同一个执行时间运行吗?你的问题并不清楚。你得到什么时间?