System.nanoTime() 完全没用吗? [英] Is System.nanoTime() completely useless?

查看:67
本文介绍了System.nanoTime() 完全没用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如博客文章中所述注意 Java 中的 System.nanoTime(),在 x86 系统上,Java 的 System.nanoTime() 使用 CPU 特定计数器.现在考虑我用来测量通话时间的以下案例:

long time1= System.nanoTime();富();long time2 = System.nanoTime();long timeSpent = time2-time1;

现在在多核系统中,可能是在测量 time1 后,线程被调度到计数器小于前一个 CPU 的不同处理器.因此,我们可以在 time2 中获得一个 小于 的值.因此,我们将在 timeSpent 中得到一个负值.

考虑到这种情况,System.nanotime现在是不是几乎没用了?

我知道更改系统时间不会影响纳米时间.这不是我上面描述的问题.问题是每个 CPU 都会保持一个不同的计数器,因为它被打开了.与第一个 CPU 相比,第二个 CPU 上的此计数器可能更低.由于线程可以在得到time1后被OS调度到第二个CPU上,timeSpent的值可能不正确,甚至是负数.

解决方案

这个答案写于 2011 年,是从当时运行在当时操作系统上的 Sun JDK 实际做了什么的角度来看的.那是很久以前的事!leventov 的回答提供了更新的视角.

那个帖子是错误的,nanoTime 是安全的.对链接到 David Holmes 的博客文章 的帖子有评论,这是实时和Sun 的并发专家.它说:

<块引用>

System.nanoTime() 是使用 QueryPerformanceCounter/QueryPerformanceFrequency API 实现的 [...] QPC 使用的默认机制由硬件抽象层 (HAL) 决定 [...] 此默认值不仅在硬件上而且也跨操作系统版本.例如,Windows XP Service Pack 2 更改了使用电源管理计时器 (PMTimer) 而不是处理器时间戳计数器 (TSC) 的内容,因为 TSC 在 SMP 系统中的不同处理器上不同步的问题,以及它的频率可能会因电源管理设置而异(及其与经过时间的关系).

因此,在 Windows 上,这在 WinXP SP2 之前是一个问题,但现在不是.

我找不到关于其他平台的第二部分(或更多),但那篇文章确实包含了 Linux 遇到并以相同方式解决相同问题的评论,并附有 clock_gettime(CLOCK_REALTIME) 的常见问题,其中说:

<块引用>

  1. clock_gettime(CLOCK_REALTIME) 在所有处理器/内核上是否一致?(arch 重要吗?例如 ppc、arm、x86、amd64、sparc).

应该或者被认为有问题.

但是,在 x86/x86_64 上,可能会看到未同步或可变频率的 TSC 导致时间不一致.2.4 内核确实对此没有任何保护,早期的 2.6 内核在这方面也做得不太好.从 2.6.18 及更高版本开始,检测这种情况的逻辑会更好,我们通常会回退到安全的时钟源.

ppc 总是有一个同步的时基,所以这应该不是问题.

因此,如果 Holmes 的链接可以被理解为暗示 nanoTime 调用 clock_gettime(CLOCK_REALTIME),那么它在 x86 上的内核 2.6.18 中是安全的,并且始终使用 PowerPC(因为 IBM 和 Motorola 与 Intel 不同,它们实际上知道如何设计微处理器).

遗憾的是,没有提及 SPARC 或 Solaris.当然,我们不知道 IBM JVM 是做什么的.但是现代 Windows 和 Linux 上的 Sun JVM 可以做到这一点.

这个答案是基于它引用的来源.但我仍然担心它实际上可能是完全错误的.一些更新的信息将非常有价值.我刚刚发现了一个链接到 四年更新的关于 Linux 时钟的文章,可能有用.

As documented in the blog post Beware of System.nanoTime() in Java, on x86 systems, Java's System.nanoTime() returns the time value using a CPU specific counter. Now consider the following case I use to measure time of a call:

long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;

Now in a multi-core system, it could be that after measuring time1, the thread is scheduled to a different processor whose counter is less than that of the previous CPU. Thus we could get a value in time2 which is less than time1. Thus we would get a negative value in timeSpent.

Considering this case, isn't it that System.nanotime is pretty much useless for now?

I know that changing the system time doesn't affect nanotime. That is not the problem I describe above. The problem is that each CPU will keep a different counter since it was turned on. This counter can be lower on the second CPU compared to the first CPU. Since the thread can be scheduled by the OS to the second CPU after getting time1, the value of timeSpent may be incorrect and even negative.

解决方案

This answer was written in 2011 from the point of view of what the Sun JDK of the time running on operating systems of the time actually did. That was a long time ago! leventov's answer offers a more up-to-date perspective.

That post is wrong, and nanoTime is safe. There's a comment on the post which links to a blog post by David Holmes, a realtime and concurrency guy at Sun. It says:

System.nanoTime() is implemented using the QueryPerformanceCounter/QueryPerformanceFrequency API [...] The default mechanism used by QPC is determined by the Hardware Abstraction layer(HAL) [...] This default changes not only across hardware but also across OS versions. For example Windows XP Service Pack 2 changed things to use the power management timer (PMTimer) rather than the processor timestamp-counter (TSC) due to problems with the TSC not being synchronized on different processors in SMP systems, and due the fact its frequency can vary (and hence its relationship to elapsed time) based on power-management settings.

So, on Windows, this was a problem up until WinXP SP2, but it isn't now.

I can't find a part II (or more) that talks about other platforms, but that article does include a remark that Linux has encountered and solved the same problem in the same way, with a link to the FAQ for clock_gettime(CLOCK_REALTIME), which says:

  1. Is clock_gettime(CLOCK_REALTIME) consistent across all processors/cores? (Does arch matter? e.g. ppc, arm, x86, amd64, sparc).

It should or it's considered buggy.

However, on x86/x86_64, it is possible to see unsynced or variable freq TSCs cause time inconsistencies. 2.4 kernels really had no protection against this, and early 2.6 kernels didn't do too well here either. As of 2.6.18 and up the logic for detecting this is better and we'll usually fall back to a safe clocksource.

ppc always has a synced timebase, so that shouldn't be an issue.

So, if Holmes's link can be read as implying that nanoTime calls clock_gettime(CLOCK_REALTIME), then it's safe-ish as of kernel 2.6.18 on x86, and always on PowerPC (because IBM and Motorola, unlike Intel, actually know how to design microprocessors).

There's no mention of SPARC or Solaris, sadly. And of course, we have no idea what IBM JVMs do. But Sun JVMs on modern Windows and Linux get this right.

EDIT: This answer is based on the sources it cites. But i still worry that it might actually be completely wrong. Some more up-to-date information would be really valuable. I just came across to a link to a four year newer article about Linux's clocks which could be useful.

这篇关于System.nanoTime() 完全没用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆