测量计时器的精确度(例如秒表/ QueryPerformanceCounter)

时间:2016-03-30 19:45:28

标签: c# performance benchmarking stopwatch microbenchmark

鉴于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;

然后差异将是大约100 ticks4000 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中的最高刻度减去ticksLower中的最低刻度。

这听起来合理吗?

为什么我想知道Stopwatch的可观察精度?因为这可以用于确定您需要测量的时间长度,以获得微基准测量的一定精度水平。即对于3位精度,长度应该是计时器精度的> 1000倍。当然,人们可以用这个长度多次测量。

1 个答案:

答案 0 :(得分:0)

Stopwatch类公开了一个Frequency属性,它是调用SafeNativeMethods。QueryPerformanceFrequency的直接结果。以下是属性页面的摘录:

  

频率值取决于基础时间的分辨率   机制。如果安装的硬件和操作系统支持a   高分辨率性能计数器,然后频率值反映   那个柜台的频率。否则,频率值基于   关于系统定时器频率。