只要您的线程保持在同一个 CPU 内核上,RDTSC 指令就会不断返回一个递增的数字,直到它回绕。对于 2GHz CPU,这发生在 292 年后,所以这不是一个真正的问题。你可能不会看到它发生。如果您希望活得那么久,请确保您的计算机重新启动,例如,每 50 年。
RDTSC 的问题是你不能保证它在老多核 CPU 的所有内核上在同一时间点启动,也不能保证它在老多核 CPU 板上的所有 CPU 上在同一时间点启动.
现代系统通常不存在此类问题,但也可以通过设置线程的亲和性使其仅在一个 CPU 上运行,从而在旧系统上解决该问题。这对应用程序性能不利,因此通常不应该这样做,但对于测量滴答声,这很好。
(另一个“问题”是很多人使用RDTSC来测量时间,这不是它的作用,但是你写了你想要CPU周期,所以没关系。如果你确实使用RDTSC来测量时间,你可能会感到惊讶省电或hyperboost或任何被称为多种频率变化技术的东西。实际上,clock_gettime
系统调用在Linux下非常好。)
我只想写rdtsc
在asm
语句中,这对我来说很好,并且比一些晦涩的十六进制代码更具可读性。假设它是正确的十六进制代码(并且由于它既不崩溃也不返回不断增加的数字,看起来如此),你的代码是好的。
如果你想测量一段代码的滴答数,你想要一个滴答差,你只需要减去不断增加的计数器的两个值。请注意,如果需要与周围代码隔离的非常准确的测量,则需要在调用(或仅在较新的处理器上支持的使用uint64_t t0 = rdtsc(); ... uint64_t t1 = rdtsc() - t0;
)之前进行序列化,即停止管道。可以在每个特权级别使用的一个序列化指令是.rdtsc
rdtscp
cpuid
回复评论中的进一步问题:
当您打开计算机时,TSC 从零开始(并且 BIOS 将所有 CPU 上的所有计数器重置为相同的值,尽管几年前的一些 BIOS 并不可靠)。
因此,从您的程序的角度来看,计数器在“过去某个未知时间”开始,并且它总是随着 CPU 看到的每个时钟滴答而增加。因此,如果您现在和稍后在不同的进程中执行返回该计数器的指令,它将返回一个更大的值(除非 CPU 在其间暂停或关闭)。同一程序的不同运行得到更大的数字,因为计数器不断增长。总是。
现在,clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
是另一回事了。这是操作系统为进程分配的 CPU 时间。当您的流程开始时,它从零开始。一个新的过程也从零开始。因此,两个相互运行的进程将获得非常相似或相同的数字,而不是永远增长的数字。
clock_gettime(CLOCK_MONOTONIC_RAW)
更接近 RDTSC 的工作方式(并且在一些较旧的系统上是用它实现的)。它返回一个不断增加的值。如今,这通常是 HPET。然而,这真的是时间,而不是滴答声。如果您的计算机进入低功耗状态(例如以 1/2 正常频率运行),它仍然会以相同的速度前进。