Пока ваш поток остается на том же ядре ЦП, инструкция RDTSC будет возвращать все большее число, пока не обернется. Для процессора с частотой 2 ГГц это происходит через 292 года, поэтому это не является реальной проблемой. Вы, вероятно, не увидите этого. Если вы собираетесь прожить так долго, убедитесь, что ваш компьютер перезагружается, скажем, каждые 50 лет.
Проблема с RDTSC заключается в том, что у вас нет гарантии, что он запускается в один и тот же момент времени на всех ядрах устаревшего многоядерного ЦП, и нет гарантии, что он запускается в одно и то же время на всех процессорах устаревшего мультипроцессора. Плата -CPU.
Современные системы обычно не имеют таких проблем, но проблему также можно обойти на старых системах, установив привязку потока, чтобы он работал только на одном процессоре. Это не очень хорошо для производительности приложения, поэтому обычно не следует этого делать, но для измерения тиков это просто прекрасно.
(Другая «проблема» заключается в том, что многие люди используют RDTSC для измерения времени, которое не , что он делает, но вы написали, что хотите, чтобы циклы ЦП, так что все в порядке. Если вы * * * * * * * Используйте измерение RDTSC для измерения времени, у вас могут возникнуть сюрпризы, когда энергосбережение или гиперскорость или что-то еще, называемое множеством методов изменения частоты. На самом деле, системный вызов clock_gettime
на удивление хорош в Linux.)
Я бы просто написал rdtsc
внутри оператора asm
, который прекрасно работает для меня и более читабелен, чем какой-то неясный шестнадцатеричный код. Предполагая, что это правильный шестнадцатеричный код (и, поскольку он не дает сбоя и не возвращает постоянно увеличивающееся число, кажется, что это так), ваш код хорош.
Если вы хотите измерить количество тактов, которое занимает фрагмент кода, вам нужна отметка разница , вам просто нужно вычесть два значения постоянно увеличивающегося счетчика. Что-то вроде uint64_t t0 = rdtsc(); ... uint64_t t1 = rdtsc() - t0;
Обратите внимание, что если необходимы очень точные измерения, изолированные от окружающего кода, вам необходимо выполнить сериализацию, то есть остановить конвейер, перед вызовом rdtsc
(или использовать rdtscp
, который поддерживается только на новых процессорах). Одна команда сериализации, которую можно использовать на каждом уровне привилегий, - cpuid
.
В ответ на дополнительный вопрос в комментарии:
TSC начинается с нуля при включении компьютера (и BIOS сбрасывает все счетчики на всех процессорах на одно и то же значение, хотя некоторые BIOS несколько лет назад не делали этого надежно).
Таким образом, с точки зрения вашей программы, счетчик запускается «какое-то неизвестное время в прошлом», и он всегда увеличивается с каждым тактом, который видит процессор. Поэтому, если вы выполните инструкцию, возвращающую этот счетчик сейчас и позже, в другом процессе, он вернет большее значение (если процессор не был приостановлен или выключен между ними). Различные прогоны одной и той же программы получают большее количество, потому что счетчик продолжает расти. Всегда.
Теперь clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
- это другое дело. Это процессорное время, которое ОС предоставила процессу. Он начинается с нуля, когда начинается ваш процесс. Новый процесс также начинается с нуля. Таким образом, два процесса, идущие друг за другом, получат очень похожие или идентичные числа, а не растущие.
clock_gettime(CLOCK_MONOTONIC_RAW)
ближе к тому, как работает RDTSC (и на некоторых старых системах реализовано с ним). Возвращает значение, которое постоянно увеличивается. В настоящее время это, как правило, HPET. Однако это действительно время , а не тиков . Если ваш компьютер переходит в состояние низкого энергопотребления (например, работает на 1/2 нормальной частоты), он будет все еще двигаться с той же скоростью.