//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #ifndef _PROFILER_H_ #define _PROFILER_H_ #include "core/torqueConfig.h" #ifdef TORQUE_ENABLE_PROFILER struct ProfilerData; struct ProfilerRootData; /// The Profiler is used to see how long a specific chunk of code takes to execute. /// All values outputted by the profiler are percentages of the time that it takes /// to run entire main loop. /// /// First, you must #define TORQUE_ENABLE_PROFILER in profiler.h in order to /// active it. Examples of script use: /// @code /// //enables or disables profiling. Data is only gathered when the profiler is enabled. /// profilerEnable(bool enable); /// profilerReset(); //resets the data gathered by the profiler /// profilerDump(); //dumps all profiler data to the console /// profilerDumpToFile(string filename); //dumps all profiler data to a given file /// profilerMarkerEnable((string markerName, bool enable); //enables or disables a given profile tag /// @endcode /// /// The C++ code side of the profiler uses pairs of PROFILE_START() and PROFILE_END(). /// /// When using these macros, make sure there is a PROFILE_END() for every PROFILE_START /// and a PROFILE_START() for every PROFILE_END(). It is fine to nest these macros, however, /// you must make sure that no matter what execution path the code takes, the PROFILE macros /// will be balanced. /// /// The profiler can be used to locate areas of code that are slow or should be considered for /// optimization. Since it tracks the relative time of execution of that code to the execution /// of the main loop, it is possible to benchmark any given code to see if changes made will /// actually improve performance. /// /// Here are some examples: /// @code /// PROFILE_START(TerrainRender); /// //some code here /// PROFILE_START(TerrainRenderGridSquare); /// //some code here /// PROFILE_END(); /// //possibly some code here /// PROFILE_END(); /// @endcode class Profiler { enum { MaxStackDepth = 256, DumpFileNameLength = 256 }; U32 mCurrentHash; ProfilerData *mCurrentProfilerData; ProfilerData *mProfileList; ProfilerData *mRootProfilerData; bool mEnabled; S32 mStackDepth; bool mNextEnable; U32 mMaxStackDepth; bool mDumpToConsole; bool mDumpToFile; char mDumpFileName[DumpFileNameLength]; void dump(); void validate(); public: Profiler(); ~Profiler(); /// Reset the data in the profiler void reset(); /// Dumps the profile to console void dumpToConsole(); /// Dumps the profile data to a file /// @param fileName filename to dump data to void dumpToFile(const char *fileName); /// Enable profiling void enable(bool enabled); /// Helper function for macro definition PROFILE_START void hashPush(ProfilerRootData *data); /// Helper function for macro definition PROFILE_END void hashPop(); /// Enable a profiler marker void enableMarker(const char *marker, bool enabled); }; extern Profiler *gProfiler; struct ProfilerRootData { const char *mName; U32 mNameHash; ProfilerData *mFirstProfilerData; ProfilerRootData *mNextRoot; F64 mTotalTime; F64 mSubTime; U32 mTotalInvokeCount; bool mEnabled; static ProfilerRootData *sRootList; ProfilerRootData(const char *name); }; struct ProfilerData { ProfilerRootData *mRoot; ///< link to root node. ProfilerData *mNextForRoot; ///< links together all ProfilerData's for a particular root ProfilerData *mNextProfilerData; ///< links all the profilerDatas ProfilerData *mNextHash; ProfilerData *mParent; ProfilerData *mNextSibling; ProfilerData *mFirstChild; enum { HashTableSize = 32, }; ProfilerData *mChildHash[HashTableSize]; ProfilerData *mLastSeenProfiler; U32 mHash; U32 mSubDepth; U32 mInvokeCount; U32 mStartTime[2]; F64 mTotalTime; F64 mSubTime; }; #define PROFILE_START(name) \ static ProfilerRootData pdata##name##obj (#name); \ if(gProfiler) gProfiler->hashPush(& pdata##name##obj ) #define PROFILE_END() if(gProfiler) gProfiler->hashPop() #else #define PROFILE_START(x) #define PROFILE_END() #endif #endif