//----------------------------------------------------------------------- void Profiler::processFrameStats(void) { Real maxFrameTime = 0; ProfileChildren::iterator it = mRoot.children.begin(), endit = mRoot.children.end(); for(;it != endit; ++it) { ProfileInstance* child = it->second; // we set the number of times each profile was called per frame to 0 // because not all profiles are called every frame child->history.numCallsThisFrame = 0; if(child->frame.calls > 0) { processFrameStats(child, maxFrameTime); } } // Calculate whether the extents are now so out of date they need regenerating if (mCurrentFrame == 0) mAverageFrameTime = maxFrameTime; else mAverageFrameTime = (mAverageFrameTime + maxFrameTime) * 0.5f; if ((Real)mMaxTotalFrameTime > mAverageFrameTime * 4) { mResetExtents = true; mMaxTotalFrameTime = (ulong)mAverageFrameTime; } else mResetExtents = false; }
//----------------------------------------------------------------------- void Profiler::processFrameStats(ProfileInstance* instance, Real& maxFrameTime) { // calculate what percentage of frame time this profile took const Real framePercentage = (Real) instance->frame.frameTime / (Real) mTotalFrameTime; const Real frameTimeMillisecs = (Real) instance->frame.frameTime / 1000.0f; // update the profile stats instance->history.currentTimePercent = framePercentage; instance->history.currentTimeMillisecs = frameTimeMillisecs; if(mResetExtents) { instance->history.totalTimePercent = framePercentage; instance->history.totalTimeMillisecs = frameTimeMillisecs; instance->history.totalCalls = 1; } else { instance->history.totalTimePercent += framePercentage; instance->history.totalTimeMillisecs += frameTimeMillisecs; instance->history.totalCalls++; } instance->history.numCallsThisFrame = instance->frame.calls; // if we find a new minimum for this profile, update it if (frameTimeMillisecs < instance->history.minTimeMillisecs || mResetExtents) { instance->history.minTimePercent = framePercentage; instance->history.minTimeMillisecs = frameTimeMillisecs; } // if we find a new maximum for this profile, update it if (frameTimeMillisecs > instance->history.maxTimeMillisecs || mResetExtents) { instance->history.maxTimePercent = framePercentage; instance->history.maxTimeMillisecs = frameTimeMillisecs; } if(instance->frame.frameTime > maxFrameTime) maxFrameTime = (Real)instance->frame.frameTime; ProfileChildren::iterator it = instance->children.begin(), endit = instance->children.end(); for(;it != endit; ++it) { ProfileInstance* child = it->second; // we set the number of times each profile was called per frame to 0 // because not all profiles are called every frame child->history.numCallsThisFrame = 0; if(child->frame.calls > 0) { processFrameStats(child, maxFrameTime); } } }
//----------------------------------------------------------------------- void Profiler::endProfile(const String& profileName, uint32 groupID) { // if the profiler received a request to be enabled or disabled // we reached the end of the frame so we can safely do this if (mEnableStateChangePending) { changeEnableState(); } // if the profiler is enabled if(!mEnabled) { return; } // mask groups if ((groupID & mProfileMask) == 0) { return; } // we only process this profile if isn't disabled DisabledProfileMap::iterator dIter; dIter = mDisabledProfiles.find(profileName); if ( dIter != mDisabledProfiles.end() ) { return; } // need a timer to profile! assert (mTimer && "Timer not set!"); // get the end time of this profile // we do this as close the beginning of this function as possible // to get more accurate timing results ulong endTime = mTimer->getMicroseconds(); // empty string is reserved for designating an empty parent assert ((profileName != "") && ("Profile name can't be an empty string")); // stack shouldn't be empty assert (!mProfiles.empty()); // get the start of this profile ProfileInstance bProfile; bProfile = mProfiles.back(); mProfiles.pop_back(); // calculate the elapsed time of this profile ulong timeElapsed = endTime - bProfile.currTime; // update parent's accumulator if it isn't the root if (bProfile.parent != "") { // find the parent ProfileStack::iterator iter; for(iter = mProfiles.begin(); iter != mProfiles.end(); ++iter) { if ((*iter).name == bProfile.parent) break; } // the parent should be found assert(iter != mProfiles.end()); // add this profile's time to the parent's accumlator (*iter).accum += timeElapsed; } // we find the profile in this frame ProfileFrameList::iterator iter; for (iter = mProfileFrame.begin(); iter != mProfileFrame.end(); ++iter) { if ((*iter).name == bProfile.name) break; } // nested profiles are cumulative (*iter).frameTime += timeElapsed; (*iter).calls++; // the stack is empty and all the profiles have been completed // we have reached the end of the frame so process the frame statistics if (mProfiles.empty()) { // we know that the time elapsed of the main loop is the total time the frame took mTotalFrameTime = timeElapsed; if (timeElapsed > mMaxTotalFrameTime) mMaxTotalFrameTime = timeElapsed; // we got all the information we need, so process the profiles // for this frame processFrameStats(); // clear the frame stats for next frame mProfileFrame.clear(); // we display everything to the screen displayResults(); } }
//----------------------------------------------------------------------- void Profiler::endProfile(const String& profileName, uint32 groupID) { if(!mEnabled) { // if the profiler received a request to be enabled or disabled if(mNewEnableState != mEnabled) { // note mNewEnableState == true to reach this. changeEnableState(); // NOTE we will be in an 'error' state until the next begin. ie endProfile will likely get invoked using a profileName that was never started. // even then, we can't be sure that the next beginProfile will be the true start of a new frame } return; } else { if(mNewEnableState != mEnabled) { // note mNewEnableState == false to reach this. changeEnableState(); // unwind the hierarchy, should be easy enough mCurrent = &mRoot; mLast = NULL; } if(&mRoot == mCurrent && mLast) { // profiler was enabled this frame, but the first subsequent beginProfile was NOT the beinging of a new frame as we had hoped. // we have a bogus ProfileInstance in our hierarchy, we will need to remove it, then update the overlays so as not to confuse ze user // we could use mRoot.children.find() instead of this, except we'd be compairing strings instead of a pointer. // the string way could be faster, but i don't believe it would. ProfileChildren::iterator it = mRoot.children.begin(), endit = mRoot.children.end(); for(;it != endit; ++it) { if(mLast == it->second) { mRoot.children.erase(it); break; } } // with mLast == NULL we won't reach this code, in case this isn't the end of the top level profile ProfileInstance* last = mLast; mLast = NULL; OGRE_DELETE last; processFrameStats(); displayResults(); } } if(&mRoot == mCurrent) return; // mask groups if ((groupID & mProfileMask) == 0) return; // need a timer to profile! assert (mTimer && "Timer not set!"); // get the end time of this profile // we do this as close the beginning of this function as possible // to get more accurate timing results const ulong endTime = mTimer->getMicroseconds(); // empty string is reserved for designating an empty parent assert ((profileName != "") && ("Profile name can't be an empty string")); // we only process this profile if isn't disabled // we check the current instance name against the provided profileName as a guard against disabling a profile name /after/ said profile began if(mCurrent->name != profileName && mDisabledProfiles.find(profileName) != mDisabledProfiles.end()) return; // calculate the elapsed time of this profile const ulong timeElapsed = endTime - mCurrent->currTime; // update parent's accumulator if it isn't the root if (&mRoot != mCurrent->parent) { // add this profile's time to the parent's accumlator mCurrent->parent->accum += timeElapsed; } mCurrent->frame.frameTime += timeElapsed; ++mCurrent->frame.calls; mLast = mCurrent; mCurrent = mCurrent->parent; if (&mRoot == mCurrent) { // the stack is empty and all the profiles have been completed // we have reached the end of the frame so process the frame statistics // we know that the time elapsed of the main loop is the total time the frame took mTotalFrameTime = timeElapsed; if(timeElapsed > mMaxTotalFrameTime) mMaxTotalFrameTime = timeElapsed; // we got all the information we need, so process the profiles // for this frame processFrameStats(); // we display everything to the screen displayResults(); } }
//-------------------------------------------------------------------- void Profiler::endProfile(const std::string& profileName, bool isSystemProfile) { // if the profiler is enabled if (!mEnabled || (isSystemProfile && !mEngineProfileEnabled)) return; // need a timer to profile! NR_ASSERT (mTimeSource && "Timer not set!"); // get the end time of this profile // we do this as close the beginning of this function as possible // to get more accurate timing results float64 endTime = mTimeSource->getTime(); // empty string is reserved for designating an empty parent NR_ASSERT ((profileName != "") && ("Profile name can't be an empty string")); // stack shouldnt be empty NR_ASSERT (!mProfiles.empty() && ("You have to begin any profile before stop it")); // get the start of this profile ProfileInstance bProfile; bProfile = mProfiles.back(); mProfiles.pop_back(); // calculate the elapsed time of this profile float64 timeElapsed = endTime - bProfile.currTime; // update parent's accumalator if it isn't the root if (bProfile.parent != "") { // find the parent ProfileStack::iterator iter; for(iter = mProfiles.begin(); iter != mProfiles.end(); iter++) if ((*iter).name == bProfile.parent) break; // the parent should be found NR_ASSERT(iter != mProfiles.end()); // add this profile's time to the parent's accumulator (*iter).accum += timeElapsed; } // we find the profile in this frame ProfileFrameList::iterator iter; for (iter = mProfileFrame.begin(); iter != mProfileFrame.end(); iter++) if ((*iter).name == bProfile.name) break; // we subtract the time the children profiles took from this profile (*iter).frameTime += timeElapsed - bProfile.accum; (*iter).frameTotalTime += timeElapsed; (*iter).calls++; // the stack is empty and all the profiles have been completed // we have reached the end of the frame so process the frame statistics if (mProfiles.empty()) { // we know that the time elapsed of the main loop is the total time the frame took mTotalFrameTime = timeElapsed; // we got all the information we need, so process the profiles // for this frame processFrameStats(); // clear the frame stats for next frame mProfileFrame.clear(); // if the profiler received a request to be enabled or disabled // we reached the end of the frame so we can safely do this if (mEnableStateChangePending) { changeEnableState(); } } }