测量定时器的精度(例如秒表/ QueryPerformanceCounter)
鉴于C#中的Stopwatch
类可以使用类似下面三个不同计时器的东西
- 系统定时器,例如精度约为
+-10 ms
具体取决于可通过timeBeginPeriod
设置的定时器分辨率,约为+-1 ms
。 - 时间戳计数器(TSC)例如,滴答频率为2.5MHz或1滴=
400 ns
因此理想情况下是精确度。 - 高精度事件定时器(HPET),例如,滴答频率为25MHz或1滴=
40 ns
因此理想情况下是精确度。
我们如何衡量这种可观察的精度? 精度被定义为
精度是指两次或多次测量彼此的接近程度。
现在,如果Stopwatch
使用HPET,这是否意味着我们可以使用Stopwatch
来测量与定时器频率相当的精度?
我不这么认为,因为这要求我们能够使用零差异或完全固定开销的计时器,据我所知,对于Stopwatch
来说并非如此。 例如,使用HPET并调用时:
var before_ticks = Stopwatch.GetTimestamp(); var after_ticks = Stopwatch.GetTimestamp(); var diff_ticks = after_ticks - before_ticks;
那么diff会说大约100 ticks
或4000 ns
,它也会有一些变化。
那么如何通过实验测量Stopwatch
的可观测精度呢? 所以它支持下面所有可能的定时器模式。
我的想法是搜索最小数量的刻度!= 0,首先建立Stopwatch
的开销,用于系统计时器,这将是0,直到例如10ms
,即10 * 1000 * 10 = 100,000个刻度,因为系统计时器的刻度分辨率为100ns
,但精度远非如此。 对于HPET,它永远不会为0,因为调用Stopwatch.GetTimestamp()
的开销高于计时器的频率。
但这并没有说明我们使用计时器测量的精确程度。 我的定义是我们可以可靠地测量的差异有多小。
可以通过测量不同的迭代次数ala来执行搜索:
var before = Stopwatch.GetTimestamp(); for (int i = 0; i < iterations; ++i) { action(); // Calling a no-op delegate Action since this cannot be inlined } var after = Stopwatch.GetTimestamp();
首先,可以找到下限,其中对于给定iterations
所有10个测量结果都产生非零数量的刻度,将这些测量值保存在long ticksLower[10]
。 然后,最接近可能的迭代次数产生的滴答差异始终高于前10个测量中的任何一个,将其保存在long ticksUpper[10]
。
最差情况精度将是ticksUpper
的最高刻度减去ticksUpper
最低刻度。
这听起来合理吗?
为什么我想知道Stopwatch
的可观察精度? 因为这可以用于确定您需要测量的时间长度,以获得微基准测量的一定精度水平。 即3位精度,长度应>计时器精度的1000倍。 当然,用这个长度可以测量多次。
Stopwatch类公开了一个Frequency属性,它是调用SafeNativeMethods的直接结果。 QueryPerformanceFrequency 。 以下是属性页面的摘录:
频率值取决于基础计时机制的分辨率。 如果安装的硬件和操作系统支持高分辨率性能计数器,则Frequency值反映该计数器的频率。 否则,频率值基于系统定时器频率。