• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 445
  • Last Modified:

C++ Timers / Framerates

I am trying to understand how to determine how long an operation has taken in C++

I have been experimenting with the QueryPerformanceCounter and must admit it has confused me.

I am getting values out but they seem to loop very fast- also i dont seem to be able to perform any mathmatics on the value as they are LARGE_INTEGERS (and dont seem to have a / or * operator) all attempts at converting these has failed.

If anyone can provide a basic (bare in mind my C++ is limited here) explaination of the QueryPerformanceCounter function and the LARGE_INTEGER data type, especially how this datatype can be used in other calculations it would be a great help.

It should be noted that the time needs to be in at least tens of milliseconds.

Thanks in advance for any help, any further info required feel free to ask :)
0
TLBH
Asked:
TLBH
  • 5
  • 4
1 Solution
 
jkrCommented:
'LARGE_INTEGER' basically is a union that encapsulates a 64-bit integer:

typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG  HighPart;
    };
    LONGLONG QuadPart;
} LARGE_INTEGER;
 
Members:
LowPart
Specifies the low-order 32 bits.
HighPart
Specifies the high-order 32 bits.
QuadPart
Specifies a 64-bit signed integer.

So, if you want to use mathematical operations on that, you'd always refer to the quad part, e.g.

LARGE_INTEGER li1;
LARGE_INTEGER li2;
LARGE_INTEGER li3;

li1.QuadPart = 12345678;
li2.QuadPart = 2;

li3.QuadPart = li1.QuadPart * li2.QuadPart;



0
 
jkrCommented:
BTW, a sample would be

#include "time.h"

enum { ttuUnknown, ttuHiRes, ttuClock } TimerToUse = ttuUnknown;
LARGE_INTEGER PerfFreq;      // ticks per second
int PerfFreqAdjust; // in case Freq is too big
int OverheadTicks;   // overhead  in calling timer

void DunselFunction() { return; }

void DetermineTimer()
{
   void (*pFunc)() = DunselFunction;

   // Assume the worst
   TimerToUse = ttuClock;
   if ( QueryPerformanceFrequency(&PerfFreq) )
      {
      // We can use hires timer, determine overhead
      TimerToUse = ttuHiRes;
      OverheadTicks = 200;
      for ( int i=0; i < 20; i++ )
         {
         LARGE_INTEGER b,e;
         int Ticks;
         QueryPerformanceCounter(&b);
         (*pFunc)();
         QueryPerformanceCounter(&e);
         Ticks = e.LowPart - b.LowPart;
         if ( Ticks >= 0 && Ticks < OverheadTicks )
            OverheadTicks = Ticks;
         }
      // See if Freq fits in 32 bits; if not lose some precision
      PerfFreqAdjust = 0;
      int High32 = PerfFreq.HighPart;
      while ( High32 )
         {
         High32 >>= 1;
         PerfFreqAdjust++;
         }
      }
   return;
}

double DoBench(void(*funcp)())
{
   double time;      /* Elapsed time */

   // Let any other stuff happen before we start
   MSG msg;
   PeekMessage(&msg,NULL,NULL,NULL,PM_NOREMOVE);
   Sleep(0);

   if ( TimerToUse == ttuUnknown )
      DetermineTimer();
     
   if ( TimerToUse == ttuHiRes )
      {
      LARGE_INTEGER tStart, tStop;
      LARGE_INTEGER Freq = PerfFreq;
      int Oht = OverheadTicks;
      int ReduceMag = 0;
      SetThreadPriority(GetCurrentThread(),
         THREAD_PRIORITY_TIME_CRITICAL);
      QueryPerformanceCounter(&tStart);
        (*funcp)();   //call the actual function being timed
      QueryPerformanceCounter(&tStop);
      SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
      // Results are 64 bits but we only do 32
      unsigned int High32 = tStop.HighPart - tStart.HighPart;
      while ( High32 )
         {
         High32 >>= 1;
         ReduceMag++;
         }
      if ( PerfFreqAdjust || ReduceMag )
         {
         if ( PerfFreqAdjust > ReduceMag )
            ReduceMag = PerfFreqAdjust;
         tStart.QuadPart = Int64ShrlMod32(tStart.QuadPart, ReduceMag);
         tStop.QuadPart = Int64ShrlMod32(tStop.QuadPart, ReduceMag);
         Freq.QuadPart = Int64ShrlMod32(Freq.QuadPart, ReduceMag);
         Oht >>= ReduceMag;
         }

      // Reduced numbers to 32 bits, now can do the math
      if ( Freq.LowPart == 0 )
         time = 0.0;
      else
         time = ((double)(tStop.LowPart - tStart.LowPart
            - Oht))/Freq.LowPart;
      }
   else
      {
        long stime, etime;
      SetThreadPriority(GetCurrentThread(),
          THREAD_PRIORITY_TIME_CRITICAL);
      stime = clock();
      (*funcp)();
      etime = clock();
        SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
      time = ((double)(etime - stime)) / CLOCKS_PER_SEC;
      }

  return (time);
}

Taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvc60/html/optcode.asp ("Developing Optimized Code with Microsoft Visual C++ 6.0")
0
 
TLBHAuthor Commented:
sorry about this but like i said im a bit of a newbie when it comes to C++ and got lost in that  example...

In mu understanding the QueryPerformanceCounter returns a number of ticks..
When are the ticks from?

I run this piece of code (trying a basic example to understand it) and get nothing but negative values back- how can i use this to find the number of milliseconds taken for the delaying loop?

------------------
#include <stdio.h>
#include <tchar.h>
#include <windows.h>

LARGE_INTEGER count1, count2, frequency;
int difference;

int main ()
{
  int n;
  //for (n=10; n>0; n--)
  for (int loopTimes = 0; loopTimes < 25; loopTimes++)
  {
    QueryPerformanceCounter(&count1);
    for(int i = 0; i<10000000; i++) {}
    QueryPerformanceCounter(&count2);
    QueryPerformanceFrequency(&frequency);
    difference = count1.QuadPart - count2.QuadPart;
    printf ("%d\n", difference);
  }
  system("PAUSE");
  return 0;
}
----------------------------

the quadpart worked as far as i can tell thanks for that..
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
TLBHAuthor Commented:
just noticed got the subtract backwards: this code is the current one ;) sorry
---------------------
#include <stdio.h>
#include <tchar.h>
#include <windows.h>

LARGE_INTEGER count1, count2, frequency;
int difference;

int main ()
{
  int n;
  //for (n=10; n>0; n--)
  for (int loopTimes = 0; loopTimes < 25; loopTimes++)
  {
    QueryPerformanceCounter(&count1);
    for(int i = 0; i<10000000; i++) {}
    QueryPerformanceCounter(&count2);
    QueryPerformanceFrequency(&frequency);
    difference = count2.QuadPart - count1.QuadPart;
    printf ("%d, %d\n", difference, frequency.QuadPart);
  }
  system("PAUSE");
  return 0;
}
----------------------
still getting a lot of values in not sure how to use tho.. sorry
0
 
jkrCommented:
>>printf ("%d, %d\n", difference, frequency.QuadPart);

As these are 64-bit inegers, you need to use different format specifiers with 'printf()', i.e.

printf ("%I64d, %I64d\n", difference, frequency.QuadPart);

Or, to anticipate the actual duration:

LARGE_INTEGER count1, count2, frequency;
LARGE_INTEGER difference;

int main ()
{
 int n;
 //for (n=10; n>0; n--)
 for (int loopTimes = 0; loopTimes < 25; loopTimes++)
 {
   QueryPerformanceCounter(&count1);
   for(int i = 0; i<10000000; i++) {}
   QueryPerformanceCounter(&count2);
   QueryPerformanceFrequency(&frequency);
   difference.QuadPart = count2.QuadPart - count1.QuadPart;
   printf ("I64%d, %I64d -> %I64d\n", difference.QuadPart, frequency.QuadPart, difference.QuadPart/ frequency.QuadPart);
 }
 system("PAUSE");
 return 0;
}
0
 
TLBHAuthor Commented:
i think ive got it...

i modified the code to divide the frequency by 1000 (to get the duration in miliseconds) and increased the delay to more easiley see the gaps

the final questions (I promise :) ) is basically: will this code work? and (I assume this is why the other code is a lot longer?) there will be situations where this code breaks? and also is is possible to convert that output into a float to find the fraction of a second it takes (this would tie in nicely to the application in making as im using SI units)

current code:
-------------------------------------
#include <stdio.h>
#include <tchar.h>
#include <windows.h>

LARGE_INTEGER count1, count2, frequency;
LARGE_INTEGER difference;

int main ()
{
 int n;
 //for (n=10; n>0; n--)
 for (int loopTimes = 0; loopTimes < 25; loopTimes++)
 {
   QueryPerformanceCounter(&count1);
   for(int i = 0; i<1000000000; i++) {}
   QueryPerformanceCounter(&count2);
   QueryPerformanceFrequency(&frequency);
   difference.QuadPart = count2.QuadPart - count1.QuadPart;
   frequency.QuadPart = frequency.QuadPart/ 1000;
   printf ("%I64d, %I64d -> %I64d\n", difference.QuadPart, frequency.QuadPart, difference.QuadPart/ frequency.QuadPart);
 }
 system("PAUSE");
 return 0;
}
-----------------------------------
Outputs:
4392520040, 2800500 -> 1568
4135256212, 2800500 -> 1476
4214645288, 2800500 -> 1504
4144759076, 2800500 -> 1480
4209412012, 2800500 -> 1503
4129651040, 2800500 -> 1474
4174978972, 2800500 -> 1490
4146471260, 2800500 -> 1480
4174600180, 2800500 -> 1490
4163089268, 2800500 -> 1486
4166515636, 2800500 -> 1487
4283685080, 2800500 -> 1529
4168421160, 2800500 -> 1488
4150671152, 2800500 -> 1482
4169326840, 2800500 -> 1488
4165248572, 2800500 -> 1487
4204039324, 2800500 -> 1501
4146277248, 2800500 -> 1480
4172498604, 2800500 -> 1489
4136907672, 2800500 -> 1477
4163323940, 2800500 -> 1486
4145151108, 2800500 -> 1480
4198050272, 2800500 -> 1499
4131879636, 2800500 -> 1475
4180720096, 2800500 -> 1492
Press any key to continue . . .
0
 
jkrCommented:
>>will this code work? and (I assume this is why the other code is a lot longer?)

Yes. That other code does a lot of additional stuff (such as adjusting thread priorities)

>>there will be situations where this code breaks?

Yes, when you have an int64-overflow :o) - but that's highly hypothetical. But, as a basic sanity check, test if the frequency returned by 'QueryPerformanceFrequency()' is non-null to avoid a 'division by zero' if that feature is unavailable.

>>and also is is possible to convert that output into a float to find the fraction of a second it takes

Sure. Since you already have it in millisecs, feed the value that you output to the screen to a 'double', e.g. like

double d = (double) (difference.QuadPart/ frequency.QuadPart) / 1000.0;
0
 
TLBHAuthor Commented:
before I accepted your answer I just want to thank you for all your help:
This is my first time actually asking a question on Experts Exchange (signed up a year ago tho lol ;) ) and if this is what I can expect I am impressed :)

So thanks again you've been a lot more helpfull then I imagined ;) (and sorry for my spelling.. it sorta vanishes whenever i sit in front of a keyboard)
0
 
jkrCommented:
You're most welcome :o)
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now