时间戳计时器
之前在做CSAPP:Lab_Performance的时候,查看代码遇到这个问题。查阅资料之后,整理、记录一下。
时间戳计时器 Time Stamp Counter(TSC)是自Pentium之后所有的x86处理器都有的一个64位寄存器。它对自上次重设之后的cycles的数量计数。指令RDSTC
将TSC返回到串联寄存器组EDX:EAX
中(即低32位保存在EAX
中,高32位保存在EDX
中)。在x86-64机器中,RDSTC
还会将RAX
和RDX
高32位清空。它的操作码是0F 31
。(以上定义,引用自(WIKIPEDIA)[en.wikipedia.org/wiki/Time_S…])
最近在查看CSAPP 对应的performance-lab的实现的时候,看到了clock.c中对于CPE计数的实现。它使用了汇编代码使用rdstc指令,来获取时间戳计时器的内容,然后对前后两次求差得到程序运行的CPE,另外由于该程序编写的年代比较久远,当时可能gcc对于64位数值还不支持,因此它使用了两个32位无符号整数ncyc_lo, ncyc_hi来分别存储rdstc指令返回的低32位和高32位,然后将结果保存在double类型result变量中。
另外,我在stack overflow中查看到还有另外一个版本使用的是rdstcp指令,在这里记录一下(stack overflow)[stackoverflow.com/questions/3…ECX
寄存器设置为0以外,所以那个版本的实现可能会导致一些意想不到的错误。
/* perf-lab clock.c*/
#if IS_x86
/* $begin x86cyclecounter */
/* Initialize the cycle counter */
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" /* Read cycle counter */
: "=r" (*hi), "=r" (*lo) /* and move results to */
: /* No input */ /* the two outputs */
: "%edx", "%eax");
}
/* Record the current value of the cycle counter. */
void start_counter()
{
access_counter(&cyc_hi, &cyc_lo);
}
/* Return the number of cycles since the last call to start_counter. */
double get_counter()
{
unsigned ncyc_hi, ncyc_lo;
unsigned 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) {
fprintf(stderr, "Error: counter returns neg value: %.0f\n", result);
}
return result;
}
/* $end x86cyclecounter */
#endif /* x86 */
在这里,其实我们完全可以使用GCC新的特性来重新实现这一部分, 1) GCC支持64位长整数,2) 不必再使用内联汇编代码,编译器已经内置了rdtsc和rdtscp,并且欧了__rdstc intrinsic,只要包括了正确的头文件。
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
/* Implementation uses gcc builtin instructions of * the rdtsc instruction. */
inline
unsigned long long access_counter()
{
return __rdstc();
}
/* Record the current value of the cycle counter. */
void start_counter()
{
cyc = access_counter();
}
/* Return the number of cycles since the last call to start_counter. */
double get_counter()
{
unsigned long long ncyc, result;
/* Get cycle counter */
ncyc = access_counter();
result = ncyc - cyc;
if (result < 0) {
fprintf(stderr, "Error: counter returns neg value: %.0f\n", result);
}
return result;
}
/* $end x86cyclecounter */
#endif /* x86 */
今天的文章时间戳计时器分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/59667.html