Comments 19
А на винде точность измерения разве не зависит от материнской платы и самой версии windows? Несколько лет назад сталкивался необходимостью замера интервалов в мкс на windows, точно замера плавала на десятки мкс, как выяснилось, для более точных замеров нужна win8 с какой версией обновления и какие то определённые мат платы
Пробовал измерять сначала функциями c#, потом win api
А на винде точность измерения разве не зависит от материнской платы и самой версии windows?
Это зависит от функции. Windows "загрубляет" дискретность ряда функций до 100ns, но если не может обеспечить и такую точность то, например, на старом 32-х битном Intel Atom Z2760@1.80GHz дискретность всех измеренных мной функций оказалась не лучше 570ns. Т.е. QueryPerformanceCounter при документированных единицах измерения 100ns смогла измерить интервал времени лишь в 5,7 раза длиннее. Такую же дискретность на этой машине выдали и все современные стандартные функции С и С++.
Многие ф-ии WinAPI (например GetSystemTime) завязаны на частоту прерывания системных часов которая по умолчанию равна 64 тикам в секунду независимо от железа, но может изменяться программно с помощью ExSetTimerResolution.
Кстати, частота прерывания системных часов может изменяться, например, музыкальным или видео плеером, что иногда приводит к неприятным сюрпризам.
Похоже, что на проверенных мной машинах с Windows инструкция CPUID выполнялась программно.
Включенный Hyper-V ?
надеюсь, кто-нибудь объяснит это в комментариях
Не зря надеялся )
Наверно, на всех машинах установлен как минимум MS Sandbox. Но для меня неожиданно, что включение Hyper-V влияет на процессы запущенные прямо на хосте, а не в VM.
IMHO с такими задержками CPUID для профилирования не годится. Но если погуглить RDTSC, то чаще всего для сериализации инструкций предлагают именно его.
Hyper V - гипервизор первого типа, так что при включении "хостовая" Windows реально бежит под ним.
А так особого смысла в сериализации не вижу. Если делать отсечки до и после более-менее тяжёлого цикла - особой разницы (в процентах от полученного значения) в измерениях не будет, если же вставлять измерение внутрь цикла - даже сама по себе rdtsc будет влиять на скорость работы и результат измерений, с сериализацией будет ещё хуже - так что получить осмысленный результат, по которому можно делать выводы о работе кода без измеряющей обвзяки, достаточно сложно.
Со временем - тут у кого на что фантазии хватит...
Под DOS, помнится, еще в 90-х года был RTC - real-time clock который "тикал" 1024 раза в секунду и мог дергать соответствующее прерывание (номер уже не вспомню за давностью лет, помню, что оно было практически не документировано и разбираться сними приходилось перерыв кучу информации).
Не так давно писал тут про Standard Time на платформе IBM i - тоже достаточно нестандартное решение... Точность 1мкс (плюс есть еще 12 "бит уникальности").
Всё таки максимальная частота таймера на IBM PC около мегагерца - https://en.wikibooks.org/wiki/X86_Assembly/Programmable_Interval_Timer
Я несколько отошел от x86 архитектуры в последние годы.
Помнится, под виндой еще со времен 3.11 был multimedia timer который как минимум миллисекунды достаточно точно считал.
Но сильно глубоко в это не вникал - просто не попадалось задач где нужно было бы точно измерять абсолютное время (или временные интервалы)
Discreteness - минимальный прирост показаний функции (очень грубо говоря это точность измерения)
Похоже на "разрешение".
clock_gettime(CLOCK_MONOTONIC_RAW) [Linux] – видимо лучший вариант для тайминга в LinuxAPI. Точность и время выполнения около 22ns.
Только если запускать нативно. В клауде, в зависимости от настроек гипервизора, ситуация может быть другой. Например на моей системе (под KVM) CLOCK_MONOTONIC
выполняется за 30 нс, а вот CLOCK_MONOTONIC_RAW
за 400 нс (делает системный вызов).
Попросил DALL-E нарисовать программиста, выбирающего секундомер. Вот результат )
Программист думает: И как я этой кучей безменов буду измерять время?
Intel SDM vol. 2 / RDTSCP:
The RDTSCP instruction is not a serializing instruction, but it does wait until all previous instructions have executed and all previous loads are globally visible.1 But it does not wait for previous stores to be globally visible, and subsequent instructions may begin execution before the read operation is performed. The following items may guide software seeking to order executions of RDTSCP:
• If software requires RDTSCP to be executed only after all previous stores are globally visible, it can execute MFENCE immediately before RDTSCP.
• If software requires RDTSCP to be executed prior to execution of any subsequent instruction (including any memory accesses), it can execute LFENCE immediately after RDTSCP.
See “Changes to Instruction Behavior in VMX Non-Root Operation” in Chapter 26 of the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3C, for more information about the behavior of this instruction in VMX non-root operation.
Речь о рекомендации использовать MFENCE
перед RDTSCP
?
Инструкция сознательно пропущена при цитировании — она довольно тяжёлая, а интерес представлял лишь запрет на out-of-order execution. Вместо неё применён LFENCE
, поскольку Intel явно рекомендует его для "executed prior to execution of any subsequent instruction".
Моя основная специализация — прикладное программирование; в ассемблере опыта немного 🙂
Публикация сделана в надежде на критику и советы от системных программистов. Буду признателен за любые комментарии!
Есть вариации рекомендаций. Можете глянуть вот это:
https://github.com/mkurnosov/tscbench (см. файл tsc_x86.h, там данные из предыдущего документа) + https://xk8.ru/files/temp/mkurnosov-rdtsc-2014.pdf
Утилита Агнера Фога: https://agner.org/optimize/#testp (но это уже дебри)
В основном всё сводится к связке xor eax,eax
+ cpuid
+ rdtsc
перед измеряемым кодом и rdtscp
+ сохранение eax/edx + xor eax,eax
+ cpuid
после. Если процессор поддерживает serialize
, думаю, xor
+cpuid
стоит заменить им.
Ну и ещё можно использовать профилировщики, Intel Architecture Code Analyzer (последняя версия 2019 года).
IACA и его "потомки" (OSACA, llvm-mca, uica) не профилировщики, а статические анализаторы - с одной стороны, они дают полную картину с точностью до работы отдельных инструкций и не подвержены погрешностям измерения, с другой - точность ограничена заложенной моделью и параметрами процессора, на железе они анализируемый код не запускают.
Так, я и не говорю, что это профилировщик. Запятая здесь — это перечисление, а не уточнение.
Краткое сравнение популярных функций измерения времени