Как получить количество циклов процессора в Win32?

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

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

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


Изменить: благодаря @Greg, который навел меня на путь к QueryPerformanceCounter, который сделал трюк.


person Lasse V. Karlsen    schedule 26.09.2008    source источник


Ответы (5)


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

person Greg Hewgill    schedule 26.09.2008

Вот интересная статья! говорит не использовать RDTSC, а вместо этого использовать < href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904" rel="nofollow noreferrer">счетчик производительности запроса.

Заключение:

Использование обычного старого 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 микросекунд) при минимальном использовании ЦП. См. код выше.

person prakash    schedule 26.09.2008
comment
Пожалуйста, избегайте timeBeginPeriod(); это влияет на общесистемный планировщик и может вызвать проблемы с энергосбережением. - person MSalters; 26.09.2008

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

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

person Seb    schedule 26.09.2008
comment
Спасибо, я собираюсь объединить только файлы, созданные на одном компьютере в один и тот же период времени, так что это сработает. Теперь мне просто нужно выяснить, что на самом деле вызывает этот метод :) - person Lasse V. Karlsen; 26.09.2008

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

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

person moonshadow    schedule 26.09.2008

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

person Ken    schedule 26.09.2008
comment
Количество тиков, кажется, увеличивается, совпадая с выходом в миллисекундах, и поэтому мне нужно что-то более точное. - person Lasse V. Karlsen; 26.09.2008