A very valuable tool for program tuning is function profiling. Here, special instrumentation code is inserted at all entry and exit points of each function to capture data that can be used to calculate the number of times a function is called and the percentage of the total execution time spent in each including and excluding its children.
To ensure portability, all instrumentation for profiling must be done at the source language level. Using language features of C++, we can instrument the source code efficiently, just by declaring a special Profiler class which only has a constructor and a destructor. A variable of that class is then declared in the first line of each function which has to be profiled. During runtime, a Profiler object is created and initialized each time the control flow reaches its definition (via the constructor) and destroyed on exit from its block (via the destructor).
This generic profiling instrumentation approach has two basic advantages. First, the instrumentation is portable, because it occurs at the source code level. Second, different implementations of the profiler can be easily created by providing different code for the constructor and destructor. This makes it very flexible. Currently, we have implemented two versions of the profiler for pC++: A direct profiler which computes the function profile during program execution, and a trace-based profiler which uses an event logging function from the pC++ software event tracing library (see Section 5.3). The computation of the profile statistics is then done off-line. Other profiling alternatives could be implemented in the same way. For example, profiling code could be activated/deactivated for each function separately, allowing dynamic profiling control. Another possibility is to let users supply function-specific profile code (specified by source code annotations or special class members with predefined names), allowing customized runtime performance analysis.
We use the Sage++ class library and restructuring toolkit to manipulate pC++ programs and insert the necessary profiler instrumentation code at the beginning of each function. The user has control over the level, detail, and type of profiling. There are also instrumented versions of the pC++ class libraries and runtime system. In addition to the instrumentation of user-level functions, they provide profiling of runtime system functions and collection access.