Next: Profiling Implementation Up: Profiling pC++ Programs Previous: Profiling pC++ Programs

General Approach

We perform all program transformations necessary for instrumentation at the language level, thus ensuring profiling portability. However, since profiling means inserting special code at all entry and exit points of a function, language-level profiling introduces the tricky problem of correctly instrumenting these points. In particular, we have to ensure that the exit profiling code is executed as late as possible before the function is exited. In general, a function can return an expression that can be arbitrarily complex, possibly taking a long time to execute. Correct profiling instrumentation would extract the expression from the return statement, compute its value, execute the profiling exit code, and finally return the expression result.

Luckily, we can let the C++ compiler do the dirty work. The trick is very simple: we declare a special Profiler class which only has a constructor and a destructor and no other methods. A variable of that class is then declared and instantiated in the first line of each function which has to be profiled as shown below for function bar.


class Profiler {
  char* name;
public:
  Profiler(char *n) {name=n; code_enter(n);}
  ~Profiler() {code_exit(name);}
};

void bar(){
  Profiler tr("bar"); // Profiler variable
  // body of bar
}

The variable 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). The C++ compiler is clever enough to rearrange the code and to insert calls to the destructor no matter how the scope is exited. Note also, that we use a private member to store a function identification which we can use in the destructor.



Next: Profiling Implementation Up: Profiling pC++ Programs Previous: Profiling pC++ Programs


mohr@cs.uoregon.edu
Thu Feb 24 13:42:43 PST 1994