Точность rdtsc в ядрах CPU

Я отправляю сетевые пакеты из одного потока и получаю ответы на второй поток, который работает на другом ядре ЦП. Мой процесс измеряет время между отправкой и получением каждого пакета (аналогично ping). Я использую rdtsc для получения времени с высоким разрешением и низким временем выполнения, которое необходимо для моей реализации.

Все измерения выглядят надежными. Тем не менее, меня беспокоит точность rdtsc по всем ядрам, поскольку я читал некоторые тексты, которые подразумевали, что tsc не синхронизирован между ядрами.

Я нашел следующую информацию о TSC в википедии

Постоянное поведение TSC гарантирует, что продолжительность каждого такта и поддерживает использование TSC в качестве таймера настенных часов, даже если процессорное ядро ​​меняет частоту. Эта является перемещение архитектурного поведения для всех процессоров Intel.

Тем не менее, я беспокоюсь о accururacy по ядрам, и это мой вопрос

Дополнительная информация

  • Я запускаю свой процесс на машине Intel nehalem.
  • Операционная система - Linux.
  • Флаг cpu constant_tsc установлен для всех ядер.

Ответ 1

X86_FEATURE_CONSTANT_TSC + X86_FEATURE_NONSTOP_TSC бит в cpuid (edx = x80000007, бит # 8; check unsynchronized_tsc function ядра linux для больше проверок)

Intel Designer vol3b, раздел 16.11.1 Инвариантный TSC говорит следующее

"16.11.1 Инвариантный TSC

Счетчик метки времени в новых процессорах может поддерживать расширение, называемое инвариантным TSC. Поддержка процессора для инвариантного TSC указывается CPUID.80000007H: EDX [8].

Инвариантный TSC будет работать с постоянной скоростью во всех ACPI P-, C-. и T-состояния. Это архитектурное поведение продвигается вперед. На процессорах с инвариантной поддержкой TSC ОС может использовать TSC для служб таймера настенных часов (вместо таймеров ACPI или HPET). Чтения TSC намного эффективнее и не несут накладные расходы, связанные с циклическим переходом или доступом к ресурсу платформы.

Итак, если TSC можно использовать для разгона, они гарантированно синхронизируются.

Ответ 2

В linux вы можете использовать clock_gettime (3) с CLOCK_MONOTONIC_RAW, что дает вам повторение наносимых наносекунд и не подлежит обновлению ntp (если это произошло).

Ответ 3

На последних процессорах вы можете делать это между отдельными ядрами одного и того же пакета (т.е. с одним ядерным процессором iX), вы просто не можете делать это в отдельных пакетах (процессорах), потому что они не будут делиться РТК. Вы можете уйти от него с помощью слияния cpu (блокировка соответствующих потоков для определенных ядер), но опять же это будет зависеть от поведения вашего приложения.

В linux вы можете проверить constant_tsc на /proc/cpuinfo, чтобы увидеть, имеет ли процессор один tsc, действительный для всего пакета. Необработанный регистр находится в CPUID.80000007H: EDX [8]

То, что я читал, но еще не подтвержденным программным путем, заключается в том, что AMD cpus из версии 11h имеет тот же смысл для этого cpuid-бита.

Ответ 4

На самом деле кажется, что ядра не разделяют TSC, проверьте этот поток: http://software.intel.com/en-us/forums/topic/388964

Подводя итог, разные ядра не делят TSC, иногда TSC может выйти из синхронизации, если ядро ​​переходит в конкретное состояние энергии, но зависит от типа процессора, поэтому вам нужно проверить документацию Intel. Кажется, что большинство операционных систем синхронизируют TSC при загрузке.
Я проверил различия между TSC на разных ядрах, используя алгоритм возбуждающего реагирования, на машине Linux Debian с процессором Core i5. Процесс возбуждения (в одном ядре) подавал TSC в общей переменной, когда реагирующий процесс обнаружил изменение в этой переменной, он сравнивает его значение и сравнивает его со своим собственным TSC. Это пример вывода моей тестовой программы:

TSC ping-pong test result:
TSC cores (exciter-reactor): 0-1
100 records, avrg: 159, range: 105-269
Dispersion: 13
TSC ping-pong test result:
TSC cores (exciter-reactor): 1-0
100 records, avrg: 167, range: 125-410
Dispersion: 13

Время реакции, когда процессор возбудителя равен 0 (159 тиков в среднем), почти совпадает с тем, когда процессор возбудителя равен 1 (167 тиков). Это указывает на то, что они довольно хорошо синхронизированы (возможно, с несколькими тиками разницы). На других парах ядер результаты были очень похожи.
С другой стороны, команда сборки rdtscp возвращает значение, указывающее CPU, в котором был прочитан TSC. Это не ваше дело, но может быть полезно, когда вы хотите измерить время в простом сегменте кода, и вы хотите убедиться, что процесс не был перемещен из центрального процессора в середине кода.

Ответ 5

Я рекомендую вам не использовать rdtsc. Он не только не переносимый, он не надежный и вообще не будет работать - в некоторых системах rdtsc не обновляется равномерно (например, если вы используете speedstep и т.д.). Если вам нужна точная информация о времени, вы должны установить опцию SO_TIMESTAMP в сокете и использовать recvmsg(), чтобы получить сообщение с отметкой времени (микросекундное разрешение).

Кроме того, временная метка, которую вы получаете с помощью SO_TIMESTAMP, на самом деле - это время, когда ядро ​​получило пакет, а не когда ваша задача заметила.

Ответ 6

С помощью API sched_set_affinity() вы можете установить сходство потоков, чтобы запустить поток на одном ядре процессора.