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

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

可用的计时方法

  • 汇编指令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().

推荐阅读


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值