当调用QueryPerformanceCounter时会发生什么?

19

我正在研究在我们系统中使用QueryPerformanceCounter的确切影响,并试图了解它对应用程序的影响。我通过在我的4核单CPU机器上运行它可以看到,它需要大约230纳秒才能运行。当我在一个24核4 CPU的Xeon上运行它时,它需要大约1.4毫秒才能运行。更有趣的是,在我的机器上,当在多个线程中运行它们时,它们互不影响。但在多CPU机器上,线程会导致某种相互作用,使它们彼此阻塞。

我想知道是否有一些共享资源在总线上,它们都要查询?当我调用QueryPerformanceCounter时会发生什么,它实际上又测量了什么?

哦天啊,1.4毫秒!是的,这是一个好问题。根据这里的说法:http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx,它以800纳秒为例说明了一台表现不佳的机器。1.4毫秒将会是超级糟糕的。 - v.oddou
在编写分析器时,我也遇到了这个问题。每次函数启动和返回时都会查询计时器。使用QueryPerformanceCounter会使程序变得非常缓慢。使用GetTickCount不会导致明显的减速,但它无法用于精确的分析。 - Calmarius
4个回答

10

Windows QueryPerformanceCounter() 函数有逻辑可以确定处理器数量并在必要时调用同步逻辑。它试图使用 TSC 寄存器,但对于多处理器系统,该寄存器不能保证在处理器之间同步(更重要的是可能会因智能降频和睡眠状态而大幅变化)。

MSDN 表示,在任何处理器上调用该函数都没有影响,因此在这种情况下可能会出现额外的同步代码导致开销增加。另外,请记住它可能会引发总线传输,所以您可能会看到总线争用的延迟。

如果可能的话,尝试使用 SetThreadAffinityMask() 将其绑定到特定的处理器。否则,您可能只能接受延迟,或者尝试使用不同的计时器(例如,查看 http://en.wikipedia.org/wiki/High_Precision_Event_Timer)。


4
我知道这个帖子有点旧了,但我想添加更多信息。首先,我同意QueryPerformanceCounter在某些机器上可能需要更多时间,但我不确定Ron的答案是否总是导致这种情况。当我研究这个问题时,我发现了一些网页,讲述了QueryPerformanceCounter的实现方式。例如,Precision is not the same as accuracy告诉我Windows(具体来说是HAL)将使用不同的计时设备来获取值。这意味着如果Windows使用较慢的计时设备(如PIT),则获取时间值需要更长时间。显然,使用PIT可能需要PCI事务,这可能是一个原因。
我还发现另一篇文章:How It Works: Timer Outputs in SQL Server 2008 R2 - Invariant TSC提供类似的描述。实际上,这篇文章告诉我们SQLServer如何以最佳方式计时事务。
然后,我在VMware网站上找到了更多信息,因为我必须处理使用虚拟机的客户,并且我发现在VM中测量时间存在其他问题。对于那些感兴趣的人,请参阅VMware论文-VMware虚拟机中的时间管理。在这篇论文中,它还谈到一些Windows版本会同步每个TSC。因此,在某些情况下使用QueryPerformanceCounter()是安全的,我认为我们应该尝试一些类似于How It Works: Timer Outputs in SQL Server 2008 R2建议的方法,以查找调用QueryPerformanceCounter()时可能发生的事情。

3

我曾认为在x86上,QueryPerformanceCounter()只是在内部调用rdtsc。我很惊讶它在多核机器上有任何减速(我从未在我的4核CPU上注意到过)。


我不知道在实践中它是否有重大影响,除非你直接寻找它,否则可能无法测量。在4核CPU上,无论如何都没有减速 :) - Matt Price
@Goz 虽然这在旧的 Opteron 上尤为明显,但是新的多核 CPU 具有同步的 TSC 寄存器。 - v.oddou
@v.oddou:可能是真的...但时间戳计数器不是一个简单的循环计数吗?它是否考虑了节流? - Goz
@Goz 是的,我一直对这个问题很好奇。我唯一能合理想象到的实际情况是,所有核心的速度都会同时提高。这反映在像“coretemp”或“CPUz”这样的程序中,它们只显示1个频率,但却有4个温度和使用率条形图。 - v.oddou

2
很久没有使用这么多了,但是如果我没记错的话,这个函数的实现不止一个,因为其内部由各种硬件制造商提供。以下是MSDN的一篇小文章:http://msdn.microsoft.com/ja-jp/library/cc399059.aspx。此外,如果您正在查询多个CPU的性能(而不是单个CPU上的多个核心),它将必须通过总线进行通信,这既更慢,也可能是您看到的某些阻塞的原因。不过,就像我之前说的那样,已经有很长时间了。
Mike

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