Profiler.h

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 

Generated on Wed Sep 12 23:19:42 2007 for nrEngine by  doxygen 1.5.1