views:

1187

answers:

7

Hi folks.

I should compute execution time of a C++ code snippet in seconds. It must be working either on Windows or Unix machines

I use code the following code to do this. (import before)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

However for small inputs or short statements such as a = a + 1, I get "0 seconds" result. I think it must be something like 0.0000001 seconds or something like that.

I remember that System.nanoTime() in Java works pretty well in this case. However I can't get same exact functionality from clock() function of C++.

Do you have a solution?

+2  A: 

Windows provides QueryPerformanceCounter() function, and Unix has gettimeofday() Both functions can measure at least 1 micro-second difference.

Captain Comic
But using windows.h is restricted. The same compiled source must run on both Windows and Unix. How to handle this problem?
Ahmet Alp Balkan
Then look for some wrapper libraryhttp://stackoverflow.com/questions/1487695/c-cross-platform-high-resolution-timer
Captain Comic
*the same compiled source* sounds like you want to run the same binary on both systems, which doesn't seem to be the case. if you meant *the same source* then an `#ifdef` must be ok (and it is judging from the answer you have accepted), and then I don't see the problem: `#ifdef WIN32 #include <windows.h> ... #else ... #endif`.
just somebody
+10  A: 

Try with this. It will work like time(NULL), but will return the number of milliseconds instead of seconds from the unix epoch on both windows and linux.

#ifdef WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

int64 GetTimeMs64()
{
#ifdef WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}

You can modify it to return microseconds instead of milliseconds if you want.

Andreas Bonini
Looks like a nice code. Thanks. I'll try.
Ahmet Alp Balkan
Should I do <code>typedef long long int64;typedef unsigned long long uint64;</code> ?
Ahmet Alp Balkan
Yes Ahmet Alp Balkan
Andreas Bonini
Also #define WIN32 on windows, of course :)
Andreas Bonini
Works very well, thanks.
Ahmet Alp Balkan
What's the granularity in Windows?
Arthur Kalliokoski
Will this function work fine if the thread(s) calling it are on different cores? The values will have strange offsets between each call in this case, isn't it? In doubt I use the Ogre source code (MIT) as there are extra code checking for this kind of case.
Klaim
@akallio: 15 milliseconds. On linux `gettimeofday` is implementation dependent, but usually 15 milliseconds as well
Andreas Bonini
@Klaim: no they won't have strange offsets, and yes it's thread safe.
Andreas Bonini
I didn't mean "thread-safe", I'm talking about another problem related to the differences in tick-count between different cores. I've seen this kind of problem with multi-cores when you don't set a thread affinity for the code calling the time function. But it was visible only with QueryPerformanceCounter() I think (on Windows). Not sure it would be a problem with GetSystemTimeAsFileTime() though.
Klaim
@Klaim: yes, I know what you meant, and no you won't have the same problem as this function returns the current date/time and not the CPU's time. It's like asking if `time(NULL)` will return different values with different cores :)
Andreas Bonini
Really interesting then +1 :D
Klaim
@Andreas Bonini: I think you should use `uint64` as the returntype of the function instead of `int64`.
MKroehnert
+3  A: 

I have another working example that uses microseconds (UNIX, POSIX, etc).

    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

Here's the file where we coded this:

http://svn.arhuaco.org/svn/src/emqbit/tools/emqbit-bench/bench.c

arhuaco
+1  A: 

I suggest using the standard library functions for obtaining time information from the system.

If you want finer resolution, perform more execution iterations. Instead of running the program once and obtaining samples, run it 1000 times or more.

Thomas Matthews
+1  A: 

It is better to run the inner loop several times with the performance timing only once and average by dividing inner loop repetitions than to run the whole thing (loop + performance timing) several times and average. This will reduce the overhead of the performance timing code vs your actual profiled section.

Wrap your timer calls for the appropriate system. For Windows, QueryPerformanceCounter is pretty fast and "safe" to use.

You can use "rdtsc" on any modern X86 PC as well but there may be issues on some multicore machines (core hopping may change timer) or if you have speed-step of some sort turned on.

Adisak
A: 

In some programs I wrote I used RDTS for such purpose. RDTSC is not about time but about number of cycles from processor start. You have to etalonate it on your system to get a result in second, but it's really handy when you want to evaluate performance, it's even better to use number of cycles directly without trying to change them back to seconds.

(link above is to a french wikipedia page, but it has C++ code samples, english version is here)

kriss
A: 

boost::timer will probably give you as much accuracy as you'll need. It's nowhere near accurate enough to tell you how long a = a+1; will take, but I what reason would you have to time something that takes a couple nanoseconds?

Brendan Long