我想在Windows中使用QueryPerformanceCounter来衡量代码块的性能。我想知道的是,在不同的运行之间我是否可以做一些事情以获得相同数据的相同测量值(我想测量不同排序算法在包含pod或某些自定义对象的不同大小的数组上的性能)。我知道由于中断或I / O操作,当前进程可能会因执行而中断。我没有做任何I / O,所以它只是可能影响我的测量的中断,我假设内核也有一些允许我的进程运行的时间框架,所以我认为& #39; s也会安排我的过程。
人们如何通过测量特定代码的执行时间来进行准确的测量?
答案 0 :(得分:1)
刚刚和Fasti Alexandrescu在Fastware上开会,他正在解决这个问题,如何衡量速度。显然得到平均值是一个坏主意,但多次测量是一个好主意。因此,考虑到这一点,您测量了一百万次,并记住最小的测量值,因为实际上您可以获得最少的噪音。
意味着很糟糕,因为你实际上将更多的噪音重量加到你测量的实际速度上(这些不是你在评估代码速度时应该考虑的唯一事情,但这是一个好的开始,还有更多关于代码执行位置的可怕内容,以及代码在一个核心上开始执行并在另一个核心上完成的开销带来的开销,但这是一个不同的故事,我不认为它适用于我的类型。)
一个好笑话是:如果你把比尔盖茨放到公共汽车上,平均每辆公共汽车都是百万富翁:))
干杯并感谢所有提供意见的人。
答案 1 :(得分:1)
时间测量很棘手,因为你需要找出你的算法速度慢的原因。这取决于输入数据(例如,预先排序的数据,请参阅Why is it faster to process a sorted array than an unsorted array?)或数据集大小(适合L1,L2,L3缓存,请参阅http://igoro.com/archive/gallery-of-processor-cache-effects/)。
这会极大地影响您的测量时间。 此外,测量的顺序可以发挥关键作用。如果在循环中执行sort alogs并且每个都分配一些内存,则第一次测试很可能会松动。并不是因为算法较差,但是当您第一次访问新分配的内存时,它将被软故障导入您的流程工作集。释放内存后,堆分配器将返回池内存,这将具有完全不同的访问性能。如果你排序更大(很多MB)的数组,那就变得非常明显了。
以下是第一次和第二次打印时来自不同线程的2 GB阵列的触摸时间。每页(4KB)的内存只触摸一次。
Threads Size_MB Time_ms us/Page MB/s Scenario
1 2000 355 0.693 5634 Touch 1
1 2000 11 0.021 N.a. Touch 2
2 2000 276 0.539 7246 Touch 1
2 2000 12 0.023 N.a. Touch 2
3 2000 274 0.535 7299 Touch 1
3 2000 13 0.025 N.a. Touch 2
4 2000 288 0.563 6944 Touch 1
4 2000 11 0.021 N.a. Touch 2
// Touch is from the compiler point of view a nop operation with no observable side effect
// This is true from a pure data content point of view but performance wise there is a huge
// difference. Turn optimizations off to prevent the compiler to outsmart us.
#pragma optimize( "", off )
void Program::Touch(void *p, size_t N)
{
char *pB = (char *)p;
char tmp;
for (size_t i = 0; i < N; i += 4096)
{
tmp = pB[i];
}
}
#pragma optimize("", on)
要真正判断算法的性能,仅执行时间测量是不够的,但您需要一个分析器(例如免费的Windows性能工具包,来自英特尔的VTune(非免费)),以确保您已经测量了正确的东西,不是完全不同的东西。