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

原创 2012年06月01日 09:34:09

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

可用的计时方法

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

推荐阅读


分别使用递归方法和非递归方法求斐波那契数列,并比较两者的运行速度(测量代码运行时间)

由运行时间可知,当数据量增大时,递归方法程序运行效率成为瓶颈,速度变得极为缓慢。 #include #include #include using namespace std; int Func...

C#三种性能分析计时器介绍

第一种方法:使用Stopwatch class Program { static void Main(string[] args) { ...

python3 性能测量

环境$ cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core)工具$ sudo pip3 install gprof2dot $ s...

短波单边带接收机电性能测量方法

  • 2016年05月16日 11:06
  • 5.18MB
  • 下载

Linux 下的一个全新的性能测量和调式诊断工具 Systemtap,第 1 部分: kprobe

http://www.ibm.com/developerworks/cn/linux/l-cn-systemtap1/index.html kprobe 的原理、编程接口、局限性和使用注...
  • hnllei
  • hnllei
  • 2012年04月28日 18:10
  • 802

高速ADC动态性能参数测量的方法

  • 2016年01月30日 23:44
  • 1.57MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用计时器来测量代码性能
举报原因:
原因补充:

(最多只允许输入30个字)