定时器精度:c clock()与WinAPI的QPC或timeGetTime()

rob*_*son 5 c c++ winapi timer

我想描述软件计时器的准确性.我不太关心它是如何准确的,但确实需要知道准确性是什么.

我已经研究了c函数clock()和WinAPI的函数QPC和timeGetTime,我知道它们都依赖于硬件.

我正在测量一个可能需要大约5-10秒的过程,而且我的要求很简单:我只需要0.1秒精度(分辨率).但我确实需要知道准确性是什么,最坏的情况.

虽然更优先考虑更准确,但我宁愿知道准确性差(500毫秒)并且考虑到它,而不是相信精确度更好(1毫秒)但不能记录它.

有没有人有关于如何表征软件时钟准确性的建议?

谢谢

Han*_*ant 10

您需要区分准确性,分辨率和延迟.

clock(),GetTickCount和timeGetTime()来自校准的硬件时钟.分辨率不是很好,它们由时钟节拍中断驱动,每秒默认为64次或每15.625毫秒一次.您可以使用timeBeginPeriod()将其降低到1.0毫秒.准确性非常好,时钟是从NTP服务器校准的,通常可以指望它在一个月内不会超过一秒钟.

QPC具有更高的分辨率,总是优于1微秒,在某些机器上只有半纳秒.然而,它的精度很差,时钟源是从某个地方的芯片组中拾取的频率.它没有经过校准,具有典型的电子公差.仅用于短时间间隔.

处理计时时,延迟是最重要的因素.如果您无法以足够快的速度读取,则无法使用高精度的定时源.当您在受保护模式操作系统上以用户模式运行代码时,这始终是一个问题.总是有比代码更高优先级的代码.特别是设备驱动程序尤其是故障制造者,视频和音频驱动程序.您的代码也会被换出RAM,需要加载页面错误.在负载很重的机器上,无法运行数百毫秒的代码并不罕见.您需要将此故障模式考虑在您的设计中.如果您需要保证亚毫秒精度,那么只有具有实时优先级的内核线程才能为您提供.

一个相当不错的计时器是你从timeSetEvent()获得的多媒体计时器.它旨在为需要可靠计时器的程序提供良好的服务.你可以在1毫秒内打勾,它会在可能的情况下赶上延迟.请注意它是一个异步计时器,回调是在一个单独的工作线程上进行的,所以你必须小心处理正确的线程同步.


Mat*_*son 0

对于 QPC,您可以致电QueryPerformanceFrequency获取其更新速率。除非您使用time,否则无论如何您都会获得超过 0.5 秒的计时精度,但clock并不是那么准确 - 通常是 10 毫秒段[尽管显然CLOCKS_PER_SEC标准化为 100 万,使数字看起来更准确]。

如果你按照这些思路做一些事情,你可以计算出你可以测量的间隙有多小[尽管在非常高的频率下你可能无法注意到有多小,例如更新每个时钟周期的时间戳计数器,并且读取它需要 20 -40 个时钟周期]:

 time_t t, t1;

 t = time();
 // wait for the next "second" to tick on. 
 while(t == (t1 = time()))  /* do nothing */ ;

 clock_t old = 0;
 clock_t min_diff = 1000000000;
 clock_t start, end;
 start = clock();
 int count = 0;
 while(t1 == time())
 {
    clock_t c = clock();
    if (old != 0 && c != old)
    {
       count ++;
       clock_t diff;
       diff = c - old;
       if (min_diff > diff) min_diff = diff;
    }
    old = c;
}
end = clock();
cout << "Clock changed " << count << " times" << endl;
cout << "Smallest differece " << min_diff << " ticks" << endl;
cout << "One second ~= " << end - start << " ticks" << endl; 
Run Code Online (Sandbox Code Playgroud)

显然,您可以将相同的原则应用于其他时间源。

(未经编译测试,但希望不要有太多拼写错误和错误)

编辑:所以,如果您测量 10 秒范围内的时间,以 100Hz 运行的计时器将为您提供 1000 个“滴答声”。但它可能是 999 或 1001,这取决于你的运气,你抓住它是对还是错,所以那里是 2000 ppm - 那么时钟输入也可能会有所不同,但它的变化要小得多~最多 100 ppm。对于Linux,更新频率clock()为100Hz(运行操作系统的实际计时器可能会以更高的频率运行,但clock()在Linux中将以100Hz或10ms的间隔更新[并且它仅在CPU正在使用时更新,因此坐5秒等待用户输入的时间为0]。

在Windows中,clock()测量实际时间,与手表相同,而不仅仅是正在使用的CPU,因此等待用户输入的5秒被视为5秒时间。我不确定它有多准确。

您会发现的另一个问题是,现代系统总体上不太擅长可重复计时 - 无论您做什么,操作系统、CPU 和内存都会共同作用,使获得相同时间的生活变得痛苦。两次运行。如今,CPU 经常以有意可变的时钟运行(允许漂移约 0.1-0.5%),以减少 EMC(电磁兼容性)测试尖峰的电磁辐射,这些尖峰可能会“溜出”密封良好的计算机机箱。

换句话说,即使你可以获得一个非常标准化的时钟,你的测试结果也会略有不同,这取决于你无能为力的其他因素......

总之,除非您正在寻找一个数字来填写表格,该表格要求您提供时钟精度的 ppm 数字,并且这是一个您不能不填写该信息的政府表格,否则我并不完全相信了解用于测量时间本身的计时器的准确性非常有用。因为其他因素至少也会发挥重要作用。