gcc内联汇编之rdtsc
有时会需要测试一个函数的运行时间, 用标准库的时间函数精度不够, 打印出来的运行时间是0.00000…
用循环来放大这个时间一般不会有问题的
但是如果多个算法之间时间开销差别很大, 比如函数aa()运行一次的时间是1.0s, 而函数bb()运行时间是0.000000s, 这时候再对他们用循环1000次的办法来放大时间, 这时bb()的运行时间也许刚好够打印输出, 比如是0.000010s, 那等待aa()循环1000次就得花1000s左右
这时候就需要用高精度计时器, 分别获取函数运行前和运行后的cpu时间戳, 相减就能算出函数运行需要的cpu时钟周期, 这个数字在不同的cpu上不一样, 不过只要保证每次测试是在同一台主机上测试的就没问题
以下是gcc中获取cpu时间戳的代码
static inline uint64_t get_cycle_count() { uint32_t time_high, time_low; __asm__( "rdtsc;" "movl %%edx,%0;" "movl %%eax,%1;" :"=m"(time_high),"=m"(time_low) : :"%edx","%eax" ); return (uint64_t) time_high << 32 | time_low; }
rdtsc指令是获取64位的当前时间戳(从开机开始计时), 并将高32位写入edx, 低32位写入eax
不过也不要太依赖cpu时间戳, 因为在多核cpu上不是太精确, 而且多次测试的值差别比较大…
具体原因见此文:http://blog.csdn.net/solstice/article/details/5196544
=====2013-2-14 更新=====
以前只是为了完成功能, 今天再看, 发现太多多余操作. 既然汇编都用了, 就效率至上吧
稍作优化:
static inline uint64_t get_cycle_count() { #if defined(_IA32_) __asm__( "rdtscnt" ); #elif defined(_X86_64_) __asm__( "rdtscnt" "shlq $32, %raxnt" "movl %edx, %eaxnt" "rol $32, %raxnt" ); #else union { uint64_t tick; struct { uint32_t low; uint32_t high; }st_t; }un_t; __asm__( "rdtscnt" "movl %%edx,%0nt" "movl %%eax,%1nt" :"=m"(un_t.st_t.high),"=m"(un_t.st_t.low) : :"%edx","%eax" ); return un_t.tick; #endif }