我最近开始阅读关于基准测试的文章,并为Android(用Java)编写它们。我知道诸如预热、垃圾收集器和编译器优化之类的问题,但不知道我面临的问题是否是由这些问题引起的。
在我的基准测试应用程序中,我创建了一个由10000个浮点变量组成的数组,并用随机值对其进行初始化。运行基准代码时:
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 + "nn");
}
在我的手机上,我有大约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 + "nn");
}
执行时间从预热的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.37640ms。(用于int)2.46728ms。(简称)3.60589ms。(用于浮动)4.34467ms。(双)
我知道短是指较慢,因为类型铸造。我还认为,在将其铸造为双倍的情况下,浮动应该更慢(也许FPU每次都会将铸造类型铸造为双倍(?))。但是,当我将sumFloat的变量类型从float更改为double时,float的时间与double时间相同。我还在另一台设备上做了这个"基准测试",该设备似乎没有出现这种奇怪的行为,每次测试的时间几乎相同:约45000ms。(确实没有明显的差异)。
Dalvik VM错误(?)
我不相信这是造成你麻烦的原因。编译器肯定只是把那些未使用的变量扔掉了吗?您确定输入数组、常量或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 + "nn");
}
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 + "nn");
}
现在,当我再添加两个浮点变量(sum2和sum3——从未在方法中使用过)时:
float sum = 0, sum2 = 0, sum3 = 0; // <------- the only code change here!!!
但是sum2
和sum3
在该方法中被使用。它们被初始化为零。这需要时间。
如果它们没有初始化,那么生成的字节码在有和没有它们的情况下都是相同的,除了分配的堆栈帧的大小之外,这不会影响时序。