/** \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