如何以微秒精度计算操作时间

6

我想在Windows平台上以微秒精度计算函数的性能。

现在Windows本身的时间精度是毫秒级别的,那么我该如何实现呢?

我尝试了下面的示例,但没有得到正确的结果。

LARGE_INTEGER ticksPerSecond = {0};
LARGE_INTEGER tick_1 = {0};
LARGE_INTEGER tick_2 = {0};
double uSec = 1000000;

// Get the frequency
QueryPerformanceFrequency(&ticksPerSecond);

//Calculate per uSec freq
double uFreq = ticksPerSecond.QuadPart/uSec;

// Get counter b4 start of op
QueryPerformanceCounter(&tick_1);

// The ope itself
Sleep(10);

// Get counter after opfinished
QueryPerformanceCounter(&tick_2);

// And now the op time in uSec
double diff = (tick_2.QuadPart/uFreq) - (tick_1.QuadPart/uFreq);

3
你会得到什么结果?请注意,“Sleep”不能保证精确地休眠指定的时间;使用例如“Sleep(1000)”来休眠一秒钟,这样你就可以自行检查它是否在做更多或更少的正确事情。 - Thomas
1
默默地数到自己真的很快。 - San Jacinto
8个回答

20

将操作在循环中执行一百万次左右,然后将结果除以该数字。这样,您可以获得那么多次执行的平均执行时间。由于多任务等原因,对非常快速的操作进行一次(甚至一百次)定时非常不可靠。


注意:如果操作足够快,循环本身可能会占用您关注的一部分时间。请将此作为一个问题牢记在心。 - Brian
如果您对其进行循环操作,缓存将生效并加快操作速度。 - PiNoYBoY82
循环1M次与它运行的秒数相比微不足道。如果你想测量纳秒,那就是另一回事了。哦,只需使用秒表;-) - phkahler

7
  • 编译它
  • 查看汇编输出
  • 计算您的函数中每个指令的数量
  • 应用目标处理器上的每个指令的周期数
  • 得出一个周期计数
  • 乘以您运行的时钟速度
  • 应用任意缩放因子来解决缓存未命中和分支错误预测问题 lol

(哇,我肯定会被踩的)


不打算点踩,只是想指出最后一行(缓存未命中和分支预测失败)基本上破坏了你到目前为止得到的非常仔细的CPU周期计数:p - Matthieu M.
+1好笑。然而,如果您是认真的,这是可怕的建议。作为讽刺,这是选择Matti答案的很好例子。 - deft_code
踩负评?不是我干的。实际上,我曾经这样做过。但是,现在有了缓存,它并不真正起作用。因此,我建议使用“运行一百万次”方法。 - Mike Dunlavey
根据您的架构,这是一种完全有效和准确的方法。并非所有处理器都具有缓存、分支预测或多任务处理能力。尽管如此,我想指出每条指令的周期数可能是可变的,甚至取决于参数... - Nathan Ernst

3
不,你可能得到了准确的结果,QueryPerformanceCounter()函数在计时短时间间隔方面效果很好。问题在于你对Sleep()函数精度的期望过高。它的分辨率为1毫秒,精度远远不如它。在大多数Windows机器上,精度不超过约15.625毫秒。
要想使其接近1毫秒,你需要先调用timeBeginPeriod(1)函数。这可能会提高匹配度,但忽略了Windows作为多任务操作系统所带来的抖动。

使用选择器和虚假的文件描述符来获取更准确的“睡眠”时间。 - PiNoYBoY82

0
如果您正在进行离线分析,一种非常简单的方法是运行该函数1000次,测量最接近的毫秒数并除以1000。

0
要获得比1毫秒更精细的分辨率,您将需要查阅操作系统文档。可能会有API以微秒分辨率获取计时器分辨率。如果有的话,请多次运行您的应用程序并取平均值。

2
有的。它叫做QueryPerformanceCounter,就像OP所提到的那样。 - Alan

0

我喜欢Matti Virkkunen的回答。检查时间,调用函数多次,完成后再次检查时间,然后除以调用函数的次数。他提到由于操作系统中断可能会导致误差。您可以改变调用函数的次数并观察差异。您能否提高进程的优先级?您能否使所有调用在单个操作系统时间片内完成?

由于您不知道操作系统何时会将您交换出去,因此可以将所有内容放入一个更大的循环中,以进行大量测量,并保存最小值,因为这是中断最少的那个。这仍然可能大于函数执行的实际时间,因为它可能仍然包含一些操作系统中断。


0

Sanjeet,

看起来你做得非常正确。QueryPerformanceCounter是一种完全可以用来测量短时间内高精度的方法。如果你没有看到预期的结果,那很可能是因为sleep并没有按照你预期的时间睡眠!但是,它很可能被正确地测量了。

我想回到你最初关于如何在Windows上以微秒精度测量时间的问题。正如你已经知道的那样,高性能计数器(即QueryPerformanceCounter)“滴答”频率由QueryPerformanceFrequency报告。这意味着你可以用以下精度来测量时间:

1/频率秒

在我的机器上,QueryPerformanceFrequency报告2337910(计数/秒)。这意味着我的电脑的QPC可以精确测量4.277e-7秒,或0.427732微秒。这意味着我可以测量的最小时间单位是0.427732微秒。当然,这就给了你最初要求的精度 :) 你的机器频率应该类似,但你可以进行计算和检查。


-1

或者你可以使用gettimeofday()函数,它会给你一个timeval结构体,其中包含一个时间戳(精确到微秒)


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