时间戳计时器

时间戳计时器之前在做CSAPP:Lab_Performance的时候,查看代码遇到这个问题。查阅资料之后,整理、记录一下。时间戳计时器 Time Stamp Counter(TSC)是自Pentium之后所有的x86处理器都有的一个64位寄存器。它对自上次重设之后的cycles的数量计数。指…

时间戳计时器

之前在做CSAPP:Lab_Performance的时候,查看代码遇到这个问题。查阅资料之后,整理、记录一下。

时间戳计时器 Time Stamp Counter(TSC)是自Pentium之后所有的x86处理器都有的一个64位寄存器。它对自上次重设之后的cycles的数量计数。指令RDSTC将TSC返回到串联寄存器组EDX:EAX中(即低32位保存在EAX中,高32位保存在EDX中)。在x86-64机器中,RDSTC还会将RAXRDX高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

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注