2014-12-31 1 views
2

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

Первоначально я использовал QueryPerformanceCounter, несмотря на то, что это высокое разрешение, оно оказалось довольно медленно. В соответствии с вопросом What happens when QueryPerformanceCounter is called? у меня также наблюдалось заметное замедление, когда я использую QPC в профилировщике, но, вероятно, не так уж плохо, что составляет 1-2 мс. Если я заменил его GetTickCount Я не заметил замедление, но эта функция неточна для профилирования.

Упомянутый вопрос упоминается о масках близости. Я попытался использовать SetProcessAffinityMask(GetCurrentProcess(), 1), чтобы связать его, но он не улучшает производительность вообще.

Я не знаю, имеет значение это или нет, но до сих пор я тестировал его на Windows, который работает в VirtualBox на хосте Linux. Это может быть проблема?

+1

[Эта статья] (http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408.aspx) выглядит интересным –

+0

О, и да, виртуализация может быть проблемой для кода, который использует низкую такие как ... таймеры, которые используют регистры процессора, например ;-) –

+2

Инструкция RDTSC снова используется для современных процессоров. Также используется QueryThreadCycleTime(). Имейте в виду, что преобразование «циклов» во времени не является прямым. –

ответ

0

Самых высокие таймеры разрешения Я в курсе на Windows, являются мультимедийными таймеры доступны через winmm.dll

Вот класс я валяюсь для моего собственного тестирования перфорации нужно - дать «эр водоворота:

public class HighResTimer 
{ 
    private delegate void TimerEventHandler(int id, int msg, IntPtr user, int dw1, int dw2); 

    private const int TIME_PERIODIC = 1; 
    private const int EVENT_TYPE = TIME_PERIODIC; 

    [System.Runtime.InteropServices.DllImport("winmm.dll")] 
    private static extern int timeSetEvent(int delay, int resolution, TimerEventHandler handler, IntPtr user, int eventType); 
    [System.Runtime.InteropServices.DllImport("winmm.dll")] 
    private static extern int timeKillEvent(int id); 
    [System.Runtime.InteropServices.DllImport("winmm.dll")] 
    private static extern int timeBeginPeriod(int msec); 
    [System.Runtime.InteropServices.DllImport("winmm.dll")] 
    private static extern int timeEndPeriod(int msec); 

    private int _timerId; 
    private TimerEventHandler _handler = delegate {}; 

    public event EventHandler OnTick; 

    public HighResTimer(int delayInMs) 
    { 
     timeBeginPeriod(1); 
     _handler = new TimerEventHandler(timerElapsed); 
     _timerId = timeSetEvent(delayInMs, 0, _handler, IntPtr.Zero, EVENT_TYPE); 
    } 

    public void Stop() 
    { 
     int res = timeKillEvent(_timerId); 
     timeEndPeriod(1); 
     _timerId = 0; 
    } 

    private void timerElapsed(int id, int msg, IntPtr user, int dw1, int dw2) 
    { 
     OnTick(this, new EventArgs()); 
    } 
} 
+3

Просто имейте в виду, что мультимедийный таймер работает в своем потоке, и есть [ограничения на то, что вы можете использовать в обратном вызове таймера] (http://msdn.microsoft.com/en-us/library/dd757631 .aspx). При этом 'timeSetEvent()' был заменен на ['CreateTimerQueueTimer()'] (http://msdn.microsoft.com/en-us/library/ms682485.aspx). –

+0

Таймеры пула потоков, таймеры очереди таймеров и ожидаемый таймер имеют одинаковое разрешение в миллисекундах, как мультимедийные таймеры. Как отмечалось в предыдущем комментарии, вы должны использовать один из них, а не мультимедийные таймеры, которые считаются устаревшими в течение нескольких лет. Что еще более важно, ваш таймер дает в лучшем случае разрешение 1 мс. 'QueryPerformanceCounter' может обеспечить близкое к * micro * второе разрешение. Конечно, это не периодический таймер, но ОП использует его для подсчета прошедшего времени, а не для выполнения кода на периодической основе. –

+0

Знал о устаревшем статусе 'winmm', не знал об альтернативах - приветствия @JimMischel @RemyLebeau – JerKimball

0

Закончено с использованием инструкции RDTSC напрямую. Так что я написал обертку для него в НКУ:

static inline unsigned long long rdtsc(void) 
{ 
    unsigned hi, lo; 
    asm volatile ("rdtsc" : "=a"(lo), "=d"(hi)); 
    return ((unsigned long long)lo)|(((unsigned long long)hi)<<32); 
} 

Нет замедлений и, видимо, не имеют достаточно высокое разрешение, чем QueryPerformanceCounter.

Код на основе this answer.

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

  • Нет связанных вопросов^_^