时间安排和基准测试

时间:2010-12-12 22:41:44

标签: c++ windows algorithm benchmarking

如果我想比较两种算法的速度,最好的方法是什么? 我熟悉数学方法,我知道我还没有完全掌握它= / 我很想知道如何在Windows上以高精度计算两种算法。 什么是最好的API,stdio.h中的time()是可靠的还是我需要更好的东西?

一个例子也会很好! 谢谢!

3 个答案:

答案 0 :(得分:2)

您要找的是QueryPerformanceCounterQueryPerformanceFrequency。这些是用于访问高分辨率计时器的Windows API函数。它们应该比timeGetSystemTime产生更好的精确度。

LARGE_INTEGER time1;
QueryPerformanceCounter(&time1);

// Your code

LARGE_INTEGER time2;
QueryPerformanceCounter(&time2);

LARGE_INTEGER ticksPerSecond;
QueryPerformanceFrequency(&ticksPerSecond);
double seconds = (double)(time2.QuadPart - time1.QuadPart) / ticksPerSecond.QuadPart;

here我找到了一个CStopWatch类的实现,可以作为一个例子。

答案 1 :(得分:2)

不幸的是,这不是一件容易的事。

如前所述,QueryPerformanceCounter是一个可行的选择 其他可能性是:
- GetTickCount (不建议,因为其准确性低于30毫秒) - timeGetTime :默认情况下,精度为15ms。这对应于任务调度程序分配的默认时间(在我的计算机上为15ms)。您可以通过更改规则调度程序分配的时间的系统范围设置来强制timeGetTime更准确:调用timeBeginPeriod可以执行此操作。但是,这应该仅用作临时系统黑客!请不要在发布代码中使用它!
- 查询处理器的时间戳计数器:这需要汇编程序编程,我不推荐它。

就QueryPerformanceCounter而言,您可以在此处找到一个易于使用的包装器:http://www.codeproject.com/KB/datetime/perftimer.aspx

你可以这样使用它:

CPerfTimer t;
t.Start();     
CallExpensiveTask();
std::cout << "Time (ms) " << t.Elapsedms();

但是有一些建议:

  • 如上所述,为了获得可靠的衡量标准,请多次运行您的功能
  • 小心任务调度程序: 在平均计算机上,每个进程在切换到另一个进程之前给出15ms。如果任务调度程序在调用测量函数期间切换任务,则可能会测量更高的时间(大约高出15ms)
  • 请注意,sleep(1)会暂停15ms(因为调度程序将切换到不同的进程)
  • 请记住,QueryPerformanceCounter可以(很少)提供不准确的结果: 在多核处理器上,您有时可能会看到负时间间隔(!)。在这种情况下,您应该重做您的措施(请参阅http://www.virtualdub.org/blog/pivot/entry.php?id=106)
  • 抵消调度程序效果的临时解决方案: - 提高您的流程优先级(您可以通过任务管理器完成) - 破解调度程序:microsoft提供的timeBeginPeriod(http://msdn.microsoft.com/en-us/library/dd757624(v=VS.85).aspx)有权更改分配给每个任务的时间15ms到更低的值(记住不包括这是你的发布代码,因为这是一个系统范围的设置,可以降低全局性能......)

有关处理器时间戳计数器的更多说明

  • 我自己没有测试它的准确性,但http://en.wikipedia.org/wiki/Time_Stamp_Counter是一个很好的信息来源,关于它的局限性(特别是在多核处理器上,也在处理器上)可变时钟频率)
  • AFAIK,建议在单个线程上使用这种计时器,为其设置处理器关联性
  • 实施示例(位于http://developer.nvidia.com/object/timer_function_performance.html)可能是:
#pragma warning (disable : 4035)    // disable no return value warning

__forceinline  DWORD GetPentiumCounter()
{
__asm
{
    xor   eax,eax             // VC won't realize that eax is modified w/out this
                              //   instruction to modify the val.
                              //   Problem shows up in release mode builds
    _emit 0x0F                // Pentium high-freq counter to edx;eax
    _emit 0x31                // only care about low 32 bits in eax

    xor   edx,edx             // so VC gets that edx is modified
}
}

#pragma warning (pop)

答案 2 :(得分:0)

QueryPerformanceCounter的/ QueryPerformanceFrequency的。 AFAIK,现在已修复,实际上是测量周期。只需记住提高线程的优先级,以便在测量时它对其他线程的影响较小。

如果可测量代码的运行时间很短,则抢占可能会导致相当多的错误。

因此提升优先级并多次重新运行测试。