source: GTP/trunk/App/Demos/Geom/OgreStuff/include/OgreProfiler.h @ 1812

Revision 1812, 16.7 KB checked in by gumbau, 18 years ago (diff)
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25/*
26
27    Although the code is original, many of the ideas for the profiler were borrowed from
28"Real-Time In-Game Profiling" by Steve Rabin which can be found in Game Programming
29Gems 1.
30
31    This code can easily be adapted to your own non-Ogre project. The only code that is
32Ogre-dependent is in the visualization/logging routines and the use of the Timer class.
33
34    Enjoy!
35
36*/
37
38#ifndef __Profiler_H__
39#define __Profiler_H__
40
41#include "OgrePrerequisites.h"
42#include "OgreSingleton.h"
43#include "OgreString.h"
44#include "OgreOverlay.h"
45
46#if OGRE_PROFILING == 1
47#   if OGRE_COMPILER != OGRE_COMPILER_BORL
48#       define OgreProfile( a ) Ogre::Profile _OgreProfileInstance( (a) )
49#       define OgreProfileBegin( a ) Ogre::Profiler::getSingleton().beginProfile( (a) )
50#       define OgreProfileEnd( a ) Ogre::Profiler::getSingleton().endProfile( (a) )
51#   else
52#           define OgreProfile( a ) Ogre::Profile _OgreProfileInstance( __FUNC__ )
53#           define OgreProfileBegin( a ) Ogre::Profiler::getSingleton().beginProfile( __FUNC__ )
54#           define OgreProfileEnd( a ) Ogre::Profiler::getSingleton().endProfile( __FUNC__ )
55#   endif
56#else
57#   define OgreProfile( a )
58#   define OgreProfileBegin( a )
59#   define OgreProfileEnd( a )
60#endif
61
62namespace Ogre {
63
64    /** An individual profile that will be processed by the Profiler
65        @remarks
66            Use the macro OgreProfile(name) instead of instantiating this profile directly
67        @remarks
68            We use this Profile to allow scoping rules to signify the beginning and end of
69            the profile. Use the Profiler singleton (through the macro OgreProfileBegin(name)
70            and OgreProfileEnd(name)) directly if you want a profile to last
71            outside of a scope (ie the main game loop).
72        @author Amit Mathew (amitmathew (at) yahoo (dot) com)
73    */
74    class _OgreExport Profile {
75
76        public:
77            Profile(const String& profileName);
78            ~Profile();
79
80        protected:
81
82            /// The name of this profile
83            String mName;
84                       
85
86    };
87
88    /** The profiler allows you to measure the performance of your code
89        @remarks
90            Do not create profiles directly from this unless you want a profile to last
91            outside of its scope (ie the main game loop). For most cases, use the macro
92            OgreProfile(name) and braces to limit the scope. You must enable the Profile
93            before you can used it with setEnabled(true). If you want to disable profiling
94            in Ogre, simply set the macro OGRE_PROFILING to 0.
95        @author Amit Mathew (amitmathew (at) yahoo (dot) com)
96        @todo resolve artificial cap on number of profiles displayed
97        @todo fix display ordering of profiles not called every frame
98    */
99    class _OgreExport Profiler : public Singleton<Profiler> {
100
101        public:
102            Profiler();
103            ~Profiler();
104
105            /** Sets the timer for the profiler */
106            void setTimer(Timer* t);
107
108            /** Retrieves the timer for the profiler */
109            Timer* getTimer();
110
111            /** Begins a profile
112            @remarks
113                Use the macro OgreProfileBegin(name) instead of calling this directly
114                so that profiling can be ignored in the release version of your app.
115            @remarks
116                You only use the macro (or this) if you want a profile to last outside
117                of its scope (ie the main game loop). If you use this function, make sure you
118                use a corresponding OgreProfileEnd(name). Usually you would use the macro
119                OgreProfile(name). This function will be ignored for a profile that has been
120                disabled or if the profiler is disabled.
121            @param profileName Must be unique and must not be an empty string
122            */
123            void beginProfile(const String& profileName);
124
125            /** Ends a profile
126            @remarks
127                Use the macro OgreProfileEnd(name) instead of calling this directly so that
128                profiling can be ignored in the release version of your app.
129            @remarks
130                This function is usually not called directly unless you want a profile to
131                last outside of its scope. In most cases, using the macro OgreProfile(name)
132                which will call this function automatically when it goes out of scope. Make
133                sure the name of this profile matches its corresponding beginProfile name.
134                This function will be ignored for a profile that has been disabled or if the
135                profiler is disabled.
136            */
137            void endProfile(const String& profileName);
138
139            /** Sets whether this profiler is enabled. Only takes effect after the
140                the frame has ended.
141                @remarks When this is called the first time with the parameter true,
142                it initializes the GUI for the Profiler
143            */
144            void setEnabled(bool enabled);
145
146            /** Gets whether this profiler is enabled */
147            bool getEnabled() const;
148
149            /** Enables a previously disabled profile
150            @remarks Only enables the profile if this function is not
151            called during the profile it is trying to enable.
152            */
153            void enableProfile(const String& profileName);
154
155            /** Disables a profile
156            @remarks Only disables the profile if this function is not called during
157            the profile it is trying to disable.
158            */
159            void disableProfile(const String& profileName);
160
161            /** Returns true if the specified profile reaches a new frame time maximum
162            @remarks If this is called during a frame, it will be reading the results
163            from the previous frame. Therefore, it is best to use this after the frame
164            has ended.
165            */
166            bool watchForMax(const String& profileName);
167
168            /** Returns true if the specified profile reaches a new frame time minimum
169            @remarks If this is called during a frame, it will be reading the results
170            from the previous frame. Therefore, it is best to use this after the frame
171            has ended.
172            */
173            bool watchForMin(const String& profileName);
174
175            /** Returns true if the specified profile goes over or under the given limit
176                frame time
177            @remarks If this is called during a frame, it will be reading the results
178            from the previous frame. Therefore, it is best to use this after the frame
179            has ended.
180            @param limit A number between 0 and 1 representing the percentage of frame time
181            @param greaterThan If true, this will return whether the limit is exceeded. Otherwise,
182            it will return if the frame time has gone under this limit.
183            */
184            bool watchForLimit(const String& profileName, Real limit, bool greaterThan = true);
185
186            /** Outputs current profile statistics to the log */
187            void logResults();
188
189            /** Clears the profiler statistics */
190            void reset();
191
192            /** Sets the Profiler so the display of results are updated ever n frames*/
193            void setUpdateDisplayFrequency(uint freq);
194
195            /** Gets the frequency that the Profiler display is updated */
196            uint getUpdateDisplayFrequency() const;
197
198            /** Override standard Singleton retrieval.
199            @remarks
200            Why do we do this? Well, it's because the Singleton
201            implementation is in a .h file, which means it gets compiled
202            into anybody who includes it. This is needed for the
203            Singleton template to work, but we actually only want it
204            compiled into the implementation of the class based on the
205            Singleton, not all of them. If we don't change this, we get
206            link errors when trying to use the Singleton-based class from
207            an outside dll.
208            @par
209            This method just delegates to the template version anyway,
210            but the implementation stays in this single compilation unit,
211            preventing link errors.
212            */
213            static Profiler& getSingleton(void);
214            /** Override standard Singleton retrieval.
215            @remarks
216            Why do we do this? Well, it's because the Singleton
217            implementation is in a .h file, which means it gets compiled
218            into anybody who includes it. This is needed for the
219            Singleton template to work, but we actually only want it
220            compiled into the implementation of the class based on the
221            Singleton, not all of them. If we don't change this, we get
222            link errors when trying to use the Singleton-based class from
223            an outside dll.
224            @par
225            This method just delegates to the template version anyway,
226            but the implementation stays in this single compilation unit,
227            preventing link errors.
228            */
229            static Profiler* getSingletonPtr(void);
230
231        protected:
232
233            /** Initializes the profiler's gui elements */
234            void initialize();
235
236            /** Prints the profiling results of each frame */
237            void displayResults();
238
239            /** Processes the profiler data after each frame */
240            void processFrameStats();
241
242            /** Handles a change of the profiler's enabled state*/
243            void changeEnableState();
244
245            /** An internal function to create the container which will hold our display elements*/
246            OverlayContainer* createContainer();
247
248            /** An internal function to create a text area */
249            OverlayElement* createTextArea(const String& name, Real width, Real height, Real top, Real left,
250                                       uint fontSize, const String& caption, bool show = true);
251
252            /** An internal function to create a panel */
253            OverlayElement* createPanel(const String& name, Real width, Real height, Real top, Real left,
254                                    const String& materialName, bool show = true);
255
256            /// Represents an individual profile call
257            struct ProfileInstance {
258
259                /// The name of the profile
260                String          name;
261
262                /// The name of the parent, empty string if root
263                String          parent;
264
265                /// The time this profile was started
266                ulong           currTime;
267
268                /// Represents the total time of all child profiles to subtract
269                /// from this profile
270                ulong           accum;
271
272                /// The hierarchical level of this profile, 0 being the root profile
273                uint            hierarchicalLvl;
274            };
275
276            /// Represents the total timing information of a profile
277            /// since profiles can be called more than once each frame
278            struct ProfileFrame {
279                               
280                /// The name of the profile
281                String  name;
282
283                /// The total time this profile has taken this frame
284                ulong   frameTime;
285
286                /// The number of times this profile was called this frame
287                uint    calls;
288
289                /// The hierarchical level of this profile, 0 being the main loop
290                uint    hierarchicalLvl;
291
292            };
293                       
294            /// Represents a history of each profile during the duration of the app
295            struct ProfileHistory {
296
297                /// The name of the profile
298                String  name;
299
300                /// The current percentage of frame time this profile has taken
301                Real    currentTime; // %
302
303                /// The maximum percentage of frame time this profile has taken
304                Real    maxTime; // %
305
306                /// The minimum percentage of frame time this profile has taken
307                Real    minTime; // %
308
309                /// The number of times this profile has been called each frame
310                uint    numCallsThisFrame;
311
312                /// The total percentage of frame time this profile has taken
313                /// (used to calculate average)
314                Real    totalTime; // %
315
316                /// The total number of times this profile was called
317                /// (used to calculate average)
318                ulong   totalCalls; // %
319
320                /// The hierarchical level of this profile, 0 being the root profile
321                uint    hierarchicalLvl;
322
323                        };
324
325                       
326            typedef std::list<ProfileInstance> ProfileStack;
327            typedef std::list<ProfileFrame> ProfileFrameList;
328            typedef std::list<ProfileHistory> ProfileHistoryList;
329            typedef std::map<String, ProfileHistoryList::iterator> ProfileHistoryMap;
330            typedef std::map<String, bool> DisabledProfileMap;
331
332            typedef std::list<OverlayElement*> ProfileBarList;
333
334            /// A stack for each individual profile per frame
335            ProfileStack mProfiles;
336
337            /// Accumulates the results of each profile per frame (since a profile can be called
338            /// more than once a frame)
339            ProfileFrameList mProfileFrame;
340
341            /// Keeps track of the statistics of each profile
342            ProfileHistoryList mProfileHistory;
343
344            /// We use this for quick look-ups of profiles in the history list
345            ProfileHistoryMap mProfileHistoryMap;
346
347            /// Holds the names of disabled profiles
348            DisabledProfileMap mDisabledProfiles;
349
350            /// Holds the display bars for each profile results
351            ProfileBarList mProfileBars;
352
353            /// Whether the GUI elements have been initialized
354            bool mInitialized;
355
356            /// The max number of profiles we can display
357            uint maxProfiles;
358
359            /// The overlay which contains our profiler results display
360            Overlay* mOverlay;
361
362            /// The window that displays the profiler results
363            OverlayContainer* mProfileGui;
364
365            /// The height of each bar
366            Real mBarHeight;
367
368            /// The height of the stats window
369            Real mGuiHeight;
370
371            /// The width of the stats window
372            Real mGuiWidth;
373
374            /// The size of the indent for each profile display bar
375            Real mBarIndent;
376
377            /// The width of the border between the profile window and each bar
378            Real mGuiBorderWidth;
379
380            /// The width of the min, avg, and max lines in a profile display
381            Real mBarLineWidth;
382
383            /// The number of frames that must elapse before the current
384            /// frame display is updated
385            uint mUpdateDisplayFrequency;
386
387            /// The number of elasped frame, used with mUpdateDisplayFrequency
388            uint mCurrentFrame;
389
390            /// The timer used for profiling
391            Timer* mTimer;
392
393            /// The total time each frame takes
394            ulong mTotalFrameTime;
395
396            /// Whether this profiler is enabled
397            bool mEnabled;
398
399            /// Keeps track of whether this profiler has
400            /// received a request to be enabled/disabled
401            bool mEnableStateChangePending;
402
403            /// Keeps track of the new enabled/disabled state that the user has requested
404            /// which will be applied after the frame ends
405            bool mNewEnableState;
406
407    }; // end class
408
409} // end namespace
410
411#endif
Note: See TracBrowser for help on using the repository browser.