00001 /*************************************************************************** 00002 * * 00003 * (c) Art Tevs, MPI Informatik Saarbruecken * 00004 * mailto: <tevs@mpi-sb.mpg.de> * 00005 * * 00006 * This program is free software; you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation; either version 2 of the License, or * 00009 * (at your option) any later version. * 00010 * * 00011 ***************************************************************************/ 00012 00013 /* 00014 * The code is borrowed from Ogre-Engine. 00015 * Many of the ideas for the profiler were borrowed from 00016 * "Real-Time In-Game Profiling" by Steve Rabin which can be found in Game Programming 00017 * Gems 1. 00018 */ 00019 00020 #ifndef __NR_ENGINE_PROFILER_H_ 00021 #define __NR_ENGINE_PROFILER_H_ 00022 00023 //---------------------------------------------------------------------------------- 00024 // Includes 00025 //---------------------------------------------------------------------------------- 00026 #include "Prerequisities.h" 00027 #include "Log.h" 00028 00029 //---------------------------------------------------------------------------------- 00030 // Defines 00031 // 00032 // If you want to profile your application, so use these macros and define NR_PROFILING 00033 //---------------------------------------------------------------------------------- 00034 #ifdef NR_APP_PROFILING 00035 # define NR_Profile( a ) ::nrEngine::Profile __nr_profile_instance( (a), false ) 00036 # define NR_ProfileBegin( a ) ::nrEngine::Engine::sProfiler()->beginProfile( (a), false ) 00037 # define NR_ProfileEnd( a ) ::nrEngine::Engine::sProfiler()->endProfile( (a), false ) 00038 #else 00039 # define NR_Profile( a ) 00040 # define NR_ProfileBegin( a ) 00041 # define NR_ProfileEnd( a ) 00042 #endif 00043 00044 00045 00046 //---------------------------------------------------------------------------------- 00047 // This macros is used to profile the engine and not the application 00048 // Actually it is the same macro but here we separate the engine profiling from 00049 // application profiling, so the user can either enable or disable one of them 00050 //---------------------------------------------------------------------------------- 00051 #ifdef NR_ENGINE_PROFILING 00052 # define _nrEngineProfile( a ) Profile __nr_profile_instance( (a), true ) 00053 # define _nrEngineProfileBegin( a ) Engine::sProfiler()->beginProfile( (a), true ) 00054 # define _nrEngineProfileEnd( a ) Engine::sProfiler()->endProfile( (a), true ) 00055 #else 00056 # define _nrEngineProfile( a ) 00057 # define _nrEngineProfileBegin( a ) 00058 # define _nrEngineProfileEnd( a ) 00059 #endif 00060 00061 00062 namespace nrEngine{ 00063 00064 //! Single profile processed by the profiler 00065 /** 00066 * Our profiler does store such kind of profiles and manage them. 00067 * Use macro NR_Profile(name) instead of instantiating this objects 00068 * directly. <br> 00069 * Using of such kind of macros does help to profile a single scope: 00070 * i.e.: 00071 * <code> 00072 * { 00073 * NR_Profile("Scope"); 00074 * .... 00075 * } 00076 * </code> 00077 * \ingroup gp 00078 **/ 00079 class _NRExport Profile { 00080 public: 00081 00082 /** 00083 * Create an instance of this class and start profiling for this profile. 00084 **/ 00085 Profile(const std::string& name, bool isSystemProfile = false); 00086 00087 /** 00088 * Release used memory and stop the profiler for this profile. 00089 **/ 00090 ~Profile(); 00091 00092 private: 00093 00094 //! Name of the profile, must be unique 00095 std::string mName; 00096 00097 //! Is this is a system profile 00098 bool mSystemProfile; 00099 00100 }; 00101 00102 00103 //! The profiler allows you to measure the performance of your code 00104 /** 00105 * Profiler is a singleton object which is created by 00106 * initializing the engine. Profiler does use a time source provide 00107 * system time to allow to measure the time differencies.<br> 00108 * 00109 * Profiling is done stack wise. It means every time you starting 00110 * a profile it will go onto the stack. Every time the profile is ending 00111 * top most profile from the stack is removed and statistics is computed for it. 00112 * Every time the stack is empty we compute the whole statistics for each profiles. 00113 * The time in that the stack is not empty is called frame. We assume that you always 00114 * profiles framewise. 00115 * 00116 * \ingroup gp 00117 **/ 00118 class _NRExport Profiler { 00119 public: 00120 00121 /** 00122 * Begin of profiling. Please use NR_ProfileBegin(name) macro 00123 * instead of this function, so it can be removed in the release 00124 * version of you application 00125 * 00126 * \param name Unique name of the profile 00127 * \param isSystemProfile Define if the profile is build for the engine 00128 **/ 00129 void beginProfile(const std::string& name, bool isSystemProfile = false); 00130 00131 /** 00132 * End a profiling for the given profiling scope/name 00133 * Please use NR_ProfileEnd(name) macro instead of directly 00134 * calling this function. 00135 * 00136 * \param name Unique name of the profile 00137 * \param isSystemProfile Set to true if the profile is created for the engine 00138 **/ 00139 void endProfile(const std::string& name, bool isSystemProfile = false); 00140 00141 /** 00142 * Reset the profiler, so we clear all currently using 00143 * profilers. 00144 **/ 00145 void reset(); 00146 00147 /** 00148 * Log current profile statistics to the log 00149 **/ 00150 void logResults(Log::LogTarget lt = Log::LOG_APP); 00151 00152 /** 00153 * Enable the profiling 00154 **/ 00155 NR_FORCEINLINE void enable() { setEnable ( true ); } 00156 00157 /** 00158 * Disable profiling 00159 **/ 00160 NR_FORCEINLINE void disable(){ setEnable ( false ); } 00161 00162 /** 00163 * Is profiler enabled 00164 **/ 00165 NR_FORCEINLINE bool isEnabled() { return mEnabled; } 00166 00167 /** 00168 * Set profiler enable/disable state 00169 **/ 00170 void setEnable(bool enable); 00171 00172 /** 00173 * Enable or disable profiling of the system components. 00174 * If you enable this all engine components calling the profiler 00175 * will be counted in the statistics. Otherwise the engine 00176 * does not produce any profile information 00177 **/ 00178 NR_FORCEINLINE void setEnableEngineProfiling(bool e) { mEngineProfileEnabled = e;} 00179 00180 /** 00181 * Get information about engine profiling status. If true, so engine's 00182 * components are getting profiled. Otherwise no. 00183 **/ 00184 NR_FORCEINLINE bool isEnabledEngineProfiling() const { return mEngineProfileEnabled; } 00185 00186 private: 00187 00188 //! Only engine can create instance of profiler 00189 friend class Engine; 00190 00191 /** 00192 * Create a profiler object and use the given time source 00193 * to retrive the time. Engine will create the object 00194 * by itself and will specify a system time source object 00195 * instance for profiler using 00196 **/ 00197 Profiler(SharedPtr<TimeSource> timeSource); 00198 00199 /** 00200 * Virtual destructor of the profiler object that allows you 00201 * to derive your own profiler classes to overwrite some 00202 * methods of the defulat one 00203 **/ 00204 ~Profiler(); 00205 00206 //! Time source used to retrieve time 00207 SharedPtr<TimeSource> mTimeSource; 00208 00209 00210 //! Represents an individual profile call 00211 struct ProfileInstance { 00212 00213 //! The name of the profile 00214 std::string name; 00215 00216 //! The name of the parent, empty string if root 00217 std::string parent; 00218 00219 //! Define if the profile is a system profile 00220 bool isSystemProfile; 00221 00222 //! The time this profile was started 00223 float64 currTime; 00224 00225 //! Represents the total time of all child profiles to subtract from this profile 00226 float64 accum; 00227 00228 /// The hierarchical level of this profile, 0 being the root profile 00229 uint32 hierarchicalLvl; 00230 }; 00231 00232 //! Represents the total timing information of a profile since profiles can be called more than once each frame 00233 struct ProfileFrame { 00234 00235 //! The name of the profile 00236 std::string name; 00237 00238 //! The time this profile has taken this frame 00239 float64 frameTime; 00240 00241 //! The number of times this profile was called this frame 00242 uint32 calls; 00243 00244 //! The hierarchical level of this profile, 0 being the main loop 00245 uint32 hierarchicalLvl; 00246 00247 //! The total time incl. children this profile has taken this frame 00248 float64 frameTotalTime; 00249 00250 }; 00251 00252 //! Represents a history of each profile during the duration of the app 00253 struct ProfileHistory { 00254 00255 //! The name of the profile 00256 std::string name; 00257 00258 //! is system profile 00259 bool isSystemProfile; 00260 00261 //! The current percentage of frame time this profile has taken 00262 float32 currentTime; // % 00263 00264 //! The maximum percentage of frame time this profile has taken 00265 float32 maxTime; // % 00266 00267 //! The minimum percentage of frame time this profile has taken 00268 float32 minTime; // % 00269 00270 //! The number of times this profile has been called this frame 00271 uint32 numCallsThisFrame; 00272 00273 //! The total percentage of frame time this profile has taken (used to calculate average) 00274 float32 totalTime; // % 00275 00276 //! The total number of times this profile was called (used to calculate average) 00277 uint32 totalCalls; 00278 00279 //! The hierarchical level of this profile, 0 being the root profile 00280 uint32 hierarchicalLvl; 00281 00282 //! Time of the profile has taken for running 00283 float32 realTime; 00284 00285 //! Total time incl. children of the profile 00286 float32 realTotalTime; 00287 00288 //! Giving order on the profiles, to allows sorting 00289 bool operator <(const ProfileHistory& p); 00290 00291 }; 00292 00293 00294 typedef std::list<ProfileInstance> ProfileStack; 00295 typedef std::list<ProfileFrame> ProfileFrameList; 00296 typedef std::list<ProfileHistory> ProfileHistoryList; 00297 typedef std::map< std::string, ProfileHistoryList::iterator> ProfileHistoryMap; 00298 typedef std::map< std::string, bool> DisabledProfileMap; 00299 00300 //! A stack for each individual profile per frame 00301 ProfileStack mProfiles; 00302 00303 //! Accumulates the results of each profile per frame (since a profile can be called more than once a frame) 00304 ProfileFrameList mProfileFrame; 00305 00306 //! Keeps track of the statistics of each profile 00307 ProfileHistoryList mProfileHistory; 00308 00309 //! We use this for quick look-ups of profiles in the history list 00310 ProfileHistoryMap mProfileHistoryMap; 00311 00312 //! The total time each frame takes 00313 float64 mTotalFrameTime; 00314 00315 //! Wether we should profile the engine subsystem 00316 bool mEngineProfileEnabled; 00317 00318 //! Whether this profiler is enabled 00319 bool mEnabled; 00320 00321 //! Keeps track of whether this profiler has received a request to be enabled/disabled 00322 bool mEnableStateChangePending; 00323 00324 //! Keeps track of the new enabled/disabled state that the user has requested which will be applied after the frame ends 00325 bool mNewEnableState; 00326 00327 void processFrameStats(); 00328 void changeEnableState(); 00329 00330 void logLine(const char* name, float32 min, float32 max, float32 frameTime, float32 totalTime, uint32 totalCalls); 00331 00332 }; 00333 00334 }; // end namespace 00335 00336 #endif 00337