Нестабильная калибровка __rdtscp под Linux на Intel Xeon X5550

Я пытаюсь использовать __rdtscp встроенная функция для измерения временных интервалов. Целевой платформой является Linux x64, процессор Intel Xeon 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, результат калибровки довольно стабилен, небольшая разница только в последней цифре.

Итак, вопрос — о чем эта проблема? Это проблема с процессором, проблема с Linux или проблема с моим кодом?

2

Решение

Другие источники дрожания будут присутствовать, если вы также не обеспечите изоляцию процессора. Вы действительно хотите избежать планирования другого процесса в этом ядре.
Также в идеале вы запускаете ядро ​​без галочек, чтобы вы никогда не запускали код ядра на этом ядре. В приведенном выше коде я думаю, что это будет иметь значение, только если вам не повезет, чтобы получить тик или переключение контекста между вызовами clock_gettime () и __rdtscp

Создание s volatile — это еще один способ победить оптимизацию компилятора.

3

Другие решения

Определенно это была моя проблема с кодом (или gcc). Компилятор оптимизировал цикл, заменив его s = 1000000,

Чтобы не допустить оптимизации gcc, этот калибровочный контур должен быть изменен следующим образом:

for (size_t i = 0; i < 1000000; ++i) s += i;

Или более простым и правильным способом (спасибо Хэлу):

for (volatile size_t i = 0; i < 1000000; ++i);
2

По вопросам рекламы [email protected]