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
}