Войти
ПрограммированиеПодсказкиОбщееОбщее

Обёртка над QPC

Автор:

Иногда, а точнее почти всегда, необходимо замерять время выполнения некоторых участков кода. Для этого есть удобное и весьма точное средство — QueryPerformanceCounter. Однако при его использовании необходимы некоторые преобразования, чтобы получить результат в секундах.

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

qpc_timer.h:

#pragma once

#include <windows.h>

class QPC_Timer
{
private:
     double            invfreq;
     LONGLONG          oldticks;
     LARGE_INTEGER     i;
public:
     QPC_Timer()
     {
          QueryPerformanceFrequency(&i);
          invfreq = 1.0 / i.QuadPart;
          QueryPerformanceCounter(&i);
          oldticks = i.QuadPart;
     }

     inline double Get()
     {
          QueryPerformanceCounter(&i);

          return (i.QuadPart - oldticks) * invfreq;
     }
     inline double Reset()
     {
          QueryPerformanceCounter(&i);
          double delta = (i.QuadPart - oldticks) * invfreq;
          oldticks = i.QuadPart;

          return delta;
     }
};

Замеры времени становятся до боли простыми:

#include <qpc_timer.h>

int main()
{
     QPC_Timer tmr;

     // Example #1
     while (true)
     {
          ... // some code

          double deltaTime = tmr.Reset();
     }

     // Example #2
     tmr.Reset();

     ... // some code

     double someCodeTiming = tmr.Get();

     // etc.
}

#C++, #Profiling

16 марта 2011

Комментарии [44]

Страницы: 1 2 3 Следующая »
#1
16:22, 16 мар 2011

Может стоит добавить получение миллисекунд?

#2
16:28, 16 мар 2011

целый класс для этого совсем не нужен

#3
16:46, 16 мар 2011

Я бы для замера скорости выполнения участков кода всё же rdtsc использовал. Плюс привязку потока к процессору.

#4
17:18, 16 мар 2011

Пару дней назад долго парился над точным таймером для Linux, вот что получил в результате, оставлю тут, может кому понадобится:

#include <ctime>

  namespace timer{

    timespec Time;
    timespec Start;

    void Reset(){
      clock_gettime(CLOCK_REALTIME,&Start);
    }

  }

  double Clock(){
    clock_gettime(CLOCK_REALTIME,&timer::Time);
    return static_cast<double>((timer::Time.tv_sec-timer::Start.tv_sec)+(timer::Time.tv_nsec-timer::Start.tv_nsec)/1000000000.0);
  }
#5
19:12, 16 мар 2011

>> Мизраэль Постоялец
>> Я бы для замера скорости выполнения участков кода всё же rdtsc использовал. Плюс привязку потока к процессору.
Скорее всего QueryPerformanceFrequency "внутри" использует rdtsc.

#6
20:05, 16 мар 2011

я себе такой таймер накидал:

#ifndef Timer_h__
#define Timer_h__


#define TIMER_QPC

#ifndef TIMER_QPC
  #define TIMER_TGT
#endif

namespace Video
{
  class Timer
  {
  private:
#ifdef TIMER_TGT
    static int refCount = 0;
    DWORD lastTime, curTime, diff;
#else
    __int64 lastTime, curTime, diff, perfFreq;
#endif
    float timeElapsed;
  public:

    Timer()
      :timeElapsed(0)
    {
      #ifdef TIMER_TGT
      if(refCount == 0)
        timeBeginPeriod(1);
      refCount++;
      #else
      QueryPerformanceFrequency((LARGE_INTEGER *)&perfFreq);
      #endif
    }
    ~Timer()
    {
      #ifdef TIMER_TGT
      refCount--;
      if(refCount == 0)
        timeEndPeriod(1);
      #endif
    }
    void Start()
    {
      #ifdef TIMER_TGT
      lastTime = timeGetTime();
      #else
      QueryPerformanceCounter((LARGE_INTEGER *)&lastTime);
      #endif

    }
    void Stop()
    {
      #ifdef TIMER_TGT
      curTime = timeGetTime();
      diff = curTime - lastTime;
      timeElapsed = 1.0d / (double)diff; //time in SECONDS
      #else
      QueryPerformanceCounter((LARGE_INTEGER *)&curTime);
      if(lastTime == 0)
        timeElapsed = 0;
      else
      {
        timeElapsed = (float)((double)(curTime - lastTime) / (double)perfFreq);
      }
      
      #endif
    }
    float getTimeElapsed()
    {
      return timeElapsed;
    }
  };
}

#endif // Timer_h__
#7
21:54, 16 мар 2011

ElWray
> Скорее всего QueryPerformanceFrequency "внутри" использует rdtsc.
Скорее всего http://en.wikipedia.org/wiki/High_Precision_Event_Timer но вообще любой высокочастотный таймер (даже GetTickCount, если ничего лучше нет)

#8
22:46, 16 мар 2011

http://www.devdoc.ru/index.php/content/view/queryPerformanceCounter.htm
Должно быть, я что-то не понимаю тут.

#9
23:23, 16 мар 2011

Там же написано, что проблемы из-за багов некоторых чипсетов (говорят, AMD славилась этим и для них был какой-то патч).

#10
23:30, 16 мар 2011

NULL_PTR
Там написано, что это неправда.
>По их мнению, счетчик тиков съезжает скачками (что видно в тестовом приложении) из-за багов (!?) в некоторых чипсетах.
>... счетчик работает неверно, потому что современные процессоры могут менять свою частоту на лету, чтобы экономить энергию. Особенно это актуально для ноутбуков.
Меня эта статья напугала в своё время.

#11
23:44, 16 мар 2011

GluKoBug
Ну это мнение какого-то левого чувака (который раскрыл заговор, не иначе!), как-то МС посолидней будет.
QPC не обязан быть завязан на такты процессора, да и тот же rdtsc как не странно, не меняет свою частоту в Core 2 Duo процессорах при смене частоты, так что тот факт, что какие-то процы/чипсеты, которые не соответствуют требованиям QPC, но при этом сообщяют системе "посмотрите, я нормальный высокочастотный таймер, положитесь на меня!!1" - это баг и проблемы кривых процов/чипсетов.

#12
23:53, 16 мар 2011

NULL_PTR
> это баг и проблемы кривых процов/чипсетов
trollface.jpg нигде в MSDN не сказано ни о каких гарантиях QPC, нет ни одного стандарта на это дело, поэтому тот кто на это полагается криворукий разработчик, не иначе.

#13
23:57, 16 мар 2011

KpeHDeJIb
Откуда жир?

QueryPerformanceFrequency Function: The frequency cannot change while the system is running.
QueryPerformanceCounter Function: On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL).

#14
10:31, 17 мар 2011

NULL_PTR
> QueryPerformanceFrequency Function: The frequency cannot change while the system is running.
Ну это про QueryPerformanceFrequency а не про сам таймер, так что не надо тут троллить.

> However
> due to bugs
Нет гарантий.

Страницы: 1 2 3 Следующая »
ПрограммированиеПодсказкиОбщееОбщее

Тема в архиве.