Точность 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()
вы можете установить сходство потоков, чтобы запустить поток на одном ядре процессора.