Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Profiler Class Reference

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

#include <Profiler.h>


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 95 of file Profiler.h.

List of all members.

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...

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
floatgetBuckets ()
 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.05f
 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

class 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.

Constructor & Destructor Documentation

Profiler::Profiler ( unsigned int  mx  ) 

constructor, but you don't want to construct one of these! Use ProfilerOfSize<x> instead!

Definition at line 119 of file Profiler.cc.


Member Function Documentation

void Profiler::finished ( Timer tr  )  [protected]

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!)

Definition at line 156 of file Profiler.cc.

Referenced by Profiler::Timer::~Timer().

unsigned int Profiler::getBucket ( float  t  )  [protected]

returns which bucket a time should go in, does a binary search over buckets (unless someone things a log() call would be faster...)

Definition at line 182 of file Profiler.h.

Referenced by finished(), and setCurrent().

float* Profiler::getBuckets (  ) 

returns the bucket boundaries

Definition at line 156 of file Profiler.h.

SectionInfo* Profiler::getInfos (  ) 

gets the actual storage area of the SectionInfo's

Definition at line 171 of file Profiler.h.

Referenced by finished(), getNewID(), report(), reset(), and setCurrent().

unsigned int Profiler::getNewID ( const char *  name  ) 

call this to get a new ID number

Definition at line 62 of file Profiler.cc.

Referenced by ProfilerOfSize< MaxSections >::getNewID().

void Profiler::initBuckets (  )  [static]

called during process init (before any profiled sections)

Definition at line 56 of file Profiler.cc.

Referenced by Profiler::AutoInit::AutoInit().

std::string Profiler::report (  ) 

outputs profiling information

Definition at line 75 of file Profiler.cc.

Referenced by ProfilerOfSize< MaxSections >::report().

void Profiler::reset (  ) 

resets profiling information

Definition at line 112 of file Profiler.cc.

void Profiler::setCurrent ( Timer tr  )  [protected]

called automatically by Timer() - sets the current timer

Definition at line 135 of file Profiler.cc.

Referenced by Profiler::Timer::setID(), and Profiler::Timer::Timer().


Friends And Related Function Documentation

friend class Timer [friend]

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

Definition at line 175 of file Profiler.h.


Member Data Documentation

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

float Profiler::buckets [static, protected]

holds boundaries for each bucket

Definition at line 197 of file Profiler.h.

Referenced by getBucket(), getBuckets(), initBuckets(), and report().

unsigned int Profiler::curSection

the current timer

Definition at line 164 of file Profiler.h.

Referenced by finished(), and setCurrent().

gamma to use with exponential averages (1 to freeze, 0 to set to last)

Definition at line 166 of file Profiler.h.

Referenced by finished(), and setCurrent().

const float Profiler::HistCurve = 4.05f [static]

affects how linearly the buckets are distributed - 1 means linear, >1 causes higher resolution for short times

Definition at line 107 of file Profiler.h.

Referenced by initBuckets().

const unsigned int Profiler::HistSize = 32 [static]

number of slots in the histograms

Definition at line 103 of file Profiler.h.

Referenced by finished(), getBucket(), initBuckets(), report(), Profiler::SectionInfo::reset(), Profiler::SectionInfo::SectionInfo(), and setCurrent().

const unsigned int Profiler::HistTime = 10*1000 [static]

the upper bound (exclusive) of the histograms, in milliseconds.

Definition at line 105 of file Profiler.h.

Referenced by finished(), initBuckets(), and setCurrent().

unsigned int Profiler::infosOffset = ((size_t)(&static_cast<ProfilerOfSize<1>*>(NULL)[1].infos))-((size_t)(&static_cast<ProfilerOfSize<1>*>(NULL)[1].prof)) [static, protected]

NASTY HACK - this is how we get around using virtual functions.

Definition at line 199 of file Profiler.h.

Referenced by getInfos().

const unsigned int Profiler::MaxSectionNameLen = 75 [static]

maximum length of names of timers

Definition at line 101 of file Profiler.h.

Referenced by getNewID().

const unsigned int Profiler::maxSections

so we can read the size of the infos array back again at runtime

Definition at line 167 of file Profiler.h.

Referenced by getNewID().

unsigned int Profiler::sectionsUsed

the number of timer IDs which have been assigned

Definition at line 168 of file Profiler.h.

Referenced by getNewID(), report(), and reset().

time of beginning profiling

Definition at line 165 of file Profiler.h.

Referenced by report(), and reset().


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

Tekkotsu v5.1CVS
Generated Mon May 9 04:59:14 2016 by Doxygen 1.6.3