Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Multiple Performance Timer

0.00/5 (No votes)
2 Jan 2003 1  
Time multiple parts of your code and display accumulated results

Introduction

This article contains one file MultiTimer.h which allows you to easily time parts of your code. It accumulates times on multiple calls and produces an output summary with all the totals and number of calls for each timer. There are many similar articles here and elsewhere, I thought it worthwhile to add this article though, as I think my timer class adds a few extra features and is very easy to use.

Example

void testfun()
{
    printf("Hello World!\n");
}

int main(int argc, char* argv[])
{
    for (int i = 0; i < 10; i++)
        testfun();

    return 0;
}

This isn't the best example of code to time, but it is a good example to show how the timing code is used. See the usage guidelines below for ideas on how to time your code.

Adding timing code

The following steps are needed to add timing code:

  • Add #include "MultiTimer.h"
  • Add timing macros to the code you want to time
  • Call TIMER_DUMP or similar macros to display the results

After adding some test timing code, the above example looks like this:

#include "MultiTimer.h"


void testfun()
{
    TIME_LINE(printf("Hello World!\n");)
}

int main(int argc, char* argv[])
{
    {
    TIME_SCOPE("total test")
    for (int i = 0; i < 10; i++)
        TIME_FUN(testfun())
    }
    TIMER_DUMP("c:\\times.txt", SORT_CALLORDER)
    
    return 0;
}

This produces the following output file:

-----------------------------------------------------------------
Timings at 10:41:56 Friday, January 03, 2003
-----------------------------------------------------------------
total test took 606.80 micro secs (called 1 time)
testfun() took 591.42 micro secs (called 10 times)
printf("Hello World!\n"); took 561.52 micro secs (called 10 times)

The results are pretty straightforward. If you download the demo code, you will see further code which breaks down the times for the testfun() calls. Here is a sample output from this code:

Total: 668.20 micro secs
Minimum: 39.39 micro secs
Maximum: 302.55 micro secs
Average: 66.82 micro secs

-----------------------------------------------------------------
testfun() at 10:22:06 Friday, January 03, 2003
-----------------------------------------------------------------
Sample  1 = 302.55 micro secs
Sample  2 = 58.11 micro secs
Sample  3 = 55.87 micro secs
Sample  4 = 41.63 micro secs
Sample  5 = 42.46 micro secs
Sample  6 = 41.07 micro secs
Sample  7 = 42.46 micro secs
Sample  8 = 39.39 micro secs
Sample  9 = 50.29 micro secs
Sample 10 = 43.02 micro secs

You can see from this that the first printf takes a lot longer on Windows 2000, I guess some initialization is going on.

Macros

From the above example, you can see that this timing code is largely macro driven, here is a list of the macros used:-

TIMER_SETUP

This needs to be included in one of the .cpp files in a project, at a global scope. It sets up the storage for the timing code.

TIME_SCOPE(name)

Place this in your code to time from that point to the end of the current scope. name is a string, which is used in the output to identify these times.

TIME_FUN(fun())

Replace a function call, fun(), with this macro to time the call.

TIME_LINE(line)

Wrap any line with this macro to time it. Avoid declaring any variables in the line, as this macro puts the line in a separate scope.

TIMER_START(name) and TIMER_STOP(name)

These macros allow you to start and stop timers manually. See the demo for an example.

TIMER_DUMP(dest, sort)

Dump the current times. If dest is a file name, then the output is written to this file. Otherwise it can be:

  • OUT_MSGBOX - Display output in a message box
  • OUT_TRACE - Send the output to the trace window
  • OUT_CONSOLE - Send the output to stdout

The output can be sorted in 3 ways:

  • SORT_TIMES - The longest time is displayed first, down to the smallest
  • SORT_CALLORDER - The times are displayed in the order the timers were called
  • SORT_NAMES - The output is sorted alphabetically

TIMER_DUMP_FILE(dest, sort, mode)

This allows 3 extra mode values:

  • FILE_NEW - Create a new file each time
  • FILE_APPEND - Add each output to the end of the file
  • FILE_PREPEND - Add each output to the start of the file

This is useful if you want to compare several test runs.

TIMER_DUMP_CSV(dest, sort, mode)

This is the same as TIMER_DUMP_FILE but the output is in comma separated format.

TIMER_DUMP_SAMPLES*(timer, ...)

The TIMER_DUMP_SAMPLES macros dump all the samples for a specified timer, this can be it's name or a CHiFreqTimer object. See the demo for an example.

There are 3 TIMER_DUMP_SAMPLES macros which correspond to the TIMER_DUMP macros, except there is no sort argument - the samples are dumped in ascending order.

GET_TIMER(name)

Return a CHiFreqTimer object for timer name. Further statistics can then be used, see the demo for an example.

T2S(time)

Converts a time returned from a CHiFreqTimer call to a meaningful string, see the demo for examples.

CLEAR_TIMERS

Removes all timers.

Disabling timing code

At the top of MultiTimer.h is a #define USE_TIMERS. Commenting this out will compile out any timing code you may have added.

Timing multiple files

You can put timing code in more than one file. Every file needs to include multitimer.h and all but the first must put the following line before the #include:

#define ANOTHER_TIMER_FILE

Clock ticks

It is sometimes useful to know how many clock ticks a piece of code took. I've added some macros which convert the time taken to clock cycles, first you must uncomment the #define _CLOCKTICKS line at the top of multitimer.h file. They are:-

T2C(time)

Converts a time to a string containing the number of clock cycles taken.

T2S_WITHCYCLES(time)

Converts a time to a string containing the time and the number of cycles.

CLOCK_SPEED

This is an int which represents your machine speed, e.g.. 733. This figure is accurate to 1 or 2 of your specific machine speed.

Usage guidelines

The idea of this type of code is to identify slow parts of your projects. If a part of your project is slow, it should help you to narrow down which bit of your code is causing the problem. You should avoid timing very quick statements - the timings are likely to be inaccurate. Also don't time all of your code, focus on areas that are slow and need to be sped up. It can also be helpful to know how many times a particular line or function is called, as this is often difficult to find out from the code alone.

Ideally release code should always be used to get accurate timings, the extra checking and lack of optimizations in debug code can cause misleading results. Other running processes can also affect times, for example virus scanners can skew file access times.

Accuracy and timing overheads

Any code added to time a file will itself take some time. This code tries to compensate for this but with very large number of timers and/or timing calls, a small loss of accuracy may result.

The QueryPerformanceCounter() call is used to time things. This is only supported on Pentiums. If you're running on an older machine, upgrading will probably speed things up...

Change History

  • 6/11/02
    • General improvements to MultiTimer.h file
    • TIMER_DUMP_FILE macro added
  • 7/11/02
    • Added TIMER_START + TIMER_STOP macros
    • Added USE_TIMERS #define
  • 3/1/03
    • Sorted out TIMER_START and TIMER_STOP manual timers
    • Added TIMER_DUMP_CSV macro
    • Added TIMER_DUMP_SAMPLES, TIMER_DUMP_SAMPLES_FILE and TIMER_DUMP_SAMPLES_CSV macros
    • Added clock tick macros
    • Removed TIMER_SETUP macro

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here