Я портирую игру, которая изначально была написана для Win32 API, в Linux (ну, портирую OS X порта Win32 в Linux).
Я реализовал QueryPerformanceCounter
, указав uSeconds с момента запуска процесса:
BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
gettimeofday(¤tTimeVal, NULL);
performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
performanceCount->QuadPart *= (1000 * 1000);
performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);
return true;
}
Это, в сочетании с QueryPerformanceFrequency()
постоянной частотой 1000000, хорошо работает на моей машине , давая мне 64-битную переменную, которая содержится uSeconds
с момента запуска программы.
Так это портативный? Я не хочу обнаруживать, что он работает иначе, если ядро было скомпилировано определенным образом или что-то в этом роде. Однако меня устраивает то, что он не переносится на что-то другое, кроме Linux.
Высокое разрешение, низкие затраты времени для процессоров Intel
Если вы используете оборудование Intel, вот как прочитать счетчик команд процессора в реальном времени. Он сообщит вам количество циклов процессора, выполненных с момента загрузки процессора. Это, вероятно, самый точный счетчик, который вы можете получить для измерения производительности.
Обратите внимание, что это количество циклов процессора. В linux вы можете получить скорость процессора из / proc / cpuinfo и разделить, чтобы получить количество секунд. Преобразование этого в двойное очень удобно.
Когда я запускаю это на своей коробке, я получаю
Вот руководство разработчика Intel, в котором содержится множество подробностей.
источник
CPUID
снова после первойRDTSC
инструкции и перед выполнением тестируемого кода? В противном случае, что помешает выполнению тестируемого кода до / параллельно с первымRDTSC
и, следовательно, недопредставленного вRDTSC
дельте?@ Бернард:
Хороший вопрос ... Думаю, код в порядке. С практической точки зрения, мы используем его в моей компании каждый день, и мы работаем на довольно большом количестве компьютеров, начиная с 2-8 ядер. Конечно, YMMV и т. Д., Но это кажется надежным и малозатратным (потому что он не переключает контекст в системное пространство) методом синхронизации.
Обычно это работает:
Конкретные примечания:
выполнение вне очереди может привести к неверным результатам, поэтому мы выполняем инструкцию cpuid, которая помимо предоставления вам некоторой информации о процессоре, также синхронизирует выполнение любой команды вне очереди.
Большинство ОС синхронизируют счетчики на процессорах при запуске, поэтому ответ будет правильным с точностью до пары наносекунд.
Комментарий о гибернации, вероятно, верен, но на практике вы, вероятно, не заботитесь о времени перехода через границы спящего режима.
относительно скорости: более новые процессоры Intel компенсируют изменения скорости и возвращают скорректированный счетчик. Я быстро просмотрел некоторые коробки в нашей сети и обнаружил только одну коробку, на которой этого не было: Pentium 3, на котором запущен какой-то старый сервер базы данных. (это ящики Linux, поэтому я проверил: grep constant_tsc / proc / cpuinfo)
Я не уверен насчет процессоров AMD, мы в первую очередь магазин Intel, хотя я знаю, что некоторые из наших системных гуру низкого уровня проводили оценку AMD.
Надеюсь, это удовлетворит ваше любопытство, это интересная и (ИМХО) недостаточно изученная область программирования. Вы знаете, когда Джефф и Джоэл говорили о том, должен ли программист знать C? Я кричал им: «Эй, забудьте про эти высокоуровневые C ... ассемблер - это то, что вам следует изучить, если вы хотите знать, что делает компьютер!»
источник
Вас может заинтересовать FAQ по Linux для
clock_gettime(CLOCK_REALTIME)
источник
Wine на самом деле использует gettimeofday () для реализации QueryPerformanceCounter () и, как известно, заставляет многие игры для Windows работать на Linux и Mac.
Запускает http://source.winehq.org/source/dlls/kernel32/cpu.c#L312
ведет к http://source.winehq.org/source/dlls/ntdll/time.c#L448
источник
Структура данных определяется как имеющая микросекунды в качестве единицы измерения, но это не означает, что часы или операционная система действительно способны измерять это точно.
Как предполагали другие люди,
gettimeofday()
это плохо, потому что установка времени может вызвать смещение часов и сбить ваши вычисления.clock_gettime(CLOCK_MONOTONIC)
это то, что вы хотите, и онclock_getres()
покажет вам точность ваших часов.источник
Я получил этот ответ от High Resolution Time Measurement and Timers, Part I
источник
В этом ответе упоминаются проблемы с настройкой часов. И ваши проблемы с гарантией тиков, и проблемы с корректировкой времени решаются в C ++ 11 с помощью
<chrono>
библиотеки.std::chrono::steady_clock
Гарантируется, что часы не будут регулироваться, и, кроме того, они будут двигаться с постоянной скоростью относительно реального времени, поэтому такие технологии, как SpeedStep, не должны влиять на него.Вы можете получить типизированные единицы, преобразовав в одну из
std::chrono::duration
специализаций, напримерstd::chrono::microseconds
. С этим типом нет двусмысленности относительно единиц, используемых значением тика. Однако имейте в виду, что часы не обязательно имеют это разрешение. Вы можете преобразовать продолжительность в аттосекунды, даже не имея точных часов.источник
Исходя из моего опыта и того, что я читал в Интернете, ответ - «Нет», это не гарантируется. Это зависит от скорости процессора, операционной системы, версии Linux и т. Д.
источник
Чтение RDTSC ненадежно в системах SMP, так как каждый ЦП поддерживает свой собственный счетчик, и синхронизация каждого счетчика с другим ЦП не гарантируется.
Я могу предложить попробовать
clock_gettime(CLOCK_REALTIME)
. В руководстве по posix указано, что это должно быть реализовано во всех совместимых системах. Он может обеспечивать счетчик наносекунд, но вы, вероятно, захотите проверитьclock_getres(CLOCK_REALTIME)
свою систему, чтобы узнать фактическое разрешение.источник
clock_getres(CLOCK_REALTIME)
не даст реального разрешения. Он всегда возвращает «1 нс» (одну наносекунду), когда доступны таймеры, проверьтеinclude/linux/hrtimer.h
файлdefine HIGH_RES_NSEC 1
(подробнее на stackoverflow.com/a/23044075/196561 )