Временные метки разрешения на микросекунду в Windows
Как получить временные метки разрешения в микросекундах в Windows?
Я использую что-то лучше, чем QueryPerformanceCounter
и QueryPerformanceFrequency
(это может дать вам только время с момента загрузки и не обязательно точное, если они вызываются в разных потоках, то есть QueryPerformanceCounter
может возвращать разные результаты на разных процессорах. Есть также некоторые процессоры, которые регулируют свою частоту энергосбережения, что, по-видимому, не всегда отражается в результатах QueryPerformanceFrequency
.)
Существует Внедрить постоянное обновление, поставщик времени с высоким разрешением для Windows, но, похоже, он не прочен. Когда вопрос о микросекундах выглядит великолепно, но он больше не доступен для скачивания.
Другим ресурсом является Получение точных временных меток в Windows XP, но для этого требуется несколько шагов, выполнение вспомогательной программы плюс некоторые элементы инициализации, Я не уверен, что он работает на нескольких процессорах.
Я также посмотрел статью Википедии Time Stamp Counter, которая интересна, но не так полезна.
Если ответ просто делает это с BSD или Linux, это намного проще и прекрасно, но я хотел бы подтвердить это и получить некоторое объяснение, почему это так сложно в Windows и так легко в Linux и BSD. Это то же самое прекрасное оборудование...
Ответы
Ответ 1
Я считаю, что это по-прежнему полезно: Внутренние системы: рекомендации по предоставлению поддержки мультимедийного таймера.
Он хорошо объясняет различные доступные таймеры и их ограничения. Возможно, ваш архенизм будет не столько разрешением, сколько латентностью.
QueryPerformanceCounter не всегда будет работать со скоростью процессора. Фактически, он может попытаться избежать RDTSC, особенно в многопроцессорных (многоядерных) системах: он будет использовать HPET в Windows и Vista, а затем, если он доступен, или таймер ACPI/PM.
В моей системе (Windows 7 x64, двухъядерный процессор AMD) таймер работает на частоте 14.31818 МГц.
То же самое верно для более ранних систем:
По умолчанию Windows Server 2003 с пакетом обновления 2 (SP2) использует таймер PM для всех многопроцессорных APIC или ACPI HAL, если процесс проверки не определяет, поддерживает ли BIOS поддержку APIC или ACPI HAL. "
Проблема в том, когда проверка завершилась неудачно. Это просто означает, что ваш компьютер /BIOS поврежден. Затем вы можете либо исправить свой BIOS (рекомендуется), либо, по крайней мере, переключиться на таймер ACPI (/usepmtimer) на данный момент.
Это легко из С# - без P/Invoke - чтобы проверить поддержку таймера с высоким разрешением с помощью Stopwatch.IsHighResolution
, а затем загляните в Stopwatch.Frequency
. Он сделает внутренний вызов QueryPerformanceCounter внутренним.
Также подумайте, что если таймеры будут разбиты, вся система будет опустошена и вообще будет вести себя странно, сообщать об отрицательном истекшем времени, замедлении и т.д. - не только ваше приложение.
Это означает, что вы действительно можете положиться на QueryPerformanceCounter.
... и вопреки распространенному мнению, QueryPerformanceFrequency()
не может измениться во время работы системы.
Изменить: поскольку в документации на QueryPerformanceCounter()
указано, что "не имеет значения, какой процессор вызывается" - и на самом деле все взлом с привязкой к потоку необходим только в случае сбоя обнаружения APIC/ACPI, и система прибегает к использованию TSC. Это курорт, который не должен произойти. Если это происходит в более старых системах, у производителя может возникнуть проблема с обновлением BIOS/драйвером. Если его нет, загрузочный переключатель /usepmtimer
все еще существует. Если это не удастся, так как система не имеет надлежащего таймера, кроме Pentium TSC, вы можете на самом деле подумать о том, чтобы возиться с привязкой к потоку - даже тогда образец, предоставленный другими в области "Содержимое Сообщества" на странице, вводящий в заблуждение, поскольку у него есть незначительные накладные расходы из-за установки сродства нитей при каждом запуске/остановке вызова, что приводит к значительным задержкам и, вероятно, уменьшает преимущества использования таймера с высоким разрешением в первую очередь.
Игровые таймеры и многоядерные процессоры - это рекомендация о том, как правильно их использовать. Пожалуйста, учтите, что сейчас уже пять лет, и в то время меньшее количество систем было полностью совместимым с ACPI/поддерживаемым - вот почему, в то время как избивая его, статья подробно рассказывает о TSC и о том, как обойти свои ограничения, сохраняя аффинный нить.
Я считаю, что сейчас довольно сложная задача - найти общий ПК с нулевой поддержкой ACPI и без использования таймера PM. Наиболее распространенным случаем является, вероятно, настройки BIOS, когда некорректная настройка ACPI (иногда, к сожалению, по умолчанию factory).
Анекдоты рассказывают, что восемь лет назад ситуация была иной в редких случаях. (Делает забавное чтение, разработчики работают над дизайном "недостатки" и избивают дизайнеров чипов. Если быть справедливым, то это может быть наоборот: -)
Ответ 2
QueryPerformanceCounter/QueryPerformanceFrequency, разрешение скорости процессора
Просто будьте осторожны с многопоточными. Каждое ядро на процессоре может иметь свой собственный счетчик.
Дополнительная информация находится в Получение точных временных меток в Windows XP.
Если вам придётся использовать этот метод:
Когда я пытался вручную записывать данные на последовательный порт (для инфракрасного передатчика), я обнаружил, что установка приоритета процесса и потока на максимальный (в реальном времени) значительно улучшила его надежность (как без ошибок), это что-то который должен был иметь разрешение около 40 кГц, если я тоже помню, поэтому он должен оставаться достаточно точным для разрешения в миллисекундах.
Ответ 3
-
Windows не является операционной системой реального времени.
-
Процессы в многозадачной ОС должны будут дать свое время другому потоку/процессу. Это дает некоторые накладные расходы на время.
-
Каждый вызов функции будет иметь накладные расходы, что дает небольшую задержку при возврате запроса.
-
Кроме того, вызывающему системному вызову потребуется ваш процесс для переключения из режима пространства пользователя в режим пространства ядра, который имеет относительно высокую задержку. Вы можете преодолеть это, запустив весь процесс в режиме ядра (например, код драйвера устройства).
-
Некоторые операционные системы, такие как Linux или BSD, но они все равно не могут поддерживать точное временное разрешение субмикросекунды (например, точность nanosleep() в Linux составляет около 1 мкс, не менее 1 мкс), за исключением того, что вы меняете ядро на какой-то конкретный планировщик, который приносит пользу вашим приложениям.
Итак, я думаю, лучше адаптировать приложение, чтобы следить за этими проблемами, например, часто повторяя частоту вашей синхронизации, и это то, что предоставляют ваши ссылки. AFAIK, самое высокое разрешение по таймеру для Windows по-прежнему является GetPerformanceCounter/Frequency() независимо от его точности. Вы можете получить лучшую точность, запустив рутинную процедуру таймера в отдельном потоке и настроив привязку потока к одному из основных процессоров и установите приоритет потока как можно более высокий.
Ответ 4
QueryPerformanceCounter - это правильное решение. Вопреки тому, что вы и некоторые люди, ответившие на вас, написали, этот вызов дает правильный ответ даже с многопроцессорными системами (если только эта система не сломана), и она обрабатывает даже изменение частоты процессора. В большинстве современных систем он получен из RDTSC, но для обработки всех этих деталей с несколькими процессорами и частотами. (Это значительно медленнее, чем RDTSC).
См. QueryPerformanceCounter
На многопроцессорном компьютере не должно иметь значения, какой процессор вызывается. Тем не менее, вы можете получить разные результаты на разных процессорах из-за ошибок в базовой системе ввода-вывода (BIOS) или слоя абстракции аппаратного обеспечения (HAL).
Ответ 5
Я не думаю, что вы найдете решение лучше, чем QueryPerformanceCounter. Стандартная методика состоит в том, чтобы настроить ваш код для улавливания и отбрасывания переходов назад и массивных выбросов, которые могут возникнуть в результате переключения потоков CPU. Если вы измеряете очень маленькие интервалы (если нет, то вам не нужна эта точность), то это не обычное явление. Просто сделайте это допустимой ошибкой, а не критической ошибкой.
В редких случаях, когда вам абсолютно необходимо быть уверенным, что это никогда не произойдет, блокировка ваших потоков путем установки маски аффинности процессора является единственным вариантом.
Ответ 6
В ответах пока есть много хорошей информации.
Если то, что вы ищете, - это простой способ получить истекшее время с 1 января 1970 года в миллисекундах или более высоком разрешении в Windows XP или более поздней версии, там очень простой кросс-платформенный пример этого в CurrentTime.cpp выпуска Apple OSS для JavaScriptCore для MacOS 10.7.5 (я не могу найти его в своих версиях 10.8+). Код, о котором я говорю, находится в функции CurrentTime()
.
Он использует стандартную методику использования QueryPerformanceCounter()
для расчета истекших разностей во времени с разрешением более высокого разрешения, а затем периодически синхронизирует его с системными часами для вычисления временной метки и учета дрейфа тактовых импульсов. Чтобы получить временные метки с более высоким разрешением, для этого требуется, чтобы вы запускали Windows XP или более позднюю версию, чтобы гарантировать успешное выполнение вызовов QueryPeformanceFrequency()
.
В нем не учитываются переключатели контекста, которые немного отбрасывают вещи (в качестве "Внедрить постоянное обновление, поставщик времени с высоким разрешением для Windows" и "Проект Timestamp Windows" , но он постоянно пересинхронизируется. Я бы не запускал с ним ракеты, но примерно в 50 строках кода это было просто реализовать и достаточно хорошо для многих целей.
Кроме того, если вы знаете, что вам гарантированно будет работать Windows 8/Windows Server 2012, вы должны просто использовать GetSystemTimePreciseAsFileTime()
, поскольку он возвращает системную дату и время с максимально возможной точностью (1 микросекунда или лучше).
Ответ 7
Я использовал класс DateTimePrecise из Проект кода.
Единственная проблема, с которой я столкнулся, заключается в том, что она дала бы сумасшедшие результаты, если бы я не назвал ее по крайней мере каждые 10 секунд - я думаю, что внутри было нечто вроде переполнения целого числа - так что у меня есть таймер, который выполняется DateTimePrecise.Now
каждые несколько секунд.
Вы также должны запустить NTP на компьютере, если хотите, чтобы время было абсолютно точным.
Удачи...
Ответ 8
Я обнаружил трудности с использованием PerformanceCounter
вместе с PerformanceCounterFrequency
, потому что данный PerformanceCounterFrequency
отклоняется от фактической частоты.
Он отклоняется на смещение, а также показывает тепловой дрейф. Более новое оборудование, похоже, имеет меньший дрейф, но смещение и смещение довольно значительны. Дрейф в несколько миллионных долей будет в значительной степени повредить точность микросекунды, так как 1 ppm составляет 1 мкс/с! Поэтому рекомендуется тщательная аппаратная калибровка при использовании PerformanceCounter
с PerformanceCounterFrequency
. Это также может быть причиной того, что "безумные результаты" наблюдаются, когда часто не вызываются определенные функции.
Я сделал несколько более подробных исследований по этому вопросу. Описание можно найти в службе разрешения времени Microsecond для Windows.