打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
X86平台采用rdtsc指令读取时间戳计数器完成高精度计时

X86平台采用rdtsc指令读取时间戳计数器完成高精度计时

从pentium开始,很多80x86微处理器都引入TSC,一个用于时间戳计数器的64位的寄存器,它在每个时钟信号(CLK, CLK是微处理器中一条用于接收外部振荡器的时钟信号输入引线)到来时加一。
通过它可以计算CPU的主频,比如:如果微处理器的主频是1MHZ的话,那么TSC就会在1秒内增加1000000。除了计算CPU的主频外,还可以通过TSC来测试微处理器其他处理单元的运算速度,http://www.h52617221.de/dictionary.php?id=278 介绍了这个内容。
那么如何获取TSC的值呢?rdtsc,一条读取TSC的指令,它把TSC的低32位存放在eax寄存器中,把TSC的高32位存放在edx中,更详细的描述见资料[1]。
下面来看看rdtsc的具体用法,在linux源代码include/asm-i386/msr.h中,可以找到这么三个关于rdtsc的宏定义:

#define rdtsc(low,high) \
      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
#define rdtscl(low) \
       __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
#define rdtscll(val) \
       __asm__ __volatile__("rdtsc" : "=A" (val))


如果我们想准确的知道一段程序,一个函数的执行时间,可以连续执行2次rdtsc,之间没有一行代码,来计算这两段指令执行过程会有的cycle数,不同机器可能都会有不同,和机器的性能有关系,但和负载没关系,也就是多进程,多线程情况下,连续两个rdtsc之间不会插入很多cycle。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static unsigned cyc_hi = 0;
static unsigned cyc_lo = 0;
 
/* Set *hi and *lo to the high and low order bits of the cycle counter.
 *    Implementation requires assembly code to use the rdtsc instruction. */
void access_counter(unsigned *hi, unsigned *lo)
{
        asm("rdtsc; movl %%edx, %0; movl %%eax, %1"
                        : "=r" (*hi), "=r" (*lo)
                        : /* No input */
                        : "%edx", "%eax");
        return;
}
 
/* Record the current value of the cycle counter. */
void start_counter(void)
{
        access_counter(&cyc_hi, &cyc_lo);
        return;
}

RDTSC只在X86下有效,其余平台会有类似指令来做准确计数,RDTSC指令的精度是可以接受的,里面能插得cycle是很有限的。如果对计数要求没那么高,可以采用一些通用库函数,当然你也可以用类似的方法来考察这些库函数的精度,连续执行2次就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Return the number of cycles since the last call to start_counter. */
double get_counter(void)
{
        unsigned int    ncyc_hi, ncyc_lo;
        unsigned int    hi, lo, borrow;
        double  result;
 
        /* Get cycle counter */
        access_counter(&ncyc_hi, &ncyc_lo);
 
        /* Do double precision subtraction */
        lo = ncyc_lo - cyc_lo;
        borrow = lo > ncyc_lo;
        hi = ncyc_hi - cyc_hi - borrow;
 
        result = (double)hi * (1 << 30) * 4 + lo;
        if (result < 0) {
                printf("Error: counter returns neg value: %.0f\n", result);
        }
        return result;
}


函数调用方式:

start_counter();
tmp = fast_log(input);
cnt = get_counter();
printf("tmp = %f. clk counter = %lf.\n",tmp,cnt);

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
使用CPU时间戳进行高精度计时
x86和arm架构原子操作的区别 - 嵌入式 - 人月计划
linux内核部件分析(二)——原子性操作atomic
用rdrtc实现linux下的精确计时
绝招:一招擒拿翻倍牛股!(二)
(转)[KVM学习笔记]TSC研究总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服