空速测试,意外结果

时间:2013-01-02 22:17:51

标签: java testing

为什么这段代码

    long s, e, sum1 = 0, sum2 = 0, TRIALS = 10000000;

    for(long i=0; i<TRIALS; i++) {
        s = System.nanoTime();
        e = System.nanoTime();
        sum1 += e - s;            
        s = System.nanoTime();
        e = System.nanoTime();
        sum2 += e - s;
    }        
    System.out.println(sum1 / TRIALS);
    System.out.println(sum2 / TRIALS);

产生此结果

-60  
61 

“在我的机器上?”

编辑:
Sam I am's answer指向nanoSecond()文档,这有助于,但现在,更准确地说,为什么结果始终有利于第一笔总和?

“我的机器”:
JavaSE-1.7,Eclipse
赢得7 x64,AMD Athlon II X4 635

在循环内切换顺序会产生反向结果

for(int i=0; i<TRIALS; i++) {            
    s = System.nanoTime();
    e = System.nanoTime();
    sum2 += e - s;            
    s = System.nanoTime();
    e = System.nanoTime();
    sum1 += e - s;
}  
61
-61  

在将它添加到sum1之前查找(e-s)使得sum1为正。

for(long i=0; i<TRIALS; i++) {
    s = System.nanoTime();
    e = System.nanoTime();
    temp = e-s;
    if(temp < 0)
        count++;
    sum1 += temp;

    s = System.nanoTime();
    e = System.nanoTime();
    sum2 += e - s;
}
61  
61

正如Andrew Alcock指出的那样,sum1 + = -s + e会产生预期的结果。

for(long i=0; i<TRIALS; i++) {
    s = System.nanoTime();
    e = System.nanoTime();
    sum1 += -s + e;

    s = System.nanoTime();
    e = System.nanoTime();
    sum2 += -s + e;
}
61
61

其他一些测试:http://pastebin.com/QJ93NZxP

3 个答案:

答案 0 :(得分:2)

这个答案是假设。如果您使用有关您的环境的一些详细信息更新您的问题,那么其他人可能会提供更详细的基础答案。

nanoTime()功能通过访问具有低访问延迟的某些高分辨率计时器来工作。在x86上,我相信这是Time Stamp Counter,它是由机器的基本时钟周期驱动的。

如果你看到+/- 60 ns的一致结果,那么我相信你只是看到机器上计时器的基本间隔。

然而,负数呢?同样,假设,但如果您阅读维基百科文章,您会看到英特尔处理器可能会重新订购说明的评论。

答案 1 :(得分:1)

与roundar一起,我们对此代码进行了大量测试。总之,在以下情况下效果消失了:

  1. 在解释模式下运行相同的代码(-Xint)
  2. 将聚合逻辑订单sum += e - s更改为sum += -s + e
  3. 在一些不同的架构或不同的VM上运行(例如,我在Mac上使用Java 6运行)
  4. 放置记录语句检查s和e
  5. 对s和e执行额外的算术
  6. 此外,效果不是线程:

    1. 没有其他线程产生
    2. 仅涉及局部变量
    3. 此效果在圆形环境中100%可重现,并且始终产生完全相同的时序,即+61和-61。
    4. 效果不是时间问题,因为:

      1. 执行超过10米迭代
      2. 此效果在圆形环境中100%可重现
      3. 在所有迭代中,结果完全相同,即+61和-61。
      4. 鉴于上述情况,我相信我们在Java VM的热点模块中有一个错误。写为的代码应返回正结果,但不会。

答案 2 :(得分:0)

直接来自oracle's documentation

简而言之:更新值的频率可能导致结果不同。

  

nanoTime

     

public static long nanoTime()

     

返回最精确的可用系统计时器的当前值,以纳秒为单位。

     

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。

     

返回的值表示自固定但任意时间以来的纳秒   (也许在未来,所以价值观可能是负面的)。这种方法   提供纳秒级精度,但不一定是纳秒级   准确性。不保证值的变化频率。   连续调用的差异大于约   292年(263纳秒)将无法准确计算经过的时间   由于数字溢出。

For example, to measure how long some code takes to execute:

   long startTime = System.nanoTime();
   // ... the code being measured ...
   long estimatedTime = System.nanoTime() - startTime;


Returns:
    The current value of the system timer, in nanoseconds.
Since:
    1.5