Większa niż 1ms rozdzielczość odmierzania czasu.

0

Czy istnieje licznik czasu jeszcze lepszej precyzji od funkcji clock(); bo ten liczy sekundę jako 1000 jednostek a chciałbym np. w milionach 1 000 000. Poniższy kod jest z ksiązki opengl programowanie opengl jak to wyeksportować:

/****************************************************************************
 HiResTimer.h
 
 Klasa obudowuj╣ca licznik czasu wysokiej rozdzielczoťci. 
 Nie mo┐e byŠ u┐ywana, jeťli licznik taki nie jest dostŕpny.
  
 Autor   :   Dave Astle
 Data     :   2/1/2001

 Opracowano dla potrzeb ksi╣┐ki "Programowanie gier w OpenGL"
*****************************************************************************/

#ifndef __TIMER_H_INCLUDED__
#define __TIMER_H_INCLUDED__

#include <windows.h>


class CHiResTimer
{
public:
  CHiResTimer() {}
  ~CHiResTimer() {}

/*****************************************************************************
 Init()

 Jeťli dostepny jest licznik czasu o du┐ej dok│adnoťci, to funkcja Init()
 zapamiŕtuje jego rozdzielczoťŠ i zwraca wartoťŠ true. 
 W przeciwnym razie zwraca wartoťŠ false i wtedy licznik nie mo┐e byŠ u┐ywany.
*****************************************************************************/
bool Init()
{
  if (!QueryPerformanceFrequency(&m_ticksPerSecond))
  {
    // system nie posiada licznika czasu o du┐ej dok│adnoťci
    return false;
  }
  else
  {
    QueryPerformanceCounter(&m_startTime);
    return true;
  }
} // Init()


float GetElapsedSeconds(unsigned long elapsedFrames = 1)
{
  static LARGE_INTEGER s_lastTime = m_startTime;
  LARGE_INTEGER currentTime;

  QueryPerformanceCounter(&currentTime);

  float seconds =  ((float)currentTime.QuadPart - (float)s_lastTime.QuadPart) / (float)m_ticksPerSecond.QuadPart;

  // "zeruje" licznik czasu
  s_lastTime = currentTime;

  return seconds;
} // GetElapsedSeconds()


/***************************************************************************
 GetFPS()

 Zwraca ťredni╣ liczbŕ klatek w okresie czasu elapsedFrames 
 (domyťlnie rˇwnym 1). Jeťli metoda nie jest wywo│ywana podczas tworzenia 
 ka┐dej ramki, to nale┐y samemu zliczaŠ liczbŕ ramek oraz zerowaŠ j╣ po
 wywo│aniu metody.
***************************************************************************/
float GetFPS(unsigned long elapsedFrames = 1)
{
  static LARGE_INTEGER s_lastTime = m_startTime;
  LARGE_INTEGER currentTime;

  QueryPerformanceCounter(&currentTime);

  float fps = (float)elapsedFrames * (float)m_ticksPerSecond.QuadPart / ((float)currentTime.QuadPart - (float)s_lastTime.QuadPart);

  // "zeruje" licznik czasu
  s_lastTime = currentTime;

  return fps;
} // GetFPS


/***************************************************************************
 LockFPS()

 Blokuje wykonanie programu tak, by prŕdkoťŠ tworzenia klatek nie wzros│a
 ponad wartoťŠ okreťlona przez parametr metody. Metoda ta nie zapewnie 
 utrzymania sta│ej prŕdkoťci tworzenia klatek, a jedynie zapobiega jej 
 wzrostowi ponad podan╣ wartoťŠ. Natomiast prŕdkoťŠ ta w praktyce mo┐e spaťŠ
 poni┐ej tej wartoťci. Zak│ada siŕ, ┐e metoda ta wywo│ywana jest podczas
 tworzenia ka┐dej klatki. Metoda zwraca chwilow╣ wartoťŠ prŕdkoťci tworzenie
 klatek (w klatkach na sekundŕ) <= targetFPS.
***************************************************************************/
float LockFPS(unsigned char targetFPS)
{
  if (targetFPS == 0)
    targetFPS = 1;

  static LARGE_INTEGER s_lastTime = m_startTime;
  LARGE_INTEGER currentTime;
  float   fps;

  // odczekuje w pŕtli okres czasu, by osi╣gn╣Š zadan╣ prŕdkoťŠ
  do {
    QueryPerformanceCounter(&currentTime);
    fps = (float)m_ticksPerSecond.QuadPart/((float)(currentTime.QuadPart - s_lastTime.QuadPart));
  } while (fps > (float)targetFPS);

  // "zeruje" licznik czasu
  s_lastTime = m_startTime;

  return fps;
} // LockFPS()


private:
  LARGE_INTEGER   m_startTime;
  LARGE_INTEGER   m_ticksPerSecond;
};

#endif // __TIMER_H_INCLUDED_
0

zrobiłem na podstawie tego mojego przykładu z książki ale jaki daje wynik dla funkcji QueryPerformanceFrequency juz mam do miliona dokładność jednostek 1 000 000

1

@wilkwielki: moim skromnym zdaniem zawsze lepiej było by używać funkcji ze standardu std::chrono ,
ale jak kod jest nieprzenośny albo znasz jakieś inne wymagania to funkcja z winAPI bedzie OK

4

Skoro w kodzie masz #include <windows.h> to zakładam, że docelowa platformą jest Windows.
W takim razie bariera językowa nie będzie stanowiła problemu i możesz popatrzeć na wpisy @furious programming, który to sam walczył z podobnym tematem jakiś czas temu, przy okazji robienia swojego silnika do gierki. Tutaj masz link do jego wpisu w tym temacie, jakbyś gdzieś utknął to pewnie będzie mógł pomóc/wyjaśnić:

Implementacja precyzyjnych l...

0

Nie jestem programistą, więc tak bardziej z ciekawości zadam pytanie jako laik: Czy nie da się tego rozwiązać wrzucając jakiś króciutki kod w assemblerze, np. pętlę na instrukcjach NOP i przeliczyć sobie ile trwa jedna instrukcja na danym procesorze/mikrokontrolerze?? Podejrzewam, że to nie jest rozwiązanie, ale czy używa się tego typu rozwiązań?

1

@Kamikos: zrób w kodzie milion linijek NOP i to zmierz 😄
każdy pomiar wpływa na wartość mierzoną ! np. pętla dodaje kilka instrukcji ASM
zazwyczaj nikt nie potrzebuje czasu pojedynczych instrukcji
zainteresuj się jakimś profilerem np. https://github.com/yse/easy_profiler

0

Trik jest taki że procki wspieraja bądź nie high resolution timers. samym tematem specjalnie isę nie interesowałem ale dasz radę do nich się dostać, tyle że moga być platform-specific
https://stackoverflow.com/questions/69911254/how-do-i-know-if-my-cpu-support-high-resolution-timers
https://www.intel.com/content/www/us/en/docs/programmable/683689/current/high-resolution-timer.html

BTW. można by podpatrzeć w google benchamrk jak to jest zrobione?

1

high_resolution_clock z biblioteki <chrono> pozwala na mierzenie czasu w milisekundach, mikrosekundach i nanosekundach za pomocą rzutowania duration<> . Można ten czas potem odczytać przy pomocy metody count().

include <iostream>
#include <chrono>
#include <ctime>


int main()
{
    auto start = std::chrono::high_resolution_clock::now();

    srand(time(nullptr));

    std::cout << "Draw: " << std::endl;

    for (int i = 100; i > 0; --i) {
        std::cout << rand() % 100 << ", ";
    }
    std::cout << std::endl << std::endl;

    auto stop = std::chrono::high_resolution_clock::now();

    
    std::chrono::duration<double, std::milli> Mi = stop - start;
    std::chrono::duration<double, std::micro> Us = stop - start;
    std::chrono::duration<double, std::nano> Na = stop - start;

    std::cout << "Duration Mi = " << Mi.count() << " milisecond." << std::endl;
    std::cout << "Duration Us = " << Us.count() << " microsecond." << std::endl;
    std::cout << "Duration Na = " << Na.count() << " nanosecond." << std::endl;

    return 0;
}

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.