2009-11-12 4 views
19

Я изучаю точные последствия использования QueryPerformanceCounter в нашей системе и пытаюсь понять его влияние на приложение. Я могу видеть, как запускать его на моем 4-ядерном процессоре с одним процессором, для его работы требуется около 230 нс. Когда я запускаю его на 24-ядерном 4-процессорном xeon, он занимает около 1,4 мс для запуска. Более интересно на моей машине при запуске в нескольких потоках они не влияют друг на друга. Но на машине с несколькими процессорами потоки вызывают какое-то взаимодействие, которое заставляет их блокировать друг друга. Мне интересно, есть ли общий ресурс на автобусе, который все они запрашивают? Что именно происходит, когда я вызываю QueryPerformanceCounter и что он действительно измеряет?Что происходит при вызове QueryPerformanceCounter?

+0

omfg, 1.4 ** ms **! да, теперь это хороший вопрос. в соответствии с этим: http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx он принимает 800 нс в качестве примера плохой машины. 1.4ms будет HYPER bad –

+0

Я тоже укушен этим при написании профилировщика. Там таймер запрашивается каждый раз, когда функция запускается и возвращается. Использование QueryPerformanceCounter замедляет программу до обхода. Использование GetTickCount не вызывает заметного замедления, но оно непригодно для точного профилирования ... – Calmarius

ответ

10

Windows QueryPerformanceCounter() имеет логику для определения количества процессоров и при необходимости вызывает логику синхронизации. Он пытается использовать регистр TSC, но для многопроцессорных систем этот регистр не может быть синхронизирован между процессорами (и, что более важно, может сильно варьироваться из-за интеллектуальных состояний разгона и сна).

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

Попробуйте использовать SetThreadAffinityMask(), если возможно, привязать его к конкретному процессору. В противном случае вам просто придется жить с задержкой, или вы можете попробовать другой таймер (например, взгляните на http://en.wikipedia.org/wiki/High_Precision_Event_Timer).

3

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

+0

Я не знаю, что это значительное влияние на практике и, вероятно, не измеримо, если вы не смотрите прямо на него. На 4-ядерном процессоре все равно нет замедления :) –

+0

rdtsc может сообщать о различных значениях для разных ядер и процессоров ... – Goz

+0

@Goz, в то время как это было особенно актуально для старых Opterons, новые многоядерные процессоры имеют синхронизированные регистры TSC. –

2

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

Вот небольшая статья из MSDN: http://msdn.microsoft.com/ja-jp/library/cc399059.aspx

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

Однако, как я уже говорил, это было довольно давно.

Майк

4

Я знаю, что эта нить немного старая, но я хотел бы добавить больше информации. Во-первых, я согласен с тем, что QueryPerformanceCounter может занимать больше времени на определенных машинах, но я не уверен, что причиной этого является ответ Рона. Хотя я занимался некоторыми исследованиями по этой проблеме, я нашел различные веб-страницы, в которых рассказывается о том, как QueryPerformanceCounter реализован. Например, Precision is not the same as accuracy сообщает мне, что Windows, HAL будет более конкретным, использовать другое устройство синхронизации для получения значения. Это означает, что если в окнах появится более медленное устройство синхронизации, такое как PIT, для получения значения времени потребуется больше времени. Очевидно, что использование PIT может потребовать транзакции PCI, поэтому это будет одна из причин.

Я также нашел другую статью: Как это работает: Выходы таймера в SQL Server 2008 R2 - Инвариантный TSC, дающий аналогичное описание. Фактически, в этой статье рассказывается, как SQLServer будет наилучшим образом выполнять транзакцию.

Затем я нашел дополнительную информацию о сайте VMware, потому что мне приходилось иметь дело с клиентами, которые используют виртуальные машины, и я обнаружил, что есть другие проблемы с измерением времени с помощью виртуальных машин. Для тех, кому это интересно, обратитесь к статье VMware - «Учет времени в виртуальных машинах VMware». В этой статье также рассказывается о том, как некоторые версии окон будут синхронизировать каждый TSC. Таким образом, было бы безопасно использовать QueryPerformanceCounter() в определенных ситуациях, и я думаю, что мы должны попробовать что-то вроде того, как это работает: выходы таймера в SQL Server 2008 R2 предложили найти, что может случиться, когда мы вызываем QueryPerformanceCounter()

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