7

在 Win32 中,有没有办法获得唯一的 cpu 循环计数或类似的东西,这对于多个进程/语言/系统/等来说是统一的。

我正在创建一些日志文件,但必须生成多个日志文件,因为我们正在托管 .NET 运行时,并且我想避免从一个到另一个调用来记录。因此,我想我只是生成两个文件,将它们组合起来,然后对它们进行排序,以获得涉及跨世界调用的连贯时间线。

但是,GetTickCount 并不是每次调用都会增加,所以这并不可靠。有没有更好的号码,以便我在排序时按正确的顺序接听电话?


编辑:感谢@Greg让我走上了 QueryPerformanceCounter 的轨道,它成功了。

4

5 回答 5

12

这是一篇有趣的文章!说不要使用 RDTSC,而是使用QueryPerformanceCounter

结论:

在许多基于 Windows 的操作系统上,使用常规的 oldtimeGetTime()进行计时并不可靠,因为系统计时器的粒度可能高达 10-15 毫秒,这意味着 timeGetTime()只能精确到 10-15 毫秒。[请注意,高粒度出现在基于 NT 的操作系统上,如 Windows NT、2000 和 XP。Windows 95 和 98 往往具有更好的粒度,大约 1-5 毫秒。]

但是,如果您 timeBeginPeriod(1)在程序开始(和 timeEndPeriod(1)结束)调用,timeGetTime()通常会精确到 1-2 毫秒,并且会为您提供极其准确的计时信息。

Sleep()行为相似;Sleep()实际休眠的时间长度与 的粒度密切相关timeGetTime(),因此在调用 timeBeginPeriod(1)一次后, Sleep(1)实际上将休眠 1-2 毫秒,Sleep(2)持续 2-3 毫秒,依此类推(而不是以高达10-15 毫秒)。

对于更高精度的计时(亚毫秒精度),您可能希望避免使用汇编助记符 RDTSC,因为它很难校准;而是使用 QueryPerformanceFrequencyand QueryPerformanceCounter,其精确到小于 10 微秒(0.00001 秒)。

对于简单的计时,timeGetTime 和 QueryPerformanceCounter 都很好用,QueryPerformanceCounter 显然更准确。但是,如果您需要执行任何类型的“定时暂停”(例如帧速率限制所必需的暂停),则需要小心坐在调用 QueryPerformanceCounter 的循环中,等待它达到某个值;这将消耗 100% 的处理器。相反,考虑一个混合方案,当您需要通过超过 1 毫秒的时间时,您调用 Sleep(1)(不要忘记 timeBeginPeriod(1)!),然后只进入 QueryPerformanceCounter 100%-busy 循环完成您需要的最后 < 1/1000 秒的延迟。这将为您提供超精确的延迟(精确到 10 微秒),并且 CPU 使用率非常低。

于 2008-09-26T11:52:36.787 回答
9

您可以使用RDTSC CPU 指令(假设 x86)。该指令提供 CPU 周期计数器,但请注意,它会很快增加到最大值,然后重置为 0。正如 Wikipedia 文章所述,使用QueryPerformanceCounter函数可能会更好。

于 2008-09-26T11:48:39.480 回答
2

System.Diagnostics.Stopwatch.GetTimestamp() 返回自时间起源以来的 CPU 周期数(可能是计算机启动时,但我不确定),我从未见过它在 2 次调用之间没有增加。

CPU 周期将特定于每台计算机,因此您不能使用它来合并两台计算机之间的日志文件。

于 2008-09-26T11:54:16.347 回答
2

RDTSC 输出可能取决于当前内核的时钟频率,这对于现代 CPU 来说既不是恒定的,在多核机器中也不是一致的。

使用系统时间,如果处理来自多个系统的提要,则使用 NTP 时间源。您可以通过这种方式获得可靠、一致的时间读数;如果开销对于您的目的来说太大了,那么使用HPET计算自上次已知的可靠时间读数以来经过的时间比单独使用 HPET 更好。

于 2008-09-26T11:57:27.150 回答
1

在合并日志文件时使用 GetTickCount 并添加另一个计数器。不会为您提供不同日志文件之间的完美顺序,但它至少会使每个文件中的所有日志保持正确的顺序。

于 2008-09-26T11:53:27.957 回答