WinAPI Präzisionszeit



  • früher reichte für Performancemessungen die Zeit in Millisec. aus, heutzutage möchte man manchmal die Zeit in Microsec. haben. hier in diesem Beitrag soll es nicht darum gehen, ob und wozu man die Microsec. braucht, sondern wie man sie

    möglichst einfach und mit möglichst guter Mantissengenauigkeit

    berechnet. Grundlage sind die WinAPI Funktionen QueryPerformanceFrequency und QueryPerformanceCounter. dazu muß man noch wissen, daß QueryPerformanceFrequency auf älteren Systemen eine Frequenz im Bereich der Taktfrequenz liefert (also im GHz Bereich). bei neueren Systemen kommt da ein Wert im MHz Bereich, was wohl irgend einem Timer im Chipsatz entspricht (oder so ähnlich).

    ich möchte 64 Bit Integer und 64 Bit Double Arithmetik verwenden, wobei die Double Arithmetik eine Mantissengenauigkeit von etwa 53 Bit hat. 128 Bit Integer Arithmetik ist leider noch nicht so weit verbreitet, wie man es gern hätte. die Werte kommen von der WinAPI als LARGE_INTEGER, was man mit einer C++ union leicht in 64 Bit Integer umwandeln kann.

    union uLargeInteger
      {
      LARGE_INTEGER m_WinPart;
      __int64       m_MyPart;
      };
    

    bei diesem Algorithmus hier geht es um eine möglichst gute Mantissengenauigkeit, und eine erste Maßnahme ist, daß ich mir beim ersten Aufruf meiner Funktion den aktuellen Wert des PerformanceCounters merke. später subtrahiere ich vom neuen PerformanceCounter den Startwert und bekomme damit kleinere Zahlen, was bei den nachfolgenden Rechenoperationen zu einer höheren Mantissengenauigkeit führt

    static uLargeInteger uStartPerfCount;
    

    die Differenz (New PerfCount - Start PerfCount) wird mit 64 Bit Integer Arithmetik durchgeführt, und bis hier hin ist die Welt auch noch in Ordnung. wenn ich diese Differenz nun in Microsec. umrechnen möchte, brauche ich Multiplikationen und/oder Divisionen.

    bei der Multiplikation von großen Integer Zahlen kann es zu einem Überlauf kommen, d.h. am oberen Ende der Bitfolge gehen mir Mantissenbits verloren. bei der Division von etwa gleich großen Integer Zahlen erhalte ich ein sehr kleines Integer Ergebnis, d.h. am unteren Ende der Bitfolge gehen mir Mantissenbits verloren. beides ist zu vermeiden

    bei der floating point Multiplikation/Division bleiben die ca. 53 Mantissenbits in etwa erhalten, aber bei der Umrechnung von __int64 in double können unnötigerweise Mantissenbits verloren gehen. also habe ich mir überlegt

    ... denke, denke, denke ...

    ich rechne zuerst mit Integer Arithmetik ohne Verlust (Shift statt Division) auf eine Zahl in der Nähe von 1 Microsec. um, wandle das dann in einen double und multipliziere mit dem Korrekturfaktor. das ganze sieht dann etwa so aus:

    static int iResetPrecisionTime;
    static unsigned uPerfShift;
    static double   dPerfTick;
    
    __int64 QueryMicroPrecTime ()
      {
      if (iResetPrecisionTime == 0)
        {
        EnterCriticalSection (...);
    
        if (iResetPrecisionTime == 0)
          {
          iResetPrecisionTime = 1;
          QueryPerformanceFrequency (& uStartPerfCount.m_WinPart);
    
          if (uStartPerfCount.m_MyPart == 0)
            {
            uPerfShift = 0;
            dPerfTick = 0.0;
            }
          else
            {
            uPerfShift = 0;
            dPerfTick = 1e6 / uStartPerfCount.m_MyPart;
    
            while (uStartPerfCount.m_MyPart > 2000000)
              {
              uStartPerfCount.m_MyPart >>= 1;
              uPerfShift += 1;
              }
    
            dPerfTick *= (1 << uPerfShift);
            QueryPerformanceCounter (& uStartPerfCount.m_WinPart);
            }
          }
    
        LeaveCriticalSection (...);
        }
    
      if (dPerfTick == 0.0)
        return 0;
    
      uLargeInteger uPerfCount;
      QueryPerformanceCounter (& uPerfCount.m_WinPart);
      return (t_Int64) (((double)
        ((uPerfCount.m_MyPart - uStartPerfCount.m_MyPart) >> uPerfShift)) * dPerfTick);
      }
    


  • Schon mal Gedanken darüber gemacht, im welchen Verhältnis der Fehler der Zeitmessung zu dem Fehler der Berechnung stehet?



  • ...


Anmelden zum Antworten