使用计时器来测量代码性能

来源:互联网 发布:网络聊天技巧知乎 编辑:程序博客网 时间:2024/06/06 07:29

在性能优化的时候,我们首先要做的是确定优化目标,即要定位最耗时的代码段 (在之前需要做架构和设计方案的优化,只有先确保房子盖的坚固没问题,才去考虑装修的事)。通常的做法就是加一些计时代码来测量代码的执行时间,看是否符合预期。那么本文就介绍一些与计时相关的一些知识。

可用的计时方法

  • 汇编指令RDTSC
  • GetTickCount()
  • timeGetTime()
  • QueryPerformanceCount()

关于RDTSC指令

  • Intel Pentium系列以后的所有处理器中都包含一个64 bit的寄存器TSC, 该寄存器保存CPU重置后经过的指令周期数。而RDTSC指令就是用来读取该寄存器值,通过EDX:EAX返回。并不是所有的处理器都包含该寄存器,如Cyrix 6x86。在Linux下,如果/proc/cpuinfo包含rdtscp,那么处理器支持TSC。
  • 当代码运行在多核或支持超线程的处理器环境,或支持休眠的操作系统中时,要小心使用RDTSC指令。因为多CPU下的TSC并不会保持同步,而系统休眠时会改变处理器的工作频率。
  • Intel Pentium Pro以后的处理器支持指令重排优化,也就是说RDTSC的执行顺序可能会被改变,从而计算了错误的指令执行时间。为了防止这种情况出现,可以先执行一些序列化指令,如CPUID。
  • 在Windows平台中,微软不建议使用TSC作为高精度的计时器,建议使用QueryPerformanceCounter()和QueryPerformanceFrequency()。Linux平台下有类似的函数,clock_gettime(CLOCK_MONOTONIC).

UINT64 readtsc(void) {#if defined(__GNUC__)#   if defined(__i386__)    uint64_t x;    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));    return x;#   elif defined(__x86_64__)    uint32_t hi, lo;    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));    return ((uint64_t)lo) | ((uint64_t)hi << 32);#   else#       error Unsupported architecture.#   endif#elif defined(_MSC_VER)    __asm {        return __rdtsc();    }#else#   error Other compilers not supported...#endif}

将机器指令周期转换为时间

  • 首先要获取CPU的主频,一般忽略因系统休眠而产生的变频问题。在Windows下,可以读取注册表值:HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\N\~MHz,也可直接调用QueryPerformanceFrequency()。在Linux下,可以读取/proc/cpuinfo。
  • 时间差 = 指令周期差 / CPU主频

如何精确测量代码的运行时间

  • 根据你的需要来选择测量方法,GetTickCount()和timeGetTime()提供ms级精度,但是它们比RDTSC和QueryPerformanceCount()更稳定。
  • 减少代码被中断的机会:尽量减少需要测量的代码量(减少线程被切换的机会);尽量减小需要访问的内存(缓存命中、缺页、内存对齐等都会影响运行时间变化);提高线程优先级;
  • Cache warming: 将数据和指令提前放入缓存。
  • 多次测量取最小值。
  • QueryPerformanceCounter()使用多种方式来获取时间计数值,如在单处理器Intel平台中可能由RDTSC实现,其它平台下也可能通过专用的高精度硬件计时器。因此,QueryPerformanceCounter()本身的调用开销相对于RDTSC指令要高昂的多,在一些较小任务的计时操作时不得不考虑该因素。此外,在多处理器平台中,建议通过SetThreadAffinityMask()来限制线程的执行处理器,从而克服多处理器的时钟不同步问题。但是,SetThreadAffinityMask()会极大的影响系统的调度策略,一般会对性能造成影响,此时可以考虑SetThreadIdealProcessor().

推荐阅读

  • Time Stamp Counter
  • Using the RDTSC Instruction for Performance Monitoring
  • How to Benchmark Code Execution Times on Intel IA-32 and IA-64 Instruction Set Architectures
  • 多核时代不宜再用x86的RDTSC指令测试指令周期和时间
  • Performance measurements with RDTSC
  • Windows下遇到测量代码性能问题
  • Game Timing and Multicore Processors

原创粉丝点击