Time Stamp Counter (TSC) 知识点

什么是Time Stamp Counter(TSC)

从Pentium处理器开始,Intel允许程序员获取TSC。TSC保存着精确的时钟周期计数。Intel的TSC是64位的MSR(model specific register),每个时钟周期自增。

TSC衡量的是时钟周期而不是时间。例如,在200MHZ的处理器中,200Million个周期等于1秒的实际时间。相同的周期数值在400MHZ的处理其中则只有0.5秒的实际时间。所以,只有在相同频率的CPU之间比较周期计数值才有意义。比较不同频率CPU之间的数值时,周期计数值应该被转换成时间单元:

实际秒数 = 时钟周期 / 时钟频率

如何获取TSC

程序员通过RDTSC(read time-stamp counter)指令获取计数器的数值。这个指令将高32位加载到EDX,低32位加载到EAX。

BTC中获取TSC的代码段如下:

static inline int64_t GetPerformanceCounter()
{
    // Read the hardware time stamp counter when available.
    // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
    return __rdtsc();
#elif !defined(_MSC_VER) && defined(__i386__)
    uint64_t r = 0;
    __asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair.
    return r;
#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
    uint64_t r1 = 0, r2 = 0;
    __asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
    return (r2 << 32) | r1;
#else
    // Fall back to using C++11 clock (usually microsecond or nanosecond precision)
    return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
}

何时使用TSC?

TSC不应该被用作一般的代码性能分析,很多性能分析工具比TSC提供更多的信息,比如VTune。

一些比较有用的场景:

1、衡量一个代码段执行的时钟周期;
2、估计一个方法或者代码段的平均运行时间。

BTC代码中TSC被用作生成随机数的种子。

影响时钟周期计数的因素:

1、乱序执行。Pentium Pro以后指令会乱序执行,导致错误的技术。解决方法是强制指令顺序执行,比如用CPUID指令。

2、数据缓存和指令缓存。

3、寄存器重写。一些编译器在内联的汇编代码中不会识别RDTSC和CPUID命令,但是这两个指令会导致重写寄存器的值。编译器将无法合适的存储被影响的寄存器的值。

4、寄存器溢出。在一个400MHZ的CPU上,仅使用低32位的值,在10.74秒后会溢出,如果使用64位精度,溢出的时间是1462.36年。

参考资料:
https://www.ccsl.carleton.ca/~jamuir/rdtscpm1.pdf

你可能感兴趣的:(Time Stamp Counter (TSC) 知识点)