2

根据 MSDN 文章Game Timing and Multicore Processors ,QueryPerformanceFrequency() 和 QueryPerformanceCounter() 函数据说是最好的。但如果不支持它,我可以使用 timeGetTime() 或 GetTickCount()。

  1. QueryPerformanceFrequency() 是否与 CPU 时钟相同,还是它使用自己的时钟或具有自己的频率且不会随时间变化的东西?
  2. 如果频率随时间随机变化会怎样(尤其是在笔记本电脑中)
  3. 如何使用 SetThreadAffinityMask 函数?(我见过的一些代码使用该函数将其更改为“1”,然后使用计数器并将掩码再次更改为旧值。为什么会这样?正确吗?)
  4. 仅使用一次 QueryPerformanceFrequency() 函数并通过除以案例/问题 1 中的频率来计算增量时间值是否正确?还是由案例2修复?
4

3 回答 3

2
  1. QPC 的底层实现差异很大。在某些情况下是这样,但通常不是。
  2. 这将影响 RDTSC,但不会影响 QPC。
  3. 那是为了防止线程从一个 CPU 内核移动到另一个 CPU 内核。它可能有助于避免报告负时间传递的高分辨率计时方法(它发生了......)。不过一般不推荐。
  4. QPC 的频率是恒定的。至少在给定的系统上,至少在重新启动之前。

但你不一定会问正确的问题......

windows上常用的四个计时函数分别是:GetTickCount、timeGetTime、QueryPerformanceCounter(QPC)、RDTSC

我的建议包括:

Game logic timing should be done with timeGetTime. It is simple, reliable, and has sufficient resolution for that purpose. (edit: default resolution varies - you can call timeBeginPeriod to force it to 1 millisecond resolution though)

GetTickCount should not be used. It's resolution is too poor for either game logic or performance monitoring (64 Hertz - a nasty frequency as it creates a beat frequency with the typical monitor refresh rate). It is the fastest timing function call IIRC, but I can't find a scenario in which that makes up for its poor resolution. (edit: rumor has it that timeBeginPeriod can improve the resolution of GetTickCount - that rumor is FALSE)

RDTSC 和 QPC 对于简单的游戏逻辑时序来说都太不可靠/古怪,但更适合性能测量。如果您想要独立于 CPU 频率变化的单位,RDTSC 的问题会使其使用起来很痛苦,并且您通常需要 asm 才能使用它。QPC 通常可以正常工作...但是当它出错时,它可能会出错,并且出错的方式多种多样(有时它真的很慢,有时它经常出现小的负增量,有时它很少出现大的负增量(不是环绕),有时它只是完全精神病,等等)。RDTSC 几乎总是更快,而且通常分辨率更好。总的来说,我更喜欢 RDTSC 用于内部使用,因为它速度更快,因此在测量时产生的失真更少。在客户机器上,它'

于 2014-04-15T13:19:49.777 回答
0

如果您需要高精度计时器,QPF/QPC 是最好的(返回值以纳秒为单位,但这并不意味着精度为 1 纳秒)。否则,只需使用GetTickCount()(以毫秒为单位)。两个版本都应正确处理可变 CPU 频率(例如,在具有省电选项的笔记本电脑上)。

我不知道亲和力掩码如何帮助检索系统时间。

获得高精度时间的正确方法是同时调用 QPF 和 QPC 并将时间计算为:

double seconds = QPC / QPF;

编辑:

GetTickCount() 的精度很差,大约为 5 毫秒,但它仍然适用于大多数应用程序。要测量非常小的时间段,只有一个选项:QPC/QPF。

于 2013-01-16T16:55:56.137 回答
0

我个人更喜欢时间戳计数器,它是 x86 架构中的 64 位计数器,每个内部时钟周期都会递增。它使用 rdtsc 指令读取并返回 edx:eax 寄存器 (x86-32) 和 rdx:rax (x86-64) 中的计数器值。

指令存在问题,但那是很多年前的事了。今天,“绿色功能”导致负载相关的执行频率变化使得计算经过的时间变得更加困难,但经过的时钟周期不是问题。

unsigned long long startCycle, endCycle, elapsedCycles, overhead;

// @ start of program

overhead=instruction_rdtsc ();
overhead=instruction_rdtsc ()-overhead;

// preparing to measure

startCycle=instruction_rdtsc ();

// (sequence to measure)

endCycle=instruction_rdtsc ();

elapsedCycles=endCycle-startCycle-overhead;

应该确定指令本身的开销。我发现英特尔处理器的开销比 AMD 处理器小。应该多次测量开销 - 例如循环 - 以找到可能的最低值。测量的序列越长,开销就越小。该指令可以在应用程序中插入永久性性能计量,以便能够在正常(非性能测试)执行下测量其实际性能。

由于流水线和乱序执行问题,不应测量非常短的序列。有些人建议在 rdtsc 之前插入 cpuid 指令,但这仅意味着实际时钟计数变得大于实际。我认为 30 左右的循环计数具有指示性,而 100 左右或更大的循环计数通常是可靠的。中间有一个灰色地带。

于 2014-01-21T10:39:33.123 回答