如何获取当前Windows系统的计时器分辨率?

3

我知道默认是每个tick 15.6毫秒,但有些人可能会更改它,然后一次又一次地更改回去,因此我需要轮询当前值以执行有效的QueryPerformanceCounter同步。

所以是否有API方法可以获取计时器分辨率?

顺便说一下,我在使用C++。

4个回答

15

Windows计时器分辨率是通过隐藏的API调用提供的:

NTSTATUS NtQueryTimerResolution(OUT PULONG MinimumResolution, 
                                OUT PULONG MaximumResolution, 
                                OUT PULONG ActualResolution);

NtQueryTimerResolution由本地Windows NT库NTDLL.DLL导出。

常见硬件平台报告 ActualResolution 为156,250或100,144;旧平台可能报告更大的数字;当支持HPET(高精度事件定时器)或恒定/不变TSC时,新系统可能返回156,001的ActualResolution。

timeBeginPeriod(n)的调用反映在 ActualResolution 中。

更多详细信息请参见答案。


1
终于有一个正确的答案了。我还制作了一个小的 GitHub 项目,使用 P/Invoke 在 C# 中实现了这些方法:https://github.com/tebjan/TimerTool - thalm
请注意,当新值小于当前值时,该工具仅会建立一个新的计时器周期(开始计时周期_)。只有当没有其他进程建立了_Current Period_的计时器周期时,_计时器结束周期_才会发挥作用。顺便提一下:_Current 不一定在 MinMax 的范围内;例如以 1024 次中断/秒运行的系统显示 Current: 0.9766,Min: 15.625 和 Max: 1。这是由于 ´NtQueryTimerResolution´ 参数缺乏准确性所导致的。更多详细信息请参见回答。 - Arno

5

这并不会有所帮助,因为在你进行校准时,另一个进程可以在此期间更改它。

这属于"如果你不能战胜他们,就加入他们"的范畴。在开始校准之前调用timeBeginPeriod(1)确保你拥有一个已知的速率,没有人可以更改它。获得改进的计时器精度肯定也是有益的。

请注意,你很难做得比QueryPerformanceFrequency()更好。除非你校准了很长时间,否则时钟速率不够高,无法给你额外的精度,因为你永远无法测量超过+/- 0.5毫秒。计时器事件也不会以毫秒精度传递,它可以任意延迟。如果你进行长时间校准,则GetTickCount64()足够好。


我需要确切地知道单个系统计时器滴答中有多少CPU时钟周期,以便将一个计时器与另一个计时器同步。这将提供ms ~300ns的计时器分辨率。 - alemjerus
“CPU ticks” 是什么意思?CPU 有一个时钟周期,以快速的千兆赫运行。在现代处理器上它会动态变化,并且与 QueryPerformanceCounter 或 timeBeginPeriod 没有任何关系。 - Hans Passant
好的,我的意思是:系统计时器滴答中有多少个QPC滴答。我知道默认值大约为47800,但即使系统计时器精度已更改,我也需要确保。如果我错过了一两次更改也没关系,毕竟我想要微秒级别的精度。 - alemjerus
已经问答完毕。由于系统时钟中断率完全在您的控制范围之外,每个时钟滴答的QPC(QueryPerformanceCounter)滴答数是不确定的,除非您自己强制更改该速率。您可以使用一些可能性进行校准,以获得一致的数字,在启动Chrome后它将不再相同。如果您的代码依赖于中断率,则存在需要修复的错误。 - Hans Passant
我并不需要它保持一致性。我只需要知道现在是什么,偶尔的错误并不是问题。因为主要目标是知道特定的tick变化是“真实”的还是只是一个线程片段。 - alemjerus
@HansPassant: ...不太可能比QueryPerformanceFrequency()更好。 注意:新版本的Windows会对频率进行校准(QueryPerfomanceFrequency),但在操作期间它们不会重复进行该校准。旧版本(例如XP)甚至认为这是一个恒定的固定值(例如3579545个tick/s),但实际上并非如此。所有这些都给了我们很大的改进空间。进行校准可以帮助解决这个问题。 - Arno

1
RDTSC指令可用于读取CPU时间戳计数器。在大多数情况下(如果不是全部),此计数器将以CPU时钟速率变化。如果您想挑剔一点,还可以使用类似于CPUID的指令来序列化指令。有关详细信息,请参阅Intel手册。您可以将RDTSC与QueryPerformanceCounter等API一起使用。换句话说,在调用之前和之后使用RDTSC进行测量。

-2

WINAPI 函数 GetSystemTimeAdjustment


不,那不是它。这是一个Windows时间修复方案。 - alemjerus
第二个参数是“指向DWORD的指针,该函数将其设置为周期时间调整之间以100纳秒为单位计数的间隔。此间隔是系统时钟中断之间的时间间隔。” - Wojtek Surowka
你确定吗?因为逻辑上来说,如果时间变化本身很小,可能只需要一个小时左右。而且更重要的是,时间调整可能会被完全禁用! - alemjerus
调整可能很小,但第二个参数是“系统时钟中断之间的时间段”——听起来像是Windows的滴答间隔。 - Wojtek Surowka
每经过lpTimeIncrement时间段,lpTimeAdjustment将被添加到当天的时间中。这与计时器分辨率/中断周期没有任何关系。实际上,它甚至是独立的;在Windows XP上,这种独立性是不可见的,但在Windows VISTA / Windows 7上变得越来越明显。只有在Windows 8 / 8.1上,这种独立性才变得非常明显。它唯一说明的是调整增益(两者之比)。 - Arno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接