Timing VisIt

VisIt has a builtin mechanism for timing execution time. This mechanism is enabled with a command line flag:

visit -timing

Finding the output

Each component outputs its timing information to its own file. For example, the viewer creates the file "viewer.timings". A parallel version of the engine encodes the MPI rank into the file name as well (engine_par.010.timings).

What's in the timing files

VisIt is already instrumented with much timing information, including these notables:

  • Startup time (gui, mdserver, & viewer)
  • Time to execute a plot (measurement in engine for pipeline execution time, measurement in viewer also includes time to transfer data back to viewer)
  • Time to execute each avtFilter (engine)
  • Many slower avtFilters add additional timing information. For example volume rendering breaks up sampling, compositing, and communication into its own entries.
  • Time to perform a scalable render (viewer and engine)
  • Time to perform 50 renders when in non-scalable rendering mode (viewer)


You can also add timing information for your own code, which is the subject of the next section.

Implementing your own timing code

Simple Interface

For the majority of cases, you can use the simplified `StackTimer' class. Include the header "StackTimer.h" and instantiate a StackTimer at the beginning of code blocks which need a timer, like so:

if(do_complicated_algorithm)
{
   StackTimer time_alg("Complicated Algorithm #42");
   obj->ComplicatedAlgorithm42();
}

Or, for timing anonymous scopes, you can use the TimedCodeBlock(message, block) macro:

TimedCodeBlock("complicated algorithm 6 * 7",
   my_obj->ComplicatedAlgorithmSixTimesSeven();
   my_obj->MeaningOfLife(42);
);

You should use the StackTimer whenever appropriate, since it has some guards which ensure you `do the right thing'. However there are some cases where it is not appropriate, in which case there is a more general mechanism available.

General Interface

You can access the timings manager by including the header "TimingsManager.h". This makes a global object (a "singleton") available: visitTimer. The visitTimer can time many things simultaneously. It keeps track of the different things being timed using handles. When you start the timer, visitTimer returns a handle. When you stop the timer, you pass the handle as an argument, as well as a description of what is being timed. For example:

#include <TimingsManager.h>
...
int t1 = visitTimer->StartTimer();
...
int t2 = visitTimer->StartTimer();
...
visitTimer->StopTimer(t2, "Taking facelists");
...
visitTimer->StopTimer(t1, "Taking facelists and removing ghost zones");

This produces output like:

    Taking facelists took 0.5
 Taking facelists and removing ghost zones took 0.75

The timer basically assumes that all new timings will finish before old timings (i.e. t2 be stopped before t1 in the example above). It still works if you violate this assumption, but its mechanism to indent the timings will become inconsistent.

Additional options

It is possible that outputting the timings to a file will affect the running time. To counteract this, you can use the flag "-withhold-timing-output". This will cause the messages to only be written to the file when it is explicitly requested, by calling:

visitTimer->DumpTimings();

It is also possible that having every processor of a parallel job write out its timing will bring the file system to its knees. This can be addressed with the flag "-timing-processor-stride N', which has only every Nth processor output timing info.

Differences between serial and parallel

There are two implementations of visitTimer. One uses system calls, while the other uses MPI timing facilities. The singleton "visitTimer" is automatically the "MPI" implementation in a parallel setting, and the "system call" implementation otherwise.