Windows 10下多核处理器上的QueryPerformanceCounter行为异常 [英] QueryPerformanceCounter on multi-core processor under Windows 10 behaves erratically

查看:652
本文介绍了Windows 10下多核处理器上的QueryPerformanceCounter行为异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Windows下,我的应用程序使用QueryPerformanceCounter(和QueryPerformanceFrequency)执行高分辨率"时间戳记.

Under Windows, my application makes use of QueryPerformanceCounter (and QueryPerformanceFrequency) to perform "high resolution" timestamping.

自Windows 10(到目前为止,仅在Intel i7处理器上进行了测试),我们观察到QueryPerformanceCounter返回的值中行为不稳定. 有时,调用返回的值会跳得很远,然后又回到其先前的值. 感觉好像线程已从一个核心移到另一个核心,并在一段时间内返回了不同的计数器值(没有证据,只是一种直觉).

Since Windows 10 (and only tested on Intel i7 processors so far), we observe erratic behaviours in the values returned by QueryPerformanceCounter. Sometimes, the value returned by the call will jump far ahead and then back to its previous value. It feels as if the thread has moved from one core to another and was returned a different counter value for a lapse of time (no proof, just a gut feeling).

在XP或7上从来没有观察到这种情况(没有关于Vista,8或8.1的数据).

This has never been observed under XP or 7 (no data about Vista, 8 or 8.1).

一种简单"的解决方法是使用BCDEdit启用UsePlatformClock引导选项(使一切正常运行).

A "simple" workaround has been to enable the UsePlatformClock boot opiton using BCDEdit (which makes everything behaves wihtout a hitch).

我知道潜在的更高级的GetSystemTimePreciseAsFileTime,但是由于我们仍然支持7,因此,除非我们为不同的OS编写完全不同的代码,否则这不是一个完全可行的选择.

I know about the potentially superior GetSystemTimePreciseAsFileTime but as we still support 7 this is not exactly an option unless we write totatlly different code for different OSes, which we really don't want to do.

在Windows 10下是否观察到/解释了这种行为?

Has such behaviour been observed/explained under Windows 10 ?

推荐答案

我需要更多有关您的代码的知识,但让我重点介绍一下MSDN中的一些内容:

I'd need much more knowledge about your code but let me highlight few things from MSDN:

在计算增量时,应限制 [来自QueryPerformanceCounter]的值,以确保计时值中的任何错误均不会导致崩溃或与时间相关的不稳定计算.

When computing deltas, the values [from QueryPerformanceCounter] should be clamped to ensure that any bugs in the timing values do not cause crashes or unstable time-related computations.

尤其是:

通过使用Windows API SetThreadAffinityMask将该单个线程设置为保留在单个处理器上...虽然QueryPerformanceCounter和QueryPerformanceFrequency通常针对多个处理器进行调整,但 BIOS或驱动程序中的错误可能导致这些例程返回不同的值,因为线程从一个处理器移至另一个.因此,最好将线程保留在单个处理器上.

Set that single thread to remain on a single processor by using the Windows API SetThreadAffinityMask ... While QueryPerformanceCounter and QueryPerformanceFrequency typically adjust for multiple processors, bugs in the BIOS or drivers may result in these routines returning different values as the thread moves from one processor to another. So, it's best to keep the thread on a single processor.

您的案例可能利用了其中一个 bug .简而言之:

Your case might exploited one of those bugs. In short:

  • 您应该始终从一个线程查询时间戳(设置相同的CPU亲和力以确保它不会更改),并从任何其他线程读取该值(只需互锁读取,无需花哨的同步).
  • 限制计算的增量(至少确保它不是负数)...

注意:

QueryPerformanceCounter()尽可能使用TSC(请参阅 MSDN ).从Windows 7到Windows 8,用于同步TSC的算法(如果可用,并且在您的情况下应该如此)已经发生了很大的变化,但是请注意:

QueryPerformanceCounter() uses, if possible, TSC (see MSDN). Algorithm to synchronize TSC (if available and in your case it should be) is vastly changed from Windows 7 to Windows 8 however note that:

随着多核/超线程CPU,具有多个CPU的系统以及休眠的操作系统的出现,不能依靠TSC来提供准确的结果-除非格外小心以纠正可能的缺陷:记号,以及所有内核(处理器)在其计时寄存器中是否具有相同的值.不能保证单个主板上多个CPU的时间戳计数器将同步.因此,程序只能通过限制其运行在特定的CPU上才能获得可靠的结果.

然后,即使理论上QPC是单调的,也必须始终从同一线程调用它以确保这一点.

Then, even if in theory QPC is monotonic then you must always call it from the same thread to be sure of this.

另一个说明:如果同步是通过软件进行的,则可以从英特尔文档中阅读:

Another note: if synchronization is made by software you may read from Intel documentation that:

...对于软件而言,这样做可能很难确保在给定的时间点所有逻辑处理器的TSC值都相同...

...It may be difficult for software to do this in a way than ensures that all logical processors will have the same value for the TSC at a given point in time...


编辑:如果您的应用程序是多线程的,并且您无法(或者您不想)设置CPU关联性(尤其是如果您需要精确的时间戳记,但需要为此付出代价的话)然后在Win8(或更高版本)上运行时可以使用GetSystemTimePreciseAsFileTime(),对于Win7,可以回退到timeGetTime()(使用timeBeginPeriod(1)将粒度设置为1 ms并假定1 ms的分辨率就足够了).一个非常有趣的读物: Windows时间戳项目.


Edit: if your application is multithreaded and you can't (or you don't wan't) to set CPU affinity (especially if you need precise timestamping at the cost to have de-synchronized values between threads) then you may use GetSystemTimePreciseAsFileTime() when running on Win8 (or later) and fallback to timeGetTime() for Win7 (after you set granularity to 1 ms with timeBeginPeriod(1) and assuming 1 ms resolution is enough). A very interesting reading: The Windows Timestamp Project.

编辑2 :OP直接建议!在适用时(因为这是系统设置,而不是您的应用程序本地),这可能是一个简单的解决方法.您可以使用bcdedit强制QPC使用HPET而不是TSC(请参阅 MSDN ).延迟和解决方案应该更糟,但是从上述问题来看,本质上是安全.

Edit 2: directly suggested by OP! This, when applicable (because it's a system setting, not local to your application), might be an easy workaround. You can force QPC to use HPET instead of TSC using bcdedit (see MSDN). Latency and resolution should be worse but it's intrinsically safe from above described issues.

这篇关于Windows 10下多核处理器上的QueryPerformanceCounter行为异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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