2008-09-26 3 views
7

В Win32 существует ли способ получить уникальный счетчик циклов процессора или что-то подобное, что было бы однородным для нескольких процессов/языков/систем/и т. Д.Как получить количество циклов процессора в Win32?

Я создаю несколько файлов журналов, но мне нужно создать несколько лог-файлов, потому что мы размещаем среду выполнения .NET, и я бы хотел избежать вызова из одного в другое для входа в журнал. Как таковой, я думал, что я просто создаю два файла, объединим их, а затем сортирую их, чтобы получить согласованную временную шкалу, включающую перекрестные вызовы.

Однако GetTickCount не увеличивается для каждого вызова, так что это не так. Есть ли лучшее число, так что я получаю звонки в правильном порядке при сортировке?


Edit: Благодаря @Greg, что поставил меня на пути к QueryPerformanceCounter, который сделал трюк.

ответ

8

Вы можете использовать инструкцию CPU RDTSC (при условии x86). Эта инструкция дает счетчик циклов процессора, но имейте в виду, что он будет очень быстро увеличиваться до максимального значения, а затем сбросить на 0. Как упоминается в статье в Википедии, вам может быть лучше использовать функцию QueryPerformanceCounter.

12

Heres an interesting article! говорит, что не использовать RDTSC, а вместо этого использовать QueryPerformanceCounter.

Вывод:

Использование регулярных старых timeGetTime() делать времени не является надежным на многих для Windows операционных систем на основе , так как зернистость системы таймера может достигать 10-15 миллисекунд , что означает, что timeGetTime() соответствует только 10-15 миллисекунд. [Обратите внимание, что высокая степень детализации происходит на операционных системах на базе NT , таких как Windows NT, 2000 и XP. Windows 95 и 98, как правило, иметь гораздо лучше детализацию, около 1-5 мс.]

Однако, если вы звоните timeBeginPeriod(1) в начале вашей программы (и timeEndPeriod(1) на конец), timeGetTime() будет, как правило, с точностью до 1-2 миллисекунд, , и предоставит вам точную информацию о времени таймера .

Sleep() ведет себя аналогичным образом; длина времени, Sleep() на самом деле спит для идет рука об руку с зернистости timeGetTime(), поэтому после вызова timeBeginPeriod(1) раз, Sleep(1) будет на самом деле сон в течение 1-2 миллисекунд, Sleep(2) для 2-3, и так что (вместо спящего с шагом достигает 10-15 мс).

Для более точного определения времени (точность доли миллисекунды), вы вероятно, хотите, чтобы избежать использования сборки мнемонические RDTSC, потому что это трудно откалибровать; вместо этого используйте QueryPerformanceFrequency и QueryPerformanceCounter, которые являются с точностью до менее 10 микросекунд (0,00001 секунд).

Для простого времени, как timeGetTime и QueryPerformanceCounter работают хорошо, и QueryPerformanceCounter является , очевидно, более точным. Тем не менее, если вам нужно сделать какое-либо «синхронизированные паузы» (например, те, которые необходимы для фреймрейта ограничения), вы должны быть осторожны, чтобы сидеть в петле вызывающей QueryPerformanceCounter, ожидая того, чтобы достичь определенного стоимость; это будет съедать 100% вашего процессора. Вместо этого рассмотрит гибридную схему, , где вы называете Sleep (1) (не забудьте timeBeginPeriod (1) первым!) Всякий раз, когда вам нужно пройти более 1 мс времени, а затем ввести только QueryPerformanceCounter 100% -сильная петля , чтобы закончить последние < 1/1000-й из второй необходимой задержки. Это даст вам сверхточную задержку (с точностью до 10 микросекунд), с очень минимальным использованием ЦП. См. Код выше.

+3

Пожалуйста, избегайте timeBeginPeriod(); это влияет на системный планировщик и может вызвать проблемы с энергосбережением. – MSalters 2008-09-26 13:03:04

1

Используйте GetTickCount и добавьте еще один счетчик при объединении файлов журнала. Не даст вам идеальной последовательности между различными файлами журнала, но он по крайней мере сохранит все журналы из каждого файла в правильном порядке.

+2

Количество отсчетов, похоже, увеличивается, совпадающее с миллисекундным выходом, и поэтому мне нужно что-то немного более точное. – 2008-09-26 12:00:30

2

System.Diagnostics.Stopwatch.GetTimestamp() возвращает количество циклов процессора с момента времени (возможно, когда компьютер запускается, но я не уверен), и я никогда не видел, чтобы он не увеличивался между двумя вызовами.

Циклы CPU будут специфичны для каждого компьютера, поэтому вы не можете использовать его для объединения файла журнала между двумя компьютерами.

+0

Спасибо, я собираюсь объединить файлы, созданные на том же компьютере, в один и тот же таймфрейм, чтобы это сработало. Теперь мне просто нужно выяснить, что на самом деле вызывает этот метод :) – 2008-09-26 11:59:37

2

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

Используйте системное время, и если работа с фидами из нескольких систем использует источник времени NTP. Таким образом, вы можете получать надежные, последовательные показания времени; если накладные расходы слишком велики для ваших целей, используя HPET, чтобы выработать время, прошедшее с тех пор, как последнее известное достоверное считывание времени лучше, чем использование только HPET.

Смежные вопросы