views:

6360

answers:

10

I'm working on a C++ application that needs detailed timing information, down to the millisecond level.

We intend to gather the time to second accuracy using the standard time() function in . We would like to additionally gather the milliseconds elapsed since the last second given by time().

Does anyone know a convenient method for obtaining this information?

Thanks.

A: 

Look into the QueryPerformanceCounter methods if this is for Windows.

dbrien
+7  A: 

There is not a portable solution to this problem, since ANSI C does not define a standard millisecond-accurate time function. If you're using Windows, you can use GetTickCount(), timeGetTime(), or QueryPerformanceCounter()/QueryPerformanceFrequency(). Keep in mind that these have different accuracies and different runtime costs.

There are other similar functions in other operating systems; I'm not sure what they are off the top of my head.

Adam Rosenfield
+1  A: 

Anything not in the (c)time.h header requires OS-specific methods. I believe all those methods are second resolution.

What OS are you working in?

jdmichal
+6  A: 

Boost.DateTime has millisecond and nanosecond representations IF the underlying platform supports them. While it is using platform specific code, it is keeping those details out of your code.

If that is a big deal, they do have another way of doing platform independent subsecond resolution. This page a couple of paragraphs down talks about how to do it.

(From the Page)

For example, let's suppose we want to construct using a count that represents tenths of a second. That is, each tick is 0.1 second.

int number_of_tenths = 5;
//create a resolution independent count -- divide by 10 since there are 
//10 tenths in a second.  
int count = number_of_tenths*(time_duration::ticks_per_second()/10);
time_duration td(1,2,3,count); //01:02:03.5 //no matter the resolution settings
Justin Rudd
+1  A: 

High Resolution, Low Overhead Timing for Intel Processors

If you're on Intel hardware, here's how to read the CPU real-time instruction counter. It will tell you the number of CPU cycles executed since the processor was booted. This is probably the finest-grained counter you can get for performance measurement.

Note that this is the number of CPU cycles. On linux you can get the CPU speed from /proc/cpuinfo and divide to get the number of seconds. Converting this to a double is quite handy.

When I run this on my box, I get

11867927879484732
11867927879692217
it took this long to call printf: 207485

Here's the Intel developer's guide that gives tons of detail.

#include < stdio.h >  // stackoverflow bug: pre tag eats the filenames,
#include < stdint.h > // so i had to put spaces in the angle brackets

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
Mark Harrison
The RDTSC instruction is discouraged, since it may give inaccurate results if the CPU goes to sleep, and it also does not produce consistent results between cores of a multicore system.
Adam Rosenfield
Those problems apply for QueryPerformanceTimer as well -- http://www.virtualdub.org/blog/pivot/entry.php?id=106
yrp
QueryPerformanceCounter() on Vista with HPET doesn't have these problems, nor does it on XP with /USEPMTIMER. AMD offers a processor driver that improves QPC() synchronization on XP. Using RDTSC directly prevents you from benefiting from any of these improvements.
bk1e
+3  A: 

GetTickCount in Windows gettimeofday in *nix QueryPerformanceCounter in Windows for better resolution (though GetTickCount should do it)

Iulian Şerbănoiu
+1  A: 

If you're on Unix, gettimeofday() will return seconds and microseconds, up to the resolution of the system clock.

int gettimeofday(struct timeval *tv, struct timezone *tz);

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};
Commodore Jaeger
+2  A: 
#include <ctime>

clock_t elapsed = static_cast<double>(clock() / CLOCKS_PER_SEC);

elapsed will be the elapsed processor time, in seconds.

resolution is operation system dependent, but is generally better than millisecond resolution on most systems.

A: 

Intel's Threading Building Blocks library has a function for this, but TBB is currently only availble on Intel and clones (that is, it's not available on SPARCs, PowerPC, ARM, etc.)

Max Lybbert
+1  A: 

As other have said, there is not a portable way to do this.

What I do (On msvc++ and linux/g++) is I use the following class that use QueryPerformanceCounter on Windows and gettimeofday on Linux. It's a timer class that can get you the elapsed time between two calls. You might want to modify it to fits your needs.

#if defined(_MSC_VER)
#  define NOMINMAX // workaround un bug dans windows.h qui define des macros
                   // "min" et "max" qui entrent en conflit avec la STL.
#  include <windows.h>
#else
#  include <sys/time.h>
#endif

namespace Utils
{

   /**
    * Implémente un chronométre qui mesure le temps etre deux appels.
    */
   class CTimer
   {
   private:
#     if defined(_MSC_VER)
         LARGE_INTEGER m_depart;
#     else
         timeval m_depart;
#     endif

   public:
      /**
       * Démarre le timer.
       * 
       * Cette fonction sert à démarrer le timer. Si le timer est  déja
       * démarrer, elle le redémarre simplement.
       */
      inline void start()
      {
#        if defined(_MSC_VER)
            QueryPerformanceCounter(&m_depart);
#        else
            gettimeofday(&m_depart, 0);
#        endif

      };

      /**
       * Retourne le nombre de secondes depuis le départ du timer.
       * 
       * @return Nombre de secondes écoulés depuis le départ du timer
       */
      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
      };
   };
}
Mathieu Pagé