Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Profiler Class Reference

#include <Profiler.h>

List of all members.


Detailed Description

Manages a hierarchy of timers for profiling time spent in code, gives microsecond resolution.

Doesn't use any pointers so it's safe to put this in shared memory regions.
That's handy so one process can collate all the profiling information across processes to give a summary report to the user.

Example usage:

  • Use a static variable to hold an id number for the code section (doesn't necessarily have to be static, but is faster that way)
  • Create a Profiler::Timer object - its construction marks the 'start' time, and its destructor marks the 'stop' time.

  ProfilerOfSize<2> prof; //A global manager for all the sections
  
  void f() {
    static unsigned int id=prof.getNewID("f"); // <== Get the ID number 
    Profiler::Timer timer(id,&prof.prof);      // <== start the timer
    //...
    if(rand()>RAND_MAX/2)
      return; // destruction of timer occurs automatically!
    //...
  } // if we didn't hit the return, timer will otherwise destruct here!

However, there's a macro that makes this a one liner:

  void g() {
    PROFSECTION("g",prof);   // <== Most of the time, this is all you need
    //...                    // (unless you're doing something fancy like conditional timers)
    f(); // will note f's time as g's child time, as well as g's own time
    //...
  }

The idea is similar to that used by MMAccessor. If you want to profile a section at smaller resolution than a function, you can use tricks shown in MMAccessor's documentation to limit the timer's scope.

For convenience, there are three global profilers predefined: mainProfiler, motionProfiler, and soundProfiler. These are what are polled by the ProfilerCheckControl -- if you instantiate a new profiler, you will have to call its report() function yourself to get the results. (If it's simply a matter of running out of sections in mainProfiler, increase the template parameter at the end of Profiler.h) Keep in mind however, that these global profilers are pointers, and need to be dereferenced to use with the macro, e.g. PROFSECTION("g2",*mainProfiler)

Here were the constraints I set for myself:

  • Processes can read each other's Profilers - so must be able to live in shared memory
    This is so one process can generate a report on performance of the entire system at once
  • Flexible memory footprint
    MainObject will probably have a lot of subsections. MotionObject won't. Since SectionInfo takes some significant memory space, we don't want to force MotionObject to needlessly make a lot of them.
  • Flexible usage - can have a single generic global, as well as creating multiple
  • Fast - don't want to kill performance of profiled sections, or throw off reported results

Consessions made:

  • Sections are not dynamically allocated
  • Sections within a Profiler are mutually exclusive (otherwise curSection won't be reliable)
  • Results don't try to take affects of pre-emptive multitasking into account.

Global readability is first priority since generating reports is the primary usage, thus we have to be able to handle being in shared memory space. This means no virtual functions and no pointer storage. Unfortunately, this makes the second constraint rather difficult.
Run-time dynamic allocation is right out. But the number of sections is set at compile time anyway, so it should be OK to set this at compile time, using a template parameter.
That gets us 99% of the way there, but it can be burdensome to use this since the template means there's no consistant type for all profilers - you can't have a generic Profiler type if it's templated - you would have to know the size of the profiler you're referring to.
That kind of brings in the third constraint... Instead of accepting a single global, I decided to make a general base (Profiler) and then a templated subclass to hold the bulk data section. This has the nice side affect of not having to specify the bulk of the code in the header, but has the downside that accessing the info stored in the subclass from the super class is very much a hack. If you think you can get around this, good luck!

Note:
This could be made much prettier if we didn't care about the virtual function-shared memory problems... sigh

Definition at line 96 of file Profiler.h.

Public Member Functions

 Profiler (unsigned int mx)
 constructor, but you don't want to construct one of these! Use ProfilerOfSize<x> instead!
unsigned int getNewID (const char *name)
 call this to get a new ID number
float * getBuckets ()
 returns the bucket boundaries
std::string report ()
 outputs profiling information
void reset ()
 resets profiling information
SectionInfogetInfos ()
 gets the actual storage area of the SectionInfo's

Static Public Member Functions

static void initBuckets ()
 called during process init (before any profiled sections)

Public Attributes

unsigned int curSection
 the current timer
TimeET startTime
 time of beginning profiling
float gamma
 gamma to use with exponential averages (1 to freeze, 0 to set to last)
const unsigned int maxSections
 so we can read the size of the infos array back again at runtime
unsigned int sectionsUsed
 the number of timer IDs which have been assigned

Static Public Attributes

static const unsigned int MaxSectionNameLen = 75
 maximum length of names of timers
static const unsigned int HistSize = 32
 number of slots in the histograms
static const unsigned int HistTime = 10*1000
 the upper bound (exclusive) of the histograms, in milliseconds.
static const float HistCurve = 4.05
 affects how linearly the buckets are distributed - 1 means linear, >1 causes higher resolution for short times

Protected Member Functions

void setCurrent (Timer &tr)
 called automatically by Timer() - sets the current timer
void finished (Timer &tr)
 called automatically by ~Timer() - notes the specified timer as finished (doesn't check if the timer is actually the current one - don't screw up!)
unsigned int getBucket (float t)
 returns which bucket a time should go in, does a binary search over buckets (unless someone things a log() call would be faster...)

Protected Attributes

Profiler::AutoInit autoInit
 Automatically causes initialization of the histogram buckets when the first Profiler is instantiated.

Static Protected Attributes

static float buckets [HistSize]
 holds boundaries for each bucket
static unsigned int infosOffset = ((size_t)(&static_cast<ProfilerOfSize<1>*>(NULL)[1].infos))-((size_t)(&static_cast<ProfilerOfSize<1>*>(NULL)[1].prof))
 NASTY HACK - this is how we get around using virtual functions.

Friends

class Timer
 Only the Timer's should be calling setCurrent() and finished() upon the Timer's construction and destruction.

Classes

class  AutoInit
 Automatically causes initialization of the histogram buckets when the first Profiler is instantiated. More...
struct  SectionInfo
 holds all the information needed for book keeping for each timer More...
class  Timer
 Measures the time that this class exists, reports result to a profiler. More...


The documentation for this class was generated from the following files:

Tekkotsu v3.0
Generated Fri May 11 20:08:35 2007 by Doxygen 1.4.7