Отметки времени микросекундного разрешения в Windows - PullRequest
16 голосов
/ 10 марта 2010

Как получить метки времени с микросекундным разрешением в Windows?

Я ищу что-то лучшее, чем QueryPerformanceCounter и QueryPerformanceFrequency (они могут дать вам только истекшее время с момента загрузки и не обязательно точны, если они вызываются в разных потоках - то есть QueryPerformanceCounter может возвращать разные результаты на разных процессорах .Есть также некоторые процессоры, которые настраивают свою частоту для экономии энергии, что, очевидно, не всегда отражается в их QueryPerformanceFrequency результате.)

Существует Реализация постоянно обновляющегося поставщика времени с высоким разрешением для Windows , но он не выглядит надежным. Когда микросекунды имеют значение выглядит великолепно, но больше не доступно для загрузки.

Другим ресурсом является Получение точных временных меток под Windows XP , но для этого требуется ряд шагов, запуск вспомогательной программы и некоторые дополнительные функции инициализации, я не уверен, работает ли она на нескольких процессорах.

Я также посмотрел статью в Википедии Счетчик отметок времени , что интересно, но не так полезно.

Если ответ просто сделать это с BSD или Linux, это намного проще и это хорошо, но я хотел бы подтвердить это и получить некоторое объяснение, почему это так сложно в Windows и так легко в Linux и BSD . Это то же самое прекрасное оборудование ...

Ответы [ 8 ]

19 голосов
/ 16 марта 2010

Я считаю, что это все еще полезно: Внутренние компоненты системы: рекомендации по обеспечению поддержки мультимедийного таймера .

Он хорошо объясняет различные доступные таймеры и их ограничения. Возможно, ваше заклятое враг будет не столько разрешением, сколько задержкой.

QueryPerformanceCounter не всегда будет работать на скорости процессора. Фактически, он может попытаться избежать RDTSC , особенно в многопроцессорных (/ многоядерных) системах: он будет использовать HPET в Windows Vista и более поздних версиях, если она доступна или таймер ACPI / PM . В моей системе (Windows 7 x64, двухъядерный AMD) таймер работает на частоте 14,31818 МГц.

То же самое верно для более ранних систем:

По умолчанию Windows Server 2003 с пакетом обновления 2 (SP2) использует таймер PM для всех мультипроцессорных HAL APIC или ACPI, если только процесс проверки для определения того, поддерживает ли BIOS APIC или HAL ACPI, не проходит. "

Проблема в том, что проверка не удалась. Это просто означает, что ваш компьютер / BIOS поврежден. Затем вы можете либо исправить свой BIOS (рекомендуется), либо хотя бы переключиться на использование таймера ACPI (/ usepmtimer) на данный момент.

В C # легко - без P / Invoke - проверить поддержку таймера высокого разрешения с помощью Stopwatch.IsHighResolution, а затем посмотреть на Stopwatch.Frequency. Это сделает необходимый вызов QueryPerformanceCounter внутри.

Также учтите, что если таймеры сломаны, вся система будет разрушена и, в целом, будет вести себя странно, сообщая об отрицательных прошедших временах, замедляя и т. Д. - не только ваше приложение.

Это означает, что вы можете положиться на QueryPerformanceCounter.

... и вопреки распространенному мнению, QueryPerformanceFrequency() "не может измениться во время работы системы" .

Редактировать: Как указано в документации по QueryPerformanceCounter(), «не должно иметь значения, какой процессор вызывается» - и фактически весь взлом с привязкой к потоку необходим, только если обнаружение APIC / ACPI происходит сбой, и система использует TSC . Это курорт, который не должен происходить. Если это происходит в более старых системах, вероятно, имеется обновление BIOS / исправление драйвера от производителя. Если его нет, загрузочный переключатель /usepmtimer все еще там. Если и это не помогает, поскольку система не имеет надлежащего таймера, кроме Pentium TSC, вы можете рассмотреть возможность связывания с привязкой потоков - даже тогда пример, предоставленный другими в области «Содержимое сообщества» на странице, вводит в заблуждение, поскольку имеет незначительные накладные расходы из-за установки соответствия потоков при каждом вызове пуска / останова, что вносит значительную задержку и, вероятно, уменьшает преимущества использования таймера с высоким разрешением.

Игровые таймеры и многоядерные процессоры - это рекомендации по их правильному использованию. Пожалуйста, учтите, что ему сейчас пять лет, и в то время меньшее количество систем полностью поддерживало / поддерживало ACPI - вот почему при его создании в статье так подробно рассказывается о TSC и о том, как обойти это. его ограничения, сохраняя аффинный поток.

Я считаю, что в настоящее время довольно сложно найти обычный ПК с нулевой поддержкой ACPI и без таймера PM. Наиболее распространенным случаем, вероятно, являются настройки BIOS, когда поддержка ACPI установлена ​​неправильно (иногда, к сожалению, по умолчанию).

Анекдоты сообщают , что восемь лет назад ситуация была иной в редких случаях. (Читает весело, разработчики работают над «недостатками» дизайна и проектируют чип-чипы. Если быть честным, то может быть так же, и наоборот.: -)

11 голосов
/ 10 марта 2010

QueryPerformanceCounter / QueryPerformanceFrequency, скорость процессора, разрешение

Просто будьте осторожны с многопоточностью. Каждое ядро ​​процессора может иметь свой собственный счетчик.

Некоторая дополнительная информация содержится в Получение точных временных меток под Windows XP .

Если вам в конечном итоге придется прибегнуть к этому методу:

Когда я пытался вручную записать данные в последовательный порт (для инфракрасного передатчика), я обнаружил, что установка максимального значения приоритета процесса и потока (в реальном времени) значительно повысила его надежность (без ошибок), это нечто разрешение должно было составлять около 40 кГц, если я тоже помню, поэтому оно должно оставаться достаточно точным для разрешения в миллисекундах.

6 голосов
/ 14 марта 2010

QueryPerformanceCounter - правильное решение для этого. Вопреки тому, что вы и некоторые люди, отвечающие вам, написали, этот вызов дает правильный ответ даже с многопроцессорными системами (если рассматриваемая система не работает), и он обрабатывает даже изменение частоты процессора. В большинстве современных систем он получен из RDTSC , но обрабатывает все эти многопроцессорные и частотные изменения для вас. (Хотя это значительно медленнее, чем RDTSC).

См. QueryPerformanceCounter

На многопроцессорном компьютере не должно иметь значения, какой процессор называется. Однако вы можете получить разные результаты на разных процессорах из-за ошибок в базовой системе ввода / вывода (BIOS) или на уровне аппаратной абстракции (HAL).

6 голосов
/ 10 марта 2010
  1. Windows не является ОС реального времени .

  2. Процессы в многозадачной ОС должны отдавать свое время другому потоку / процессу. Это дает некоторые накладные расходы на время.

  3. Каждый вызов функции будет иметь накладные расходы, что дает небольшую задержку при возврате запроса.

  4. Кроме того, вызывающему системному вызову потребуется, чтобы ваш процесс переключился из режима пространства пользователя в режим пространства ядра, который имеет относительно высокую задержку. Вы можете преодолеть это, запустив весь процесс в режиме ядра (например, код драйвера устройства).

  5. Некоторые ОС, такие как Linux или BSD , лучше, но они все еще не могут поддерживать точное временное разрешение до микросекунды (например, точность nanosleep () в Linux составляет около 1 мс (не менее 1 мс), за исключением того, что вы устанавливаете ядро ​​на какой-то определенный планировщик, который дает преимущества вашему приложению.

Так что я думаю, что лучше адаптировать ваше приложение к таким проблемам, как, например, частая перекалибровка вашей процедуры синхронизации, что и обеспечивают ваши ссылки. AFAIK , самое высокое разрешение таймера для Windows по-прежнему равно GetPerformanceCounter / Frequency () независимо от его точности. Вы можете добиться большей точности, запустив подпрограмму таймера в отдельном потоке, установив привязку этого потока к одному базовому процессору и установив приоритет потока наивысшего значения, которое вы можете получить.

5 голосов
/ 10 марта 2010

Не думаю, что вы найдете решение лучше, чем QueryPerformanceCounter. Стандартный метод состоит в том, чтобы настроить ваш код так, чтобы он ловил и отбрасывал скачки времени назад и массивные выбросы, которые могут возникнуть в результате переключения потоков CPU . Если вы измеряете очень малые интервалы (если нет, то вам не нужна эта точность), то это не обычное явление. Просто сделайте это допустимой ошибкой, а не критической ошибкой.

В тех редких случаях, когда вам абсолютно необходимо быть уверенным в том, что этого никогда не произойдет, единственной опцией является блокировка потоков с помощью маски соответствия процессоров.

3 голосов
/ 23 мая 2014

В ответах много полезной информации.

Если то, что вы ищете, представляет собой простой способ получить истекшее время с 1 января 1970 года в миллисекундах или с более высоким разрешением в Windows XP или более поздней версии, есть очень простой кроссплатформенный пример этого в CurrentTime .cpp выпуска AppleCSS для JavaScriptCore для MacOS 10.7.5 (кажется, я не могу найти его в их версиях 10.8+). Код, на который я ссылаюсь, находится в функции CurrentTime().

В нем используется стандартная методика использования QueryPerformanceCounter() для расчета истекшей разницы во времени с разрешением, превышающим миллисекунду, а затем периодическая синхронизация его с системными часами для вычисления метки времени и учета смещения часов. Для получения меток времени с более высоким разрешением требуется, чтобы вы работали под управлением Windows XP или более поздней версии, поэтому вызовы на QueryPeformanceFrequency() гарантированно будут успешными.

Он не учитывает переключатели контекста, слегка отбрасывающие вещи (как "Реализация постоянно обновляющегося поставщика времени с высоким разрешением для Windows" и "Проект отметки времени Windows" делать), но он постоянно повторяет синхронизацию. Я бы не стал запускать ракету с ним, но примерно с 50 строками кода он прост в реализации и достаточно хорош для многих целей.

Кроме того, если вы знаете, что вы гарантированно используете Windows 8 / Windows Server 2012, вам следует просто использовать GetSystemTimePreciseAsFileTime(), поскольку он возвращает системную дату и время с максимально возможной точностью ( 1 микросекунда или лучше).

1 голос
/ 07 июля 2012

Я обнаружил трудности при использовании PerformanceCounter вместе с PerformanceCounterFrequency, потому что данное PerformanceCounterFrequency отклоняется от фактической частоты.

Отклоняется от смещения, а также показывает тепловой дрейф. Новые аппаратные средства, кажется, имеют меньший дрейф, но дрейф и смещение довольно значительны. Дрейф в несколько частей на миллион уже значительно ухудшит микросекундную точность, так как 1 часть на миллион составляет 1 мкс / с! Поэтому при использовании PerformanceCounter с PerformanceCounterFrequency настоятельно рекомендуется проводить тщательную калибровку для конкретного оборудования. Это также может быть причиной того, что "сумасшедшие результаты" наблюдаются, когда некоторые функции часто не вызывают.

Я провел несколько более подробных исследований по этому вопросу. Описание можно найти в Службах времени с микросекундным разрешением для Windows .

1 голос
/ 11 марта 2010

Я использовал класс DateTimePrecise из Проект кода .

Единственная проблема, с которой я столкнулся, это то, что это дало бы сумасшедшие результаты, если бы я не вызывал его хотя бы каждые 10 секунд - я думаю, что было внутреннее целочисленное переполнение - поэтому у меня есть таймер, который выполняет DateTimePrecise.Now каждые несколько секунд.

Вы также должны запустить NTP на машине, если вы хотите, чтобы время было точным.

Удачи ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...