5

我想描述软件计时器的准确性。我不太关心它的准确度,但确实需要知道准确度是多少。

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

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

虽然更喜欢更高的准确性,但我宁愿知道准确性很差(500ms)并考虑它,而不是相信准确性更好(1 ms)但无法记录它。

有人对如何表征软件时钟精度有任何建议吗?

谢谢

4

3 回答 3

11

您需要区分准确性、分辨率和延迟。

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

QPC 的分辨率要高得多,在某些机器上总是优于一微秒,甚至只有半纳秒。然而,它的精度很差,时钟源是从芯片组某处拾取的频率。它未经校准,具有典型的电子公差。仅用于短时间间隔。

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

一个相当不错的计时器是您从 timeSetEvent() 获得的多媒体计时器。它旨在为需要可靠计时器的程序提供良好的服务。你可以让它以 1 毫秒的速度滴答作响,它会尽可能赶上延迟。请注意,它是一个异步计时器,回调是在单独的工作线程上进行的,因此您必须小心处理正确的线程同步。

于 2013-08-21T01:24:07.973 回答
1

由于您要求提供确凿的事实,因此它们是:

典型的频率设备控制HPETsCB3LV-3I-14M31818 ,它规定在 -40 °C 和 +85 °C 之间的频率稳定性为 +/- 50ppm。更便宜的芯片是CB3LV-3I-66M6660。该器件在 -20°C 和 70°C 之间具有 +/- 100 ppm 的频率稳定性。

如您所见,50 到 100 ppm 将导致 50 到 100 微秒/秒、180 到 360 毫秒/小时或 4.32 到 8.64 秒/天的漂移!

控制RTC它们的设备通常要好一些:RV-8564-C2 RTC 模块提供 +/- 10 到 20 ppm 的容差。更严格的公差通常可提供军用版本或应要求提供。该来源的偏差比 HPET 的偏差小 5 倍。但是,它仍然是 0.86 秒/天。

以上所有值均为数据表中指定的最大值。正如我在评论中提到的,典型值可能要少得多,它们在几个 ppm 范围内。

频率值也伴随着热漂移。结果QueryPerformanceCounter()可能会受到使用 ACPI 电源管理定时器芯片(示例)运行的系统上的热漂移的严重影响。

关于定时器的更多信息:时钟和定时器电路

于 2013-08-22T07:08:28.673 回答
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; 

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

(未经过编译测试,但希望不会有太多错别字和错误)

编辑:因此,如果您测量 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 数字,并且这是您不能不填写该信息的政府表格,否则我并不完全相信了解用于测量时间本身的计时器的准确性非常有用。因为其他因素至少会起到同样重要的作用。

于 2013-08-21T00:26:50.610 回答