tags:

views:

497

answers:

8

Hi, I'm interested in measuring a specific point in time down to the nanosecond using c++ in windows. Is this possible? If it isn't, is it possible to get the specific time in microseconds at least? Any library should do, unless I suppose it's possible with managed code. thanks

+3  A: 

Windows has a high-performance counter API

You need to get the ticks form QueryPerformanceCounter and divide by the frequency of the processor, provided by QueryPerformanceFrequency.

LONG_INTEGER frequency;
if (::QueryPerformanceFrequency(&frequency) == FALSE)
    throw "foo";

LONG_INTEGER start;
if (::QueryPerformanceCounter(&start) == FALSE)
    throw "foo";

// Calculation.


LONG_INTEGER end;
if (::QueryPerformanceCounter(&end) == FALSE)
    throw "foo";

double interval = static_cast<double>(end - start) / frequency;

This interval should be in seconds.

Konrad Rudolph
Be warned, though, that intel's SpeedStep technology may change the PerformanceFrequency without your code noticing...
xtofl
@xtofl: truth be told, the values of `QPF` are probably not all that accurate anyway (there was a good description of the risks somewhere). But repeated measures tend to average this out relatively well.
Konrad Rudolph
QueryPerformanceFrequency/Coutner doesn't necessarily use the system clock for that very reason. However that means it uses another, lower frequency timer. Either the PIC timer, ACPI timer, or the HPET on very new systems. See http://blogs.msdn.com/oldnewthing/archive/2007/07/05/3695356.aspx for some details
shf301
For this very reason, recent versions of Windows won't use rdtsc for QPC, and hence don't return the processor frequency for QPF. They might use the 1.193182 MHz programmable interrupt timer (PIT) or the high-speed (>10 MHz) HPET.
DrPizza
QPF gives counts per second, so interval in this code is in seconds, not nanoseconds.
markh44
@mark: Thanks for the correction.
Konrad Rudolph
FWIW it seems Windows 7 uses the HPET :) Getting much better resolution, since I upgraded from Vista.
leppie
A: 

using QueryPerformanceCounter (for windows)

aJ
+1  A: 

You can use the Performance Counter API as Konrad Rudolf proposed, but should be warned that it is based on the CPU frequency. This frequency is not stable when e.g. a power save mode is enabled. If you want to use this API, make sure the CPU is at a constant frequency.

Otherwise, you can create some kind of 'statistical' system, correlating the CPU ticks to the PC BIOS clock. The latter is way less precise, but constant.

xtofl
+1  A: 

With respect to Konrad Rudolph's answer, note that in my experience the frequency of the performance counter is around 3.7MHz, so sub-microsecond, but certainly not nanosecond precision. The actual frequency is hardware (and power-save mode) dependent. Nanosecond precision is somewhat unreasonable in any case since interrupt latencies and process/thread context switching times are far longer than that, and that is also the order of magnitude of individual machine instructions.

Clifford
+1  A: 

rdtsc instruction is the most accurate.

Alexey Malistov
In English (although with different content) http://en.wikipedia.org/wiki/Time_Stamp_Counter
Clifford
Sorry. I did not pay attention. Fixed
Alexey Malistov
+5  A: 

If you have a threaded application running on a multicore computer QueryPerformanceCounter can (and will) return different values depending on which core the code is executing on. See this MSDN article. (rdtsc has the same problem)

This is not just a theoretical problem; we ran into it with our application and had to conclude that the only reliable time source is timeGetTime which only has ms precision (which fortunately was sufficient in our case). We also tried fixating the thread affinity for our threads to guarantee that each thread always got a consistent value from QueryPerformanceCounter, this worked but it absolutely killed the performance in the application.

To sum things up there isn't a reliable timer on windows that kan be used to time thing with micro second precision (at least not when running on a multicore computer).

Andreas Brinck
+1 for pointing out the poorly-known pitfalls to QueryPerformanceCounter. High performance timers on Windows just don't reliably exist, which is a giant PITA for some systems. Compare and contrast to Unix-based systems, which do it with ease...
Shaggy Frog
A: 

Here is a Timer class that will work both for Windows and Linux :

#ifndef INCLUDE_CTIMER_HPP_
#define INCLUDE_CTIMER_HPP_

#if defined(_MSC_VER)
#  define NOMINMAX // workaround a bug in windows.h
#  include <windows.h>
#else
#  include <sys/time.h>
#endif

namespace Utils
{
   class CTimer
   {
   private:
#     if defined(_MSC_VER)
         LARGE_INTEGER m_depart;
#     else
         timeval m_depart;
#     endif

   public:
      inline void start()
      {
#        if defined(_MSC_VER)
            QueryPerformanceCounter(&m_depart);
#        else
            gettimeofday(&m_depart, 0);
#        endif
      };

      inline float GetSecondes() const
      {
#        if defined(_MSC_VER)
            LARGE_INTEGER now;
            LARGE_INTEGER freq;

            QueryPerformanceCounter(&now);
            QueryPerformanceFrequency(&freq);

            return (now.QuadPart - m_depart.QuadPart) / static_cast<float>(freq.QuadPart);
#        else
            timeval now;
            gettimeofday(&now, 0);

            return now.tv_sec - m_depart.tv_sec + (now.tv_usec - m_depart.tv_usec) / 1000000.0f;
#        endif
      };
   };
}
#endif // INCLUDE_CTIMER_HPP_
Mathieu Pagé
A: 

Thanks for the input...though I couldn't get nano, or microsecond resolution which would have been nice, I was however able to come up with this...maybe someone else will find it usefull.

    class N_Script_Timer
{
 public:
  N_Script_Timer()
  {
   running = false;
   milliseconds = 0;
   seconds = 0;
   start_t = 0;
   end_t = 0;
  }
  void Start()
  {
   if(running)return;
   running = true;
   start_t = timeGetTime();
  }
  void End()
  {
   if(!running)return;
   running = false;
   end_t = timeGetTime();
   milliseconds = end_t - start_t;
   seconds = milliseconds / (float)1000;
  }
  float milliseconds;
  float seconds;

 private:
  unsigned long start_t;
  unsigned long end_t;
  bool running;
};
kelton52
To improve your resolution, you may want to add `timeBeginPeriod(1)` and `timeEndPeriod(1)` in `Start()` and `End()`, respectively.
mskfisher