为什么我的System.nanoTime()坏了?

Cha*_*had 11 java timestamp nanotime

我和我这个时代的另一位开发人员最近从一台Core 2 Duo机器搬到了新的Core 2 Quad 9505; 两者都使用JDK 1.6.0_18运行Windows XP SP3 32位.

在这样做的时候,我们对一些时序/统计/度量聚合代码的自动单元测试很快就会失败,因为看起来似乎是从System.nanoTime()返回的荒谬值.

在我的机器上可靠地显示此行为的测试代码是:

import static org.junit.Assert.assertThat;

import org.hamcrest.Matchers;
import org.junit.Test;

public class NanoTest {

  @Test
  public void testNanoTime() throws InterruptedException {
    final long sleepMillis = 5000;

    long nanosBefore = System.nanoTime();
    long millisBefore = System.currentTimeMillis();

    Thread.sleep(sleepMillis);

    long nanosTaken = System.nanoTime() - nanosBefore;
    long millisTaken = System.currentTimeMillis() - millisBefore;

    System.out.println("nanosTaken="+nanosTaken);
    System.out.println("millisTaken="+millisTaken);

    // Check it slept within 10% of requested time
    assertThat((double)millisTaken, Matchers.closeTo(sleepMillis, sleepMillis * 0.1));
    assertThat((double)nanosTaken, Matchers.closeTo(sleepMillis * 1000000, sleepMillis * 1000000 * 0.1));
  }

}
Run Code Online (Sandbox Code Playgroud)

典型输出:

millisTaken=5001
nanosTaken=2243785148
Run Code Online (Sandbox Code Playgroud)

100x运行产生的纳米结果占实际睡眠时间的33%至60%; 通常约为40%.

我理解Windows中计时器准确性的弱点,并且读过线程之类的Is System.nanoTime()等相关线程是否一致?但是我的理解是System.nanoTime()的目的完全是我们使用它的目的: - 测量经过的时间; 比currentTimeMillis()更准确.

有谁知道为什么它会返回如此疯狂的结果?这可能是硬件架构问题(唯一重要的是这台机器上的CPU /主板)?Windows HAL与我当前的硬件有问题?一个JDK问题?我应该放弃nanoTime()吗?我应该在某处记录错误,还是有关我如何进一步调查的任何建议?

更新19/07 03:15 UTC:在尝试下面的finnw的测试用例后,我做了一些谷歌搜索,遇到了诸如bugid:6440250之类的条目.它还让我想起了周五晚些时候我注意到的一些其他奇怪的行为,其中ping是负面的.所以我将/ usepmtimer添加到我的boot.ini中,现在所有的测试都按预期运行.我的ping也是正常的.

我有点困惑为什么这仍然是一个问题; 从我的阅读中我认为TSC与PMT问题在Windows XP SP3中基本得到了解决.可能是因为我的机器最初是SP2,并且被修补到SP3而不是最初安装为SP3?我现在也想知道是否应该安装像MS KB896256那样的补丁.也许我应该与企业桌面构建团队一起解决这个问题?

Cha*_*had 7

通过在我的C:\ boot.ini字符串的末尾添加/ usepmtimer,解决了问题(对于nanoTime()在多核系统上的适用性有一些公开的怀疑!)强制Windows使用电源管理计时器而不是TSC.这是一个悬而未决的问题,为什么我需要这样做,因为我在XP SP3上,因为我知道这是默认的,但也许是因为我的机器被修补到SP3的方式.