1 | /* |
---|
2 | ----------------------------------------------------------------------------- |
---|
3 | This source file is part of OGRE |
---|
4 | (Object-oriented Graphics Rendering Engine) |
---|
5 | For the latest info, see http://www.ogre3d.org/ |
---|
6 | |
---|
7 | Copyright (c) 2000-2006 Torus Knot Software Ltd |
---|
8 | Also see acknowledgements in Readme.html |
---|
9 | |
---|
10 | This program is free software; you can redistribute it and/or modify it under |
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
13 | version. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
18 | |
---|
19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
23 | |
---|
24 | You may alternatively use this source under the terms of a specific version of |
---|
25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
26 | Torus Knot Software Ltd. |
---|
27 | ----------------------------------------------------------------------------- |
---|
28 | */ |
---|
29 | #include "OgreStableHeaders.h" |
---|
30 | /* |
---|
31 | |
---|
32 | Although the code is original, many of the ideas for the profiler were borrowed from |
---|
33 | "Real-Time In-Game Profiling" by Steve Rabin which can be found in Game Programming |
---|
34 | Gems 1. |
---|
35 | |
---|
36 | This code can easily be adapted to your own non-Ogre project. The only code that is |
---|
37 | Ogre-dependent is in the visualization/logging routines and the use of the Timer class. |
---|
38 | |
---|
39 | Enjoy! |
---|
40 | |
---|
41 | */ |
---|
42 | |
---|
43 | #include "OgreProfiler.h" |
---|
44 | #include "OgreTimer.h" |
---|
45 | #include "OgreLogManager.h" |
---|
46 | #include "OgreStringConverter.h" |
---|
47 | #include "OgreOverlayManager.h" |
---|
48 | #include "OgreOverlayElement.h" |
---|
49 | #include "OgreOverlayContainer.h" |
---|
50 | |
---|
51 | namespace Ogre { |
---|
52 | //----------------------------------------------------------------------- |
---|
53 | // PROFILE DEFINITIONS |
---|
54 | //----------------------------------------------------------------------- |
---|
55 | template<> Profiler* Singleton<Profiler>::ms_Singleton = 0; |
---|
56 | Profiler* Profiler::getSingletonPtr(void) |
---|
57 | { |
---|
58 | return ms_Singleton; |
---|
59 | } |
---|
60 | Profiler& Profiler::getSingleton(void) |
---|
61 | { |
---|
62 | assert( ms_Singleton ); return ( *ms_Singleton ); |
---|
63 | } |
---|
64 | //----------------------------------------------------------------------- |
---|
65 | Profile::Profile(const String& profileName) { |
---|
66 | |
---|
67 | mName = profileName; |
---|
68 | |
---|
69 | Ogre::Profiler::getSingleton().beginProfile(profileName); |
---|
70 | |
---|
71 | } |
---|
72 | //----------------------------------------------------------------------- |
---|
73 | Profile::~Profile() { |
---|
74 | |
---|
75 | Ogre::Profiler::getSingleton().endProfile(mName); |
---|
76 | |
---|
77 | } |
---|
78 | //----------------------------------------------------------------------- |
---|
79 | |
---|
80 | |
---|
81 | //----------------------------------------------------------------------- |
---|
82 | // PROFILER DEFINITIONS |
---|
83 | //----------------------------------------------------------------------- |
---|
84 | Profiler::Profiler() { |
---|
85 | |
---|
86 | // init some variables |
---|
87 | mTimer = 0; |
---|
88 | mTotalFrameTime = 0; |
---|
89 | mUpdateDisplayFrequency = 0; |
---|
90 | mCurrentFrame = 0; |
---|
91 | mEnabled = mNewEnableState = false; // the profiler starts out as disabled |
---|
92 | mEnableStateChangePending = false; |
---|
93 | mInitialized = false; |
---|
94 | maxProfiles = 50; |
---|
95 | |
---|
96 | // by default the display will be updated every 10 frames |
---|
97 | mUpdateDisplayFrequency = 10; |
---|
98 | |
---|
99 | } |
---|
100 | //----------------------------------------------------------------------- |
---|
101 | Profiler::~Profiler() { |
---|
102 | |
---|
103 | if (!mProfileHistory.empty()) { |
---|
104 | // log the results of our profiling before we quit |
---|
105 | logResults(); |
---|
106 | } |
---|
107 | |
---|
108 | // clear all our lists |
---|
109 | mProfiles.clear(); |
---|
110 | mProfileFrame.clear(); |
---|
111 | mProfileHistoryMap.clear(); |
---|
112 | mProfileHistory.clear(); |
---|
113 | mDisabledProfiles.clear(); |
---|
114 | mProfileBars.clear(); |
---|
115 | |
---|
116 | } |
---|
117 | //----------------------------------------------------------------------- |
---|
118 | void Profiler::initialize() { |
---|
119 | |
---|
120 | // init some gui characteristics |
---|
121 | mBarHeight = 10; //0.02; |
---|
122 | mGuiBorderWidth = 10; //0.02; |
---|
123 | mGuiHeight = 25; //0.05; |
---|
124 | mGuiWidth = 250; //0.15; |
---|
125 | mBarIndent = mGuiWidth; |
---|
126 | mBarLineWidth = 2; |
---|
127 | |
---|
128 | // create a new overlay to hold our Profiler display |
---|
129 | mOverlay = OverlayManager::getSingleton().create("Profiler"); |
---|
130 | mOverlay->setZOrder(500); |
---|
131 | |
---|
132 | // this panel will be the main container for our profile bars |
---|
133 | mProfileGui = createContainer(); |
---|
134 | |
---|
135 | OverlayElement* element; |
---|
136 | |
---|
137 | // we create the little "ticks" above the profiles |
---|
138 | for (uint k = 1; k < 10; ++k) { // we don't want a tick at 0% or 100% |
---|
139 | |
---|
140 | if (k != 5) { // we don't want a tick at 50% |
---|
141 | element = createTextArea("ProfileKeyLine" + StringConverter::toString(k), 20, 10, 2, mGuiWidth * (1 + k * .1), 9, "|"); |
---|
142 | mProfileGui->addChild(element); |
---|
143 | } |
---|
144 | |
---|
145 | } |
---|
146 | |
---|
147 | // we create a 0% marker |
---|
148 | element = createTextArea("ProfileKey0", 50, 10, 2, mGuiWidth * 0.99, 9, "0%"); |
---|
149 | mProfileGui->addChild(element); |
---|
150 | |
---|
151 | // we create a 50% marker |
---|
152 | element = createTextArea("ProfileyKey50", 50, 10, 2, mGuiWidth * 1.48, 9, "50%"); |
---|
153 | mProfileGui->addChild(element); |
---|
154 | |
---|
155 | // we create a 100% marker |
---|
156 | element = createTextArea("ProfileKey100", 50, 10, 2, mGuiWidth * 1.98, 9, "100%"); |
---|
157 | mProfileGui->addChild(element); |
---|
158 | |
---|
159 | // we create an initial pool of 50 profile bars |
---|
160 | for (uint i = 0; i < maxProfiles; ++i) { |
---|
161 | |
---|
162 | // this is for the profile name and the number of times it was called in a frame |
---|
163 | element = createTextArea("profileText" + StringConverter::toString(i), 90, mBarHeight, mGuiBorderWidth + (mBarHeight * 2) * i, 0, 14, "", false); |
---|
164 | mProfileGui->addChild(element); |
---|
165 | mProfileBars.push_back(element); |
---|
166 | |
---|
167 | // this indicates the current frame time |
---|
168 | element = createPanel("currBar" + StringConverter::toString(i), 0, mBarHeight, mGuiBorderWidth + (mBarHeight * 2) * i, mBarIndent, "Core/ProfilerCurrent", false); |
---|
169 | mProfileGui->addChild(element); |
---|
170 | mProfileBars.push_back(element); |
---|
171 | |
---|
172 | // this indicates the minimum frame time |
---|
173 | element = createPanel("minBar" + StringConverter::toString(i), mBarLineWidth, mBarHeight, mGuiBorderWidth + (mBarHeight * 2) * i, 0, "Core/ProfilerMin", false); |
---|
174 | mProfileGui->addChild(element); |
---|
175 | mProfileBars.push_back(element); |
---|
176 | |
---|
177 | // this indicates the maximum frame time |
---|
178 | element = createPanel("maxBar" + StringConverter::toString(i), mBarLineWidth, mBarHeight, mGuiBorderWidth + (mBarHeight * 2) * i, 0, "Core/ProfilerMax", false); |
---|
179 | mProfileGui->addChild(element); |
---|
180 | mProfileBars.push_back(element); |
---|
181 | |
---|
182 | // this indicates the average frame time |
---|
183 | element = createPanel("avgBar" + StringConverter::toString(i), mBarLineWidth, mBarHeight, mGuiBorderWidth + (mBarHeight * 2) * i, 0, "Core/ProfilerAvg", false); |
---|
184 | mProfileGui->addChild(element); |
---|
185 | mProfileBars.push_back(element); |
---|
186 | |
---|
187 | } |
---|
188 | |
---|
189 | // throw everything all the GUI stuff into the overlay and display it |
---|
190 | mOverlay->add2D(mProfileGui); |
---|
191 | mOverlay->show(); |
---|
192 | |
---|
193 | } |
---|
194 | //----------------------------------------------------------------------- |
---|
195 | void Profiler::setTimer(Timer* t) { |
---|
196 | |
---|
197 | mTimer = t; |
---|
198 | |
---|
199 | } |
---|
200 | //----------------------------------------------------------------------- |
---|
201 | Timer* Profiler::getTimer() { |
---|
202 | |
---|
203 | assert(mTimer && "Timer not set!"); |
---|
204 | return mTimer; |
---|
205 | |
---|
206 | } |
---|
207 | //----------------------------------------------------------------------- |
---|
208 | void Profiler::setEnabled(bool enabled) { |
---|
209 | |
---|
210 | if (!mInitialized && enabled) { |
---|
211 | |
---|
212 | // the user wants to enable the Profiler for the first time |
---|
213 | // so we initialize the GUI stuff |
---|
214 | initialize(); |
---|
215 | mInitialized = true; |
---|
216 | mEnabled = true; |
---|
217 | |
---|
218 | } |
---|
219 | else { |
---|
220 | // We store this enable/disable request until the frame ends |
---|
221 | // (don't want to screw up any open profiles!) |
---|
222 | mEnableStateChangePending = true; |
---|
223 | mNewEnableState = enabled; |
---|
224 | } |
---|
225 | |
---|
226 | } |
---|
227 | //----------------------------------------------------------------------- |
---|
228 | bool Profiler::getEnabled() const { |
---|
229 | |
---|
230 | return mEnabled; |
---|
231 | |
---|
232 | } |
---|
233 | //----------------------------------------------------------------------- |
---|
234 | void Profiler::disableProfile(const String& profileName) { |
---|
235 | |
---|
236 | // make sure the profile isn't already disabled |
---|
237 | DisabledProfileMap::iterator iter; |
---|
238 | iter = mDisabledProfiles.find(profileName); |
---|
239 | |
---|
240 | // make sure you don't disable a profile in the middle of that profile |
---|
241 | ProfileStack::iterator pIter; |
---|
242 | for (pIter = mProfiles.begin(); pIter != mProfiles.end(); ++pIter) { |
---|
243 | |
---|
244 | if (profileName == (*pIter).name) |
---|
245 | break; |
---|
246 | |
---|
247 | } |
---|
248 | |
---|
249 | // if those two conditions are met, disable the profile |
---|
250 | if ( (iter == mDisabledProfiles.end()) && (pIter == mProfiles.end()) ) { |
---|
251 | |
---|
252 | mDisabledProfiles.insert(std::pair<String, bool>(profileName, true)); |
---|
253 | |
---|
254 | } |
---|
255 | |
---|
256 | } |
---|
257 | //----------------------------------------------------------------------- |
---|
258 | void Profiler::enableProfile(const String& profileName) { |
---|
259 | |
---|
260 | // make sure the profile is actually disabled |
---|
261 | DisabledProfileMap::iterator iter; |
---|
262 | iter = mDisabledProfiles.find(profileName); |
---|
263 | |
---|
264 | // make sure you don't enable a profile in the middle of that profile |
---|
265 | ProfileStack::iterator pIter; |
---|
266 | for (pIter = mProfiles.begin(); pIter != mProfiles.end(); ++pIter) { |
---|
267 | |
---|
268 | if (profileName == (*pIter).name) |
---|
269 | break; |
---|
270 | |
---|
271 | } |
---|
272 | |
---|
273 | // if those two conditions are met, enable the profile by removing it from |
---|
274 | // the disabled list |
---|
275 | if ( (iter != mDisabledProfiles.end()) && (pIter == mProfiles.end()) ) { |
---|
276 | |
---|
277 | mDisabledProfiles.erase(iter); |
---|
278 | |
---|
279 | } |
---|
280 | |
---|
281 | } |
---|
282 | //----------------------------------------------------------------------- |
---|
283 | void Profiler::beginProfile(const String& profileName) { |
---|
284 | |
---|
285 | // if the profiler is enabled |
---|
286 | if (!mEnabled) { |
---|
287 | |
---|
288 | return; |
---|
289 | |
---|
290 | } |
---|
291 | |
---|
292 | // empty string is reserved for the root |
---|
293 | assert ((profileName != "") && ("Profile name can't be an empty string")); |
---|
294 | |
---|
295 | ProfileStack::iterator iter; |
---|
296 | for (iter = mProfiles.begin(); iter != mProfiles.end(); ++iter) { |
---|
297 | |
---|
298 | if ((*iter).name == profileName) { |
---|
299 | |
---|
300 | break; |
---|
301 | |
---|
302 | } |
---|
303 | |
---|
304 | } |
---|
305 | |
---|
306 | // make sure this profile isn't being used more than once |
---|
307 | assert ((iter == mProfiles.end()) && ("This profile name is already being used")); |
---|
308 | |
---|
309 | // we only process this profile if isn't disabled |
---|
310 | DisabledProfileMap::iterator dIter; |
---|
311 | dIter = mDisabledProfiles.find(profileName); |
---|
312 | if ( dIter != mDisabledProfiles.end() ) { |
---|
313 | |
---|
314 | return; |
---|
315 | |
---|
316 | } |
---|
317 | |
---|
318 | ProfileInstance p; |
---|
319 | p.hierarchicalLvl = static_cast<uint>(mProfiles.size()); |
---|
320 | |
---|
321 | // this is the root, it has no parent |
---|
322 | if (mProfiles.empty()) { |
---|
323 | |
---|
324 | p.parent = ""; |
---|
325 | |
---|
326 | } |
---|
327 | // otherwise peek at the stack and use the top as the parent |
---|
328 | else { |
---|
329 | |
---|
330 | ProfileInstance parent = mProfiles.back(); |
---|
331 | p.parent = parent.name; |
---|
332 | |
---|
333 | } |
---|
334 | |
---|
335 | // need a timer to profile! |
---|
336 | assert (mTimer && "Timer not set!"); |
---|
337 | |
---|
338 | ProfileFrameList::iterator fIter; |
---|
339 | ProfileHistoryList::iterator hIter; |
---|
340 | |
---|
341 | // we check to see if this profile has been called in the frame before |
---|
342 | for (fIter = mProfileFrame.begin(); fIter != mProfileFrame.end(); ++fIter) { |
---|
343 | |
---|
344 | if ((*fIter).name == profileName) |
---|
345 | break; |
---|
346 | |
---|
347 | } |
---|
348 | // if it hasn't been called before, set its position in the stack |
---|
349 | if (fIter == mProfileFrame.end()) { |
---|
350 | |
---|
351 | ProfileFrame f; |
---|
352 | f.name = profileName; |
---|
353 | f.frameTime = 0; |
---|
354 | f.calls = 0; |
---|
355 | f.hierarchicalLvl = (uint) mProfiles.size(); |
---|
356 | mProfileFrame.push_back(f); |
---|
357 | |
---|
358 | } |
---|
359 | |
---|
360 | // we check to see if this profile has been called in the app before |
---|
361 | ProfileHistoryMap::iterator histMapIter; |
---|
362 | histMapIter = mProfileHistoryMap.find(profileName); |
---|
363 | |
---|
364 | // if not we add a profile with just the name into the history |
---|
365 | if (histMapIter == mProfileHistoryMap.end()) { |
---|
366 | |
---|
367 | ProfileHistory h; |
---|
368 | h.name = profileName; |
---|
369 | h.numCallsThisFrame = 0; |
---|
370 | h.totalTime = 0; |
---|
371 | h.totalCalls = 0; |
---|
372 | h.maxTime = 0; |
---|
373 | h.minTime = 1; |
---|
374 | h.hierarchicalLvl = p.hierarchicalLvl; |
---|
375 | h.currentTime = 0; |
---|
376 | |
---|
377 | // we add this to the history |
---|
378 | hIter = mProfileHistory.insert(mProfileHistory.end(), h); |
---|
379 | |
---|
380 | // for quick look-ups, we'll add it to the history map as well |
---|
381 | mProfileHistoryMap.insert(std::pair<String, ProfileHistoryList::iterator>(profileName, hIter)); |
---|
382 | |
---|
383 | } |
---|
384 | |
---|
385 | // add the stats to this profile and push it on the stack |
---|
386 | // we do this at the very end of the function to get the most |
---|
387 | // accurate timing results |
---|
388 | p.name = profileName; |
---|
389 | p.currTime = mTimer->getMicroseconds(); |
---|
390 | p.accum = 0; |
---|
391 | mProfiles.push_back(p); |
---|
392 | |
---|
393 | } |
---|
394 | //----------------------------------------------------------------------- |
---|
395 | void Profiler::endProfile(const String& profileName) { |
---|
396 | |
---|
397 | // if the profiler received a request to be enabled or disabled |
---|
398 | // we reached the end of the frame so we can safely do this |
---|
399 | if (mEnableStateChangePending) { |
---|
400 | |
---|
401 | changeEnableState(); |
---|
402 | |
---|
403 | } |
---|
404 | |
---|
405 | // if the profiler is enabled |
---|
406 | if(!mEnabled) { |
---|
407 | |
---|
408 | return; |
---|
409 | |
---|
410 | } |
---|
411 | |
---|
412 | // need a timer to profile! |
---|
413 | assert (mTimer && "Timer not set!"); |
---|
414 | |
---|
415 | // get the end time of this profile |
---|
416 | // we do this as close the beginning of this function as possible |
---|
417 | // to get more accurate timing results |
---|
418 | ulong endTime = mTimer->getMicroseconds(); |
---|
419 | |
---|
420 | // empty string is reserved for designating an empty parent |
---|
421 | assert ((profileName != "") && ("Profile name can't be an empty string")); |
---|
422 | |
---|
423 | // we only process this profile if isn't disabled |
---|
424 | DisabledProfileMap::iterator dIter; |
---|
425 | dIter = mDisabledProfiles.find(profileName); |
---|
426 | if ( dIter != mDisabledProfiles.end() ) { |
---|
427 | |
---|
428 | return; |
---|
429 | |
---|
430 | } |
---|
431 | |
---|
432 | // stack shouldnt be empty |
---|
433 | assert (!mProfiles.empty()); |
---|
434 | |
---|
435 | // get the start of this profile |
---|
436 | ProfileInstance bProfile; |
---|
437 | bProfile = mProfiles.back(); |
---|
438 | mProfiles.pop_back(); |
---|
439 | |
---|
440 | // calculate the elapsed time of this profile |
---|
441 | ulong timeElapsed = endTime - bProfile.currTime; |
---|
442 | |
---|
443 | // update parent's accumalator if it isn't the root |
---|
444 | if (bProfile.parent != "") { |
---|
445 | |
---|
446 | // find the parent |
---|
447 | ProfileStack::iterator iter; |
---|
448 | for(iter = mProfiles.begin(); iter != mProfiles.end(); ++iter) { |
---|
449 | |
---|
450 | if ((*iter).name == bProfile.parent) |
---|
451 | break; |
---|
452 | |
---|
453 | } |
---|
454 | |
---|
455 | // the parent should be found |
---|
456 | assert(iter != mProfiles.end()); |
---|
457 | |
---|
458 | // add this profile's time to the parent's accumlator |
---|
459 | (*iter).accum += timeElapsed; |
---|
460 | |
---|
461 | } |
---|
462 | |
---|
463 | // we find the profile in this frame |
---|
464 | ProfileFrameList::iterator iter; |
---|
465 | for (iter = mProfileFrame.begin(); iter != mProfileFrame.end(); ++iter) { |
---|
466 | |
---|
467 | if ((*iter).name == bProfile.name) |
---|
468 | break; |
---|
469 | |
---|
470 | } |
---|
471 | |
---|
472 | // we subtract the time the children profiles took from this profile |
---|
473 | (*iter).frameTime += timeElapsed - bProfile.accum; |
---|
474 | (*iter).calls++; |
---|
475 | |
---|
476 | // the stack is empty and all the profiles have been completed |
---|
477 | // we have reached the end of the frame so process the frame statistics |
---|
478 | if (mProfiles.empty()) { |
---|
479 | |
---|
480 | // we know that the time elapsed of the main loop is the total time the frame took |
---|
481 | mTotalFrameTime = timeElapsed; |
---|
482 | |
---|
483 | // we got all the information we need, so process the profiles |
---|
484 | // for this frame |
---|
485 | processFrameStats(); |
---|
486 | |
---|
487 | // clear the frame stats for next frame |
---|
488 | mProfileFrame.clear(); |
---|
489 | |
---|
490 | // we display everything to the screen |
---|
491 | displayResults(); |
---|
492 | |
---|
493 | } |
---|
494 | |
---|
495 | } |
---|
496 | //----------------------------------------------------------------------- |
---|
497 | void Profiler::processFrameStats() { |
---|
498 | |
---|
499 | ProfileFrameList::iterator frameIter; |
---|
500 | ProfileHistoryList::iterator historyIter; |
---|
501 | |
---|
502 | // we set the number of times each profile was called per frame to 0 |
---|
503 | // because not all profiles are called every frame |
---|
504 | for (historyIter = mProfileHistory.begin(); historyIter != mProfileHistory.end(); ++historyIter) { |
---|
505 | |
---|
506 | (*historyIter).numCallsThisFrame = 0; |
---|
507 | |
---|
508 | } |
---|
509 | |
---|
510 | // iterate through each of the profiles processed during this frame |
---|
511 | for (frameIter = mProfileFrame.begin(); frameIter != mProfileFrame.end(); ++frameIter) { |
---|
512 | |
---|
513 | String s = (*frameIter).name; |
---|
514 | |
---|
515 | // use our map to find the appropriate profile in the history |
---|
516 | historyIter = (*mProfileHistoryMap.find(s)).second; |
---|
517 | |
---|
518 | // extract the frame stats |
---|
519 | ulong frameTime = (*frameIter).frameTime; |
---|
520 | uint calls = (*frameIter).calls; |
---|
521 | uint lvl = (*frameIter).hierarchicalLvl; |
---|
522 | |
---|
523 | // calculate what percentage of frame time this profile took |
---|
524 | Real framePercentage = (Real) frameTime / (Real) mTotalFrameTime; |
---|
525 | |
---|
526 | // update the profile stats |
---|
527 | (*historyIter).currentTime = framePercentage; |
---|
528 | (*historyIter).totalTime += framePercentage; |
---|
529 | (*historyIter).totalCalls++; |
---|
530 | (*historyIter).numCallsThisFrame = calls; |
---|
531 | (*historyIter).hierarchicalLvl = lvl; |
---|
532 | |
---|
533 | // if we find a new minimum for this profile, update it |
---|
534 | if ((framePercentage) < ((*historyIter).minTime)) { |
---|
535 | |
---|
536 | (*historyIter).minTime = framePercentage; |
---|
537 | |
---|
538 | } |
---|
539 | |
---|
540 | // if we find a new maximum for this profile, update it |
---|
541 | if ((framePercentage) > ((*historyIter).maxTime)) { |
---|
542 | |
---|
543 | (*historyIter).maxTime = framePercentage; |
---|
544 | |
---|
545 | } |
---|
546 | |
---|
547 | } |
---|
548 | |
---|
549 | } |
---|
550 | //----------------------------------------------------------------------- |
---|
551 | void Profiler::displayResults() { |
---|
552 | |
---|
553 | if (!mEnabled) { |
---|
554 | |
---|
555 | return; |
---|
556 | |
---|
557 | } |
---|
558 | |
---|
559 | // if its time to update the display |
---|
560 | if (mCurrentFrame >= mUpdateDisplayFrequency) { |
---|
561 | |
---|
562 | mCurrentFrame = 0; |
---|
563 | |
---|
564 | ProfileHistoryList::iterator iter; |
---|
565 | ProfileBarList::iterator bIter; |
---|
566 | |
---|
567 | OverlayElement* g; |
---|
568 | |
---|
569 | Real newGuiHeight = mGuiHeight; |
---|
570 | |
---|
571 | int temp = 0; // dummy variable for weird Ogre issue |
---|
572 | |
---|
573 | // go through each profile and display it |
---|
574 | for (iter = mProfileHistory.begin(), bIter = mProfileBars.begin(); |
---|
575 | iter != mProfileHistory.end() && bIter != mProfileBars.end(); |
---|
576 | ++iter, ++bIter) |
---|
577 | { |
---|
578 | |
---|
579 | // display the profile's name and the number of times it was called in a frame |
---|
580 | g = *bIter; |
---|
581 | g->show(); |
---|
582 | g->setCaption(String((*iter).name + " (" + StringConverter::toString((*iter).numCallsThisFrame) + ")")); |
---|
583 | g->setLeft(10 + (*iter).hierarchicalLvl * 15); |
---|
584 | |
---|
585 | // display the main bar that show the percentage of the frame time that this |
---|
586 | // profile has taken |
---|
587 | bIter++; |
---|
588 | g = *bIter; |
---|
589 | g->show(); |
---|
590 | // most of this junk has been set before, but we do this to get around a weird |
---|
591 | // Ogre gui issue (bug?) |
---|
592 | g->setMetricsMode(GMM_PIXELS); |
---|
593 | g->setHeight(mBarHeight); |
---|
594 | g->setWidth(((*iter).currentTime) * mGuiWidth); |
---|
595 | g->setLeft(mGuiWidth); |
---|
596 | g->setTop(mGuiBorderWidth + temp * mBarHeight * 2); |
---|
597 | |
---|
598 | // display line to indicate the minimum frame time for this profile |
---|
599 | bIter++; |
---|
600 | g = *bIter; |
---|
601 | g->show(); |
---|
602 | g->setLeft(mBarIndent + (*iter).minTime * mGuiWidth); |
---|
603 | |
---|
604 | // display line to indicate the maximum frame time for this profile |
---|
605 | bIter++; |
---|
606 | g = *bIter; |
---|
607 | g->show(); |
---|
608 | g->setLeft(mBarIndent + (*iter).maxTime * mGuiWidth); |
---|
609 | |
---|
610 | // display line to indicate the average frame time for this profile |
---|
611 | bIter++; |
---|
612 | g = *bIter; |
---|
613 | g->show(); |
---|
614 | if ((*iter).totalCalls != 0) |
---|
615 | g->setLeft(mBarIndent + ((*iter).totalTime / (*iter).totalCalls) * mGuiWidth); |
---|
616 | else |
---|
617 | g->setLeft(mBarIndent); |
---|
618 | // we set the height of the display with respect to the number of profiles displayed |
---|
619 | newGuiHeight += mBarHeight * 2; |
---|
620 | |
---|
621 | temp++; |
---|
622 | |
---|
623 | } |
---|
624 | |
---|
625 | // set the main display dimensions |
---|
626 | mProfileGui->setMetricsMode(GMM_PIXELS); |
---|
627 | mProfileGui->setHeight(newGuiHeight); |
---|
628 | mProfileGui->setWidth(mGuiWidth * 2 + 15); |
---|
629 | mProfileGui->setTop(5); |
---|
630 | mProfileGui->setLeft(5); |
---|
631 | |
---|
632 | // we hide all the remaining pre-created bars |
---|
633 | for (; bIter != mProfileBars.end(); ++bIter) { |
---|
634 | |
---|
635 | (*bIter)->hide(); |
---|
636 | |
---|
637 | } |
---|
638 | |
---|
639 | } |
---|
640 | |
---|
641 | // not time to update the display yet |
---|
642 | else { |
---|
643 | |
---|
644 | mCurrentFrame++; |
---|
645 | |
---|
646 | } |
---|
647 | |
---|
648 | } |
---|
649 | //----------------------------------------------------------------------- |
---|
650 | bool Profiler::watchForMax(const String& profileName) { |
---|
651 | |
---|
652 | ProfileHistoryMap::iterator mapIter; |
---|
653 | ProfileHistoryList::iterator iter; |
---|
654 | |
---|
655 | mapIter = mProfileHistoryMap.find(profileName); |
---|
656 | |
---|
657 | // if we don't find the profile, return false |
---|
658 | if (mapIter == mProfileHistoryMap.end()) |
---|
659 | return false; |
---|
660 | |
---|
661 | iter = (*mapIter).second; |
---|
662 | |
---|
663 | return ((*iter).currentTime == (*iter).maxTime); |
---|
664 | |
---|
665 | } |
---|
666 | //----------------------------------------------------------------------- |
---|
667 | bool Profiler::watchForMin(const String& profileName) { |
---|
668 | |
---|
669 | ProfileHistoryMap::iterator mapIter; |
---|
670 | ProfileHistoryList::iterator iter; |
---|
671 | |
---|
672 | mapIter = mProfileHistoryMap.find(profileName); |
---|
673 | |
---|
674 | // if we don't find the profile, return false |
---|
675 | if (mapIter == mProfileHistoryMap.end()) |
---|
676 | return false; |
---|
677 | |
---|
678 | iter = (*mapIter).second; |
---|
679 | |
---|
680 | return ((*iter).currentTime == (*iter).minTime); |
---|
681 | |
---|
682 | } |
---|
683 | //----------------------------------------------------------------------- |
---|
684 | bool Profiler::watchForLimit(const String& profileName, Real limit, bool greaterThan) { |
---|
685 | |
---|
686 | ProfileHistoryMap::iterator mapIter; |
---|
687 | ProfileHistoryList::iterator iter; |
---|
688 | |
---|
689 | mapIter = mProfileHistoryMap.find(profileName); |
---|
690 | |
---|
691 | // if we don't find the profile, return false |
---|
692 | if (mapIter == mProfileHistoryMap.end()) |
---|
693 | return false; |
---|
694 | |
---|
695 | iter = (*mapIter).second; |
---|
696 | |
---|
697 | if (greaterThan) |
---|
698 | return ((*iter).currentTime > limit); |
---|
699 | else |
---|
700 | return ((*iter).currentTime < limit); |
---|
701 | |
---|
702 | } |
---|
703 | //----------------------------------------------------------------------- |
---|
704 | void Profiler::logResults() { |
---|
705 | |
---|
706 | ProfileHistoryList::iterator iter; |
---|
707 | |
---|
708 | LogManager::getSingleton().logMessage("----------------------Profiler Results----------------------"); |
---|
709 | |
---|
710 | for (iter = mProfileHistory.begin(); iter != mProfileHistory.end(); ++iter) { |
---|
711 | |
---|
712 | // create an indent that represents the hierarchical order of the profile |
---|
713 | String indent = ""; |
---|
714 | for (uint i = 0; i < (*iter).hierarchicalLvl; ++i) { |
---|
715 | |
---|
716 | indent = indent + " "; |
---|
717 | |
---|
718 | } |
---|
719 | |
---|
720 | LogManager::getSingleton().logMessage(indent + "Name " + (*iter).name + " | Min " + StringConverter::toString((*iter).minTime) + " | Max " + StringConverter::toString((*iter).maxTime) + " | Avg "+ StringConverter::toString((*iter).totalTime / (*iter).totalCalls)); |
---|
721 | |
---|
722 | } |
---|
723 | |
---|
724 | LogManager::getSingleton().logMessage("------------------------------------------------------------"); |
---|
725 | |
---|
726 | } |
---|
727 | //----------------------------------------------------------------------- |
---|
728 | void Profiler::reset() { |
---|
729 | |
---|
730 | ProfileHistoryList::iterator iter; |
---|
731 | for (iter = mProfileHistory.begin(); iter != mProfileHistory.end(); ++iter) { |
---|
732 | |
---|
733 | (*iter).currentTime = (*iter).maxTime = (*iter).totalTime = 0; |
---|
734 | (*iter).numCallsThisFrame = (*iter).totalCalls = 0; |
---|
735 | |
---|
736 | (*iter).minTime = 1; |
---|
737 | |
---|
738 | } |
---|
739 | |
---|
740 | } |
---|
741 | //----------------------------------------------------------------------- |
---|
742 | void Profiler::setUpdateDisplayFrequency(uint freq) { |
---|
743 | |
---|
744 | mUpdateDisplayFrequency = freq; |
---|
745 | |
---|
746 | } |
---|
747 | //----------------------------------------------------------------------- |
---|
748 | uint Profiler::getUpdateDisplayFrequency() const { |
---|
749 | |
---|
750 | return mUpdateDisplayFrequency; |
---|
751 | |
---|
752 | } |
---|
753 | //----------------------------------------------------------------------- |
---|
754 | void Profiler::changeEnableState() { |
---|
755 | |
---|
756 | if (mNewEnableState) { |
---|
757 | |
---|
758 | mOverlay->show(); |
---|
759 | |
---|
760 | } |
---|
761 | else { |
---|
762 | |
---|
763 | mOverlay->hide(); |
---|
764 | |
---|
765 | } |
---|
766 | mEnabled = mNewEnableState; |
---|
767 | mEnableStateChangePending = false; |
---|
768 | |
---|
769 | } |
---|
770 | //----------------------------------------------------------------------- |
---|
771 | OverlayContainer* Profiler::createContainer() { |
---|
772 | |
---|
773 | OverlayContainer* container = (OverlayContainer*) |
---|
774 | OverlayManager::getSingleton().createOverlayElement( |
---|
775 | "BorderPanel", "profiler"); |
---|
776 | container->setMetricsMode(GMM_PIXELS); |
---|
777 | container->setMaterialName("Core/StatsBlockCenter"); |
---|
778 | container->setHeight(mGuiHeight); |
---|
779 | container->setWidth(mGuiWidth * 2 + 15); |
---|
780 | container->setParameter("border_size", "1 1 1 1"); |
---|
781 | container->setParameter("border_material", "Core/StatsBlockBorder"); |
---|
782 | container->setParameter("border_topleft_uv", "0.0000 1.0000 0.0039 0.9961"); |
---|
783 | container->setParameter("border_top_uv", "0.0039 1.0000 0.9961 0.9961"); |
---|
784 | container->setParameter("border_topright_uv", "0.9961 1.0000 1.0000 0.9961"); |
---|
785 | container->setParameter("border_left_uv","0.0000 0.9961 0.0039 0.0039"); |
---|
786 | container->setParameter("border_right_uv","0.9961 0.9961 1.0000 0.0039"); |
---|
787 | container->setParameter("border_bottomleft_uv","0.0000 0.0039 0.0039 0.0000"); |
---|
788 | container->setParameter("border_bottom_uv","0.0039 0.0039 0.9961 0.0000"); |
---|
789 | container->setParameter("border_bottomright_uv","0.9961 0.0039 1.0000 0.0000"); |
---|
790 | container->setLeft(5); |
---|
791 | container->setTop(5); |
---|
792 | |
---|
793 | return container; |
---|
794 | |
---|
795 | } |
---|
796 | //----------------------------------------------------------------------- |
---|
797 | OverlayElement* Profiler::createTextArea(const String& name, Real width, Real height, Real top, Real left, |
---|
798 | uint fontSize, const String& caption, bool show) { |
---|
799 | |
---|
800 | |
---|
801 | OverlayElement* textArea = |
---|
802 | OverlayManager::getSingleton().createOverlayElement("TextArea", name); |
---|
803 | textArea->setMetricsMode(GMM_PIXELS); |
---|
804 | textArea->setWidth(width); |
---|
805 | textArea->setHeight(height); |
---|
806 | textArea->setTop(top); |
---|
807 | textArea->setLeft(left); |
---|
808 | textArea->setParameter("font_name", "BlueHighway"); |
---|
809 | textArea->setParameter("char_height", StringConverter::toString(fontSize)); |
---|
810 | textArea->setCaption(caption); |
---|
811 | textArea->setParameter("colour_top", "1 1 1"); |
---|
812 | textArea->setParameter("colour_bottom", "1 1 1"); |
---|
813 | |
---|
814 | if (show) { |
---|
815 | textArea->show(); |
---|
816 | } |
---|
817 | else { |
---|
818 | textArea->hide(); |
---|
819 | } |
---|
820 | |
---|
821 | return textArea; |
---|
822 | |
---|
823 | } |
---|
824 | //----------------------------------------------------------------------- |
---|
825 | OverlayElement* Profiler::createPanel(const String& name, Real width, Real height, Real top, Real left, |
---|
826 | const String& materialName, bool show) { |
---|
827 | |
---|
828 | OverlayElement* panel = |
---|
829 | OverlayManager::getSingleton().createOverlayElement("Panel", name); |
---|
830 | panel->setMetricsMode(GMM_PIXELS); |
---|
831 | panel->setWidth(width); |
---|
832 | panel->setHeight(height); |
---|
833 | panel->setTop(top); |
---|
834 | panel->setLeft(left); |
---|
835 | panel->setMaterialName(materialName); |
---|
836 | |
---|
837 | if (show) { |
---|
838 | panel->show(); |
---|
839 | } |
---|
840 | else { |
---|
841 | panel->hide(); |
---|
842 | } |
---|
843 | |
---|
844 | return panel; |
---|
845 | |
---|
846 | } |
---|
847 | //----------------------------------------------------------------------- |
---|
848 | |
---|
849 | } |
---|