"cpuid" перед "rdtsc" - PullRequest
       70

"cpuid" перед "rdtsc"

18 голосов
/ 27 мая 2010

Иногда я сталкиваюсь с кодом, который читает TSC с инструкцией rdtsc, но вызывает cpuid прямо перед этим.

Почему звонить cpuid необходимо? Я понимаю, что это может иметь какое-то отношение к различным ядрам, имеющим значения TSC, но что точно происходит при последовательном вызове этих двух инструкций?

Ответы [ 3 ]

18 голосов
/ 27 мая 2010

Это для предотвращения неправильного исполнения.По ссылке, которая теперь исчезла из Интернета (но была случайно скопирована здесь до ее исчезновения), этот текст взят из статьи под названием «Мониторинг производительности» одного из авторов Джона Экердала:

Pentium Proи процессоры Pentium II поддерживают команды выполнения вне очереди, которые могут быть выполнены в другом порядке, как вы их запрограммировали.Это может стать источником ошибок, если не позаботиться о них.

Чтобы предотвратить это, программист должен сериализовать очередь команд.Это можно сделать, вставив команду сериализации, например инструкцию CPUID, перед командой RDTSC.

6 голосов
/ 08 июня 2012

Две причины:

  • Как говорит paxdiablo, когда CPU видит код операции CPUID, он проверяет выполнение всех предыдущих инструкций, а затем CPUID перед выполнением любых последующих инструкций. Без такой инструкции конвейер выполнения ЦП может в конечном итоге выполнить TSC раньше, чем команда (ы), которую вы хотели бы рассчитать.
  • Значительная часть машин не может синхронизировать регистры TSC по ядрам. Если вы хотите прочитать это из a рта лошади - вырубите себя в http://msdn.microsoft.com/en-us/library/ee417693%28VS.85%29.aspx. Итак, при измерении интервала между показаниями TSC, если они не взяты на том же самом ядре, у вас будет введен фактически случайный, но, возможно, постоянный (см. ниже) интервал - он может легко составлять несколько секунд (да секунд) даже вскоре после загрузки. Это эффективно отражает то, как долго BIOS работал на одном ядре, прежде чем запускать другие, плюс - если у вас есть какие-либо неприятные варианты энергосбережения - увеличение дрейфа, вызванного тем, что ядра работают на разных частотах или снова выключаются. Итак, если вы не прибили потоки, считывающие регистры TSC, к одному и тому же ядру, то вам нужно будет создать некую межъядерную дельта-таблицу и знать идентификатор ядра (который возвращается CPUID) для каждого образца TSC по порядку. чтобы компенсировать это смещение. Это еще одна причина, по которой вы можете видеть CPUID вместе с RDTSC, и действительно причина, по которой с более новой версией RDTSCP многие ОС хранят номера идентификаторов ядра в дополнительных возвращаемых данных TSC_AUX [31: 0]. (Доступный в Core i7 и Athlon 64 X2, RDTSCP является гораздо лучшим вариантом во всех отношениях - ОС обычно дает вам идентификатор ядра, как уже упоминалось, атомарный для чтения TSC, и предотвращают переупорядочение команд).
1 голос
/ 16 января 2019

CPUID выполняет сериализацию, предотвращая неправильное выполнение RDTSC.

В эти дни вы можете смело использовать LFENCE. Он задокументирован как сериализация в потоке команд (но не в памяти) на процессорах Intel, а теперь и на AMD после их обновления микрокода для Spectre.

https://hadibrais.wordpress.com/2018/05/14/the-significance-of-the-x86-lfence-instruction/ объясняет больше о LFENCE.

См. Также https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf, чтобы узнать, как использовать RDTSC P , который удерживает CPUID (или LFENCE) вне временной области:

LFENCE     ; (or CPUID) Don't start the timed region until everything above has executed
RDTSC           ; EDX:EAX = timestamp
mov  ebx, eax   ; low 32 bits of start time

   code under test

RDTSCP     ; built-in one way barrier stops it from running early
LFENCE     ; (or CPUID) still use a barrier after to prevent anything weird
sub  eax, ebx   ; low 32 bits of end-start

См. Также Получить счетчик циклов ЦП? для получения дополнительной информации о предупреждениях RDTSC, таких как constant_tsc и nonstop_tsc.

В качестве бонуса RDTSCP дает вам основной идентификатор. Вы также можете использовать RDTSCP для времени запуска, если хотите проверить миграцию ядра. Но если ваш процессор имеет функции constant_tsc, все ядра в пакете должны синхронизироваться с TSC, так что на современном x86 это обычно не требуется.

Вместо этого вы можете получить идентификатор ядра из CPUID, как указывает ответ @ Tony.

...