Rdtsc

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

rdtsc (англ. Read Time Stamp Counter) — ассемблерная инструкция для платформы x86, читающая счётчик TSC (Time Stamp Counter) и возвращающая в регистрах EDX:EAX 64-битное количество тактов с момента последнего сброса процессора.

rdtsc поддерживается в процессорах Pentium (и совместимых с ними) и более новых. Опкод: 0F 31.

rdtscp[1] поддерживается начиная с Intel Nehalem и AMD Family 0x0F[2]. Опкод: 0F 01 F9.[3]

Использование[править | править исходный текст]

rdtsc чаще всего используется:

  • для измерения времени;
  • для точного измерения временных интервалов;
  • при оптимизации — для измерения времени, необходимого для выполнения конкретных инструкций или их набора;
  • в антиотладочных целях;[4][5]
  • как источник энтропии для генераторов псевдослучайных чисел.[6]

Преимущества[править | править исходный текст]

В сравнении с предоставляемыми операционными системами API (при условии отсутствия перечисленных ниже проблем) вроде WINAPI::QueryPerformanceCounter() или gettimeofday() инструкция rdtsc предоставляет следующие преимущества.

  • Точность почти до тика, что особенно критично для архитектур и операционных систем, полноценно не поддерживающих HPET, то есть всех сколько-нибудь устаревших ПК и ОС (для win32 начиная только с Windows Vista, требуется включение опции BIOS «HPET Support»), где используется системный таймер (его точность не чаще OsTimeSlice — 10-15ms). Для win 2k и младше используется параметр /usepmtimer в boot.ini. см. NTLDR)
  • Скорость, обычно в десятки-сотни тысяч раз быстрее (в зависимости от множества факторов). Это очень важно, например, при измерении времени исполнения интенсивных операций, таких, как вызовы функций.
  • Не требует переключения в Ring0 в большинстве систем (если команда разрешена в данной ОС).

Проблемы использования[править | править исходный текст]

  • QueryPerformanceCounter может работать неправильно в Windows Server 2000, Windows Server 2003 и Windows XP.[7]
  • При создании коммерческих программ RDTSC потенциально может быть недоступна на конечной системе, поэтому должны быть предусмотрены режимы функционирования, не требующие данной команды.
  • Точные замеры:
    • невозможность получения точного значения из-за влияния кэшей процессора при обращении к памяти, да и просто исполнение команд требует предвыборки оттуда же. Традиционно решается многократным измерением фрагмента программы.
    • возможность переупорядочивания с замеряемыми командами на Out-of-Order процессорах. Решается добавлением сериализующих команд (например, CLD/CLC для Pentium моделей P5, P54[8] или cpuid для более новых) или использованием rdtscp.
  • возможная недоступность:
    • на старых процессорах (например, 80486) либо на процессорах, реализующих архитектуру x86 не в полном объеме.
    • инструкция может быть потенциально превращена в привилегированную (операционной системой установлен 3-й бит в управляющем регистре CR4), и её использование приведет к генерации исключения в программе.
  • режим энергосбережения:
    • В современных процессорах Intel счетчик TSC не зависит от использования технологий энергосбережения и увеличивается на 1 каждый такт, вне зависимости от того, работал ли процессор или находился в состоянии сна.
    • Существует также вопрос периодического динамического автоснижения и автоповышения частот технологиями Cool&Quiet и аналогов от других производителей процессоров, а также технологий псевдоразгона — Intel® Turbo Boost Technology. Для не сильно критических к таймингам систем это обычно обходится периодическим пересчётом частоты, например, в играх (особенно в однопользовательском режиме) и подобных 3D-эмуляторах, а также в реалтайм-счётчиках времени исполнения тех или иных блоков программы.
  • псевдовсплески в системах с многопоточным ядром (ядрами) или HyperThreading для случаев очень точных замеров блока команд из-за неучёта загруженности общих процессорных блоков а также кэша и памяти, что верно и для просто мультипроцессорных систем. Простейшее решение — отключить на время тестов HyperThreading в BIOS, при наличии более одного ядра — в BIOS или программно в ОС ограничить число ядер до одного (для win32 — параметр /numproc=1 в c:\boot.ini).
  • рассинхронизация в многоядерных системах:
    • При инициализации процессоров. В некоторых реализациях счетчики TSC могут иметь синхронные значения на многоядерной системе, в том числе временно, что может ввести программиста в заблуждение о таком же поведение и на других системах.
    • Рассинхронизация самих счётчиков в первых многоядерных системах из-за неверно-синхронной инициализации процессоров некоторыми BIOS. Исправляется обновлением BIOS или обновлением операционной системы. Существуют программы для проверки на наличие этой ошибки.[9]
    • Порча оперируемого программой значения счётчика в многоядерных системах, когда частота разная или программа не рассчитана на исполнение на многопроцессорной системе, при периодическом автопереключении потока или процесса с одного процессора на другой системой.
    • Основной проблемой для применения инструкции rdtsc на многоядерных системах (особенно критично это в случае, когда она используется для измерения временных интервалов) является то, что значения счетчика команд на разных процессорных ядрах могут быть разными (не синхронизированными).
    • Для того, чтобы на прикладном уровне можно было отследить факт смены ядра на многоядерных системах, введена инструкция rdtscp, которая, работая аналогично rdtsc, возвращает в регистре ecx дополнительно id процессорного ядра.

Для решения многих проблем рекомендуется фиксирование потока на конкретном процессоре (cpu affinity) и отключение технологий автоматического изменения частоты (в целях энергосбережения или повышения производительности).

Рекомендации по замерам[править | править исходный текст]

Если возможно [временно переключить разрабатываемую программу], то лучший режим для однозначности результата, при сколько то длительных замерах: однопоточный (или же поочерёдно-[раз]блокирующий многопоточный, суммарно с одним активным потоком) с cpu-affinity-заблокированным исполнением на одном процессоре, но исполняющийся на *многопроцессном ПК* - для уменьшения влияния ОС. И с выгружжеными максимумом фоновых программ, системных сервисов и по возможности даже драйверов, особенно сети - если она не тестируется. Незабыв про повышенный приоритет процесса.

Примечания[править | править исходный текст]

  1. Сериализующий вариант инструкции rdtsc, также читающий IA32_TSC_AUX MSR, в котором часто хранится номер ядра.
  2. rdtscp
  3. x86/x64 Instruction Set Reference
  4. Windows Anti-Debug Reference | Symantec Connect Community
  5. Слайд 58 Timing Based Anti-Debugging
  6. Tom St. Denis, Simon Johnson, Cryptography for developers.
  7. Programs that use the QueryPerformanceCounter function may perform poorly in Windows Server 2000, in Windows Server 2003, and in Windows XP
  8. How to optimize for the Pentium family of microprocessors // 1996—2000 by Agner Fog. Chapter «30. Testing speed», перевод
  9. ICE Affinity

Ссылки[править | править исходный текст]