Time Stamp Counter (TSC) 知识点
2018-05-23 本文已影响0人
学生张奎
什么是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年。