/** \file ProfileSample.h
* Declares the ProfileSample class.
*
* @note The design of the Profiler is inspired by the book Game Programming
* Gems 1 by Steve Rabin
*
* @author Vovansim (aka Scorpion)
* @version Version 1.0
* @date September 14, 2003
*/
#ifndef PROJECT_AXIS_PROFILE_SAMPLE
#define PROJECT_AXIS_PROFILE_SAMPLE
#include
#include
#include "SDL/SDL.h"
#include "IProfilerOutputHandler.h"
/** Defines the maximum number of samples that can exist ar any given time */
#define MAX_PROFILE_SAMPLES 50
/** All the data for a sample is stored in this struct */
typedef struct tagProfileSample {
/** Whether or not this sample is valid */
bool IsValid;
/** Is this sample currently being profiled? */
bool IsOpen;
/** Number of times this sample has been profiled this frame */
unsigned int CallCount;
/** Name of the sample */
std::string Name;
/** Starting time on the clock, in seconds */
float StartTime;
/** Total time recorded across all profiles of this sample */
float TotalTime;
/** Total time taken by children of this sample */
float ChildTime;
/** Depth of the sample in the hierarchy (distance for the top-most sample */
int ParentCount;
/** Average percentage of game loop time taken up */
float AveragePc;
/** Minimum percentage of game loop time taken up */
float MinimumPc;
/** Maximum percentage of game loop time taken up */
float MaximumPc;
/** Number of percentage values that have been stored */
unsigned long DataCount;
tagProfileSample()
{
IsValid = false;
DataCount = 0;
AveragePc = -1;
MinimumPc = -1;
MaximumPc = -1;
}
} sProfileSample;
/**
* The ProfileSample class is the meat and bones of the
* profiler. Essentially, it combines the functionality of a single
* profile sample (or a single piece of code in the suite of those
* being profiled) and the profiler as a whole. The latter is being
* represented by the static members of the class. Essentially, there
* are two things one needs to take care of before the profiler can be
* used:
* 1. Create a profile output handler and tell the profiler to use it
* 2. Create a root profile sample, with relation to which all of the
* other samples will be counted. It is best to put the root sample
* around the call to the game loop or in the main method.
* After the program is finished executing, one needs to tell the
* profiler to dump the output by calling the static output
* method. Profiling is then as simple as that.
*
* That is as far as global profiler is concerned. Now, let us look at
* the single profile samples. Samples are started when they are
* created and are stopped when they are destroyed. So, one can use
* scope to take care of the samples. In other words, create a sample
* object somewhere in a function, and it will time the execution
* untill it falls out of scope or is explicitly destroyed. Note that
* the profiler keeps track of samples by their name, and not
* necessarily by instances of the object. Thus, two samples with the
* same name will count towards the same statistic. Also, the profiler
* supports sample nesting, so don't be shy about creating new
* profiles within methods or pieces of code that are already being
* profiled. As long as the samples have different names, everything
* will be computed correctly.
*/
class ProfileSample {
public:
/** Creates a sample with the given name and starts the timer */
ProfileSample(std::string sampleName);
/** Destroys the current profile: stops the timer and records the data */
~ProfileSample();
////////////////////////////// Static Methods /////////////////////////////
/** Takes the output handler and uses it to output the results for the profiler */
static void Output();
/** Resets the sameple with the given name */
static void ResetSample(std::string sampleName);
/** Resets all samples in the profile */
static void ResetAll();
/** Starts the profiler if it is stopped */
inline static void StartProfiler() { profilerIsRunning = true; }
/** Stops the profiler if it is running */
inline static void StopProfiler() { profilerIsRunning = false; }
/** Returns true if the profiler is running and false otherwise */
inline static bool IsProfilerRunning() { return profilerIsRunning; }
/** Gets the output handler */
inline static IProfilerOutputHandler* GetOutputHandler() { return outputHandler; }
/** Sets the output handler for the profiler */
inline static void SetOutputHandler(IProfilerOutputHandler* handler) { outputHandler = handler; }
//////////////////////////// End Static Methods ///////////////////////////
protected:
/** Index of the current sample in the array of samples */
int sampleIndex;
/** Index of the parent sample in the array of samples */
int parentIndex;
/** Returns current time */
inline float GetTime(){ return SDL_GetTicks()/1000.0f; }
///////////////////////// Static data and methods /////////////////////////
/** A pointer to the output handler used to print the results of profiling */
static IProfilerOutputHandler* outputHandler;
/** Whether or not the profiler is running */
static bool profilerIsRunning;
/** An array of samples currently being profiled */
static sProfileSample samples[MAX_PROFILE_SAMPLES];
/** The index in the array of the sample that was opened last */
static int lastOpenedSample;
/** The number of open samples */
static int openSampleCount;
/** The time when the root sample was begun */
static float rootBegin;
/** The time when the root sample was stopped */
static float rootEnd;
/////////////////////// End Static data and methods ///////////////////////
};
#ifdef _DEBUG
#define PROFILE(name) ProfileSample _profile_sample(name);
#else
#define PROFILE(name)
#endif
#endif//PROJECT_AXIS_PROFILE_SAMPLE