我正在尝试使用__rdtscp
内在函数来测量时间间隔。目标平台是Linux x64,CPU英特尔至强X5550。尽管constant_tsc
为此处理器设置了标志,但校准__rdtscp
会产生非常不同的结果:
$ taskset -c 1 ./ticks
Ticks per usec: 256
$ taskset -c 1 ./ticks
Ticks per usec: 330.667
$ taskset -c 1 ./ticks
Ticks per usec: 345.043
$ taskset -c 1 ./ticks
Ticks per usec: 166.054
$ taskset -c 1 ./ticks
Ticks per usec: 256
$ taskset -c 1 ./ticks
Ticks per usec: 345.043
$ taskset -c 1 ./ticks
Ticks per usec: 256
$ taskset -c 1 ./ticks
Ticks per usec: 330.667
$ taskset -c 1 ./ticks
Ticks per usec: 256
$ taskset -c 1 ./ticks
Ticks per usec: 330.667
$ taskset -c 1 ./ticks
Ticks per usec: 330.667
$ taskset -c 1 ./ticks
Ticks per usec: 345.043
$ taskset -c 1 ./ticks
Ticks per usec: 256
$ taskset -c 1 ./ticks
Ticks per usec: 125.388
$ taskset -c 1 ./ticks
Ticks per usec: 360.727
$ taskset -c 1 ./ticks
Ticks per usec: 345.043
如我们所见,程序执行之间的差异最多可以达到3倍(125-360)。这种不稳定性不适用于任何测量。
以下是代码(gcc 4.9.3,在Oracle Linux 6.6上运行,内核3.8.13-55.1.2.el6uek.x86_64):
// g++ -O3 -std=c++11 -Wall ticks.cpp -o ticks
#include <x86intrin.h>
#include <ctime>
#include <cstdint>
#include <iostream>
int main()
{
timespec start, end;
uint64_t s = 0;
const double rdtsc_ticks_per_usec = [&]()
{
unsigned int dummy;
clock_gettime(CLOCK_MONOTONIC, &start);
uint64_t rd_start = __rdtscp(&dummy);
for (size_t i = 0; i < 1000000; ++i) ++s;
uint64_t rd_end = __rdtscp(&dummy);
clock_gettime(CLOCK_MONOTONIC, &end);
double usec_dur = double(end.tv_sec) * 1E6 + end.tv_nsec / 1E3;
usec_dur -= double(start.tv_sec) * 1E6 + start.tv_nsec / 1E3;
return (double)(rd_end - rd_start) / usec_dur;
}();
std::cout << s << std::endl;
std::cout << "Ticks per usec: " << rdtsc_ticks_per_usec << std::endl;
return 0;
}
当我在Windows 7,i7-4470,VS2015下运行非常相似的程序时,校准结果非常稳定,只有最后一位的差异很小。
那么问题来了-那是什么问题呢?是CPU问题,Linux问题还是我的代码问题?
绝对是我的代码(或gcc)问题。编译器优化了循环,将其替换为s = 1000000
。
为防止gcc优化此校准回路,应按以下方式进行更改:
for (size_t i = 0; i < 1000000; ++i) s += i;
或更简单正确的方法(感谢Hal):
for (volatile size_t i = 0; i < 1000000; ++i);
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句