quake4-sdk/source/idlib/TimingCollection.cpp

399 lines
9.4 KiB
C++
Raw Normal View History

2007-06-15 00:00:00 +00:00
#include "precompiled.h"
#pragma hdrstop
#if !defined(__TIMINGCOLLECTION_H_)
#include "TimingCollection.h"
#endif
#ifdef RV_TIMERCOLLECTION
//-----------------------------------------------------------------------------
//
// rvSingleTiming::Clear
//
//-----------------------------------------------------------------------------
void rvSingleTiming::Clear( void )
{
mTotalUpdates = 0;
mCurValue = 0;
mTotalValue = 0;
mPeakValue = 0;
mLimit = 0;
mLimitExceeded = 0;
mLimitExceededTimesFive = 0;
mDisplayLevel = 0;
mName = "";
mParentName = "";
mStartFile = "";
mStartLine = 0;
mEndFile = "";
mEndLine = 0;
}
//-----------------------------------------------------------------------------
//
// rvSingleTiming::rvSingleTiming
//
//-----------------------------------------------------------------------------
rvSingleTiming::rvSingleTiming()
{
Clear();
}
//-----------------------------------------------------------------------------
//
// rvSingleTiming::rvSingleTiming
//
//-----------------------------------------------------------------------------
rvSingleTiming::rvSingleTiming( idStr &newName )
{
Clear();
mName = newName;
}
//-----------------------------------------------------------------------------
//
// rvSingleTiming::OutputDataToFile
//
//-----------------------------------------------------------------------------
void rvSingleTiming::OutputDataToFile( idFile *file, int framesRecorded )
{
char buffer[1024];
idStr outputName = "";
for( int i = 0; i < mDisplayLevel; i++ )
{
outputName += "**";
}
outputName += mName;
sprintf(buffer, "%-36s %-9.3f %-9.3f %-9.3f %-9.3f %-9i %-9i %-9.3f\n", outputName.c_str(),
(float)mTotalValue, (float)( mTotalValue / (float)framesRecorded), (float)mPeakValue,
(float)mLimit, mLimitExceeded, mLimitExceededTimesFive, (float)(mTotalUpdates / (float)framesRecorded) );
file->Write ( buffer, strlen( buffer ) );
}
//-----------------------------------------------------------------------------
//
// rvSingleTiming::OutputInfoToFile
//
//-----------------------------------------------------------------------------
void rvSingleTiming::OutputInfoToFile( idFile *file )
{
char buffer[1024];
sprintf(buffer, "Name: %s\nParent: %s\n", mName.c_str(), mParentName.c_str() );
file->Write ( buffer, strlen( buffer ) );
sprintf(buffer, "Starting at %s(%d)\nEnding at %s(%d)\n\n", mStartFile.c_str(), mStartLine, mEndFile.c_str(), mEndLine );
file->Write ( buffer, strlen( buffer ) );
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::Clear
//
//-----------------------------------------------------------------------------
void rvTimingCollection::Clear( void )
{
mUpdates = 0;
mCurTimer = 0;
mFramesRecorded = 0;
mCurrentlyUpdating = 0;
mTimings.Clear();
mTimingsIndex.Clear();
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::rvTimingCollection
//
//-----------------------------------------------------------------------------
rvTimingCollection::rvTimingCollection()
{
Clear();
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::GetTiming
//
//-----------------------------------------------------------------------------
rvSingleTiming *rvTimingCollection::GetTiming( idStr &timingName )
{
int *handle = NULL;
if( mTimingsIndex.Get( timingName, &handle ) )
{
return( &mTimings[*handle] );
}
rvSingleTiming newTiming( timingName );
int index = mTimings.Num();
mTimingsIndex.Set( timingName, index );
mTimings.Append( newTiming );
return &mTimings[index];
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::DisplayTimingValues
//
//-----------------------------------------------------------------------------
void rvTimingCollection::DisplayTimingValues( void ) {
// Fixme: the display resulting from this is really, really a mess - quite unreadable.
common->Printf ( "Timer: \n" );
for( int i = 0; i < mTimings.Num(); i++ ) {
if ( (int)(mTimings[i].mCurValue) ) {
common->Printf( "\t%s %3i\n", mTimings[i].mName.c_str(), (int)(mTimings[i].mCurValue) );
}
}
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::OutputToFile
//
//-----------------------------------------------------------------------------
void rvTimingCollection::OutputToFile( void )
{
idFile *file = NULL;
idStr name;
char buffer[1024];
// Fixme: Do we have any good information for building a better file name here?
name = "Timings/output.txt";
file = fileSystem->OpenFileWrite ( name );
if ( !file )
{
return;
}
sprintf( buffer, "Total frames = %d\n\n", mFramesRecorded );
file->Write( buffer, strlen( buffer ) );
sprintf( buffer, "%-36s %-9s %-9s %-9s %-9s %-9s %-9s %-9s\n\n",
"Name", "Total", "Average", "Peak", "Limit", "Exceeded", "Exceed*5", "Calls" );
file->Write ( buffer, strlen( buffer ) );
for( int i = 0; i < mTimings.Num(); i++ )
{
mTimings[i].OutputDataToFile( file, mFramesRecorded );
if( !( ( i + 1 )%3) ) // break up the prints into groups of 3 to make scanning visually easier.
{
sprintf( buffer, "\n" );
file->Write( buffer, strlen( buffer ) );
}
}
sprintf(buffer, "\n\nInformation about categories\n\n" );
file->Write ( buffer, strlen( buffer ) );
for( int i = 0; i < mTimings.Num(); i++ )
{
mTimings[i].OutputInfoToFile( file );
}
fileSystem->CloseFile ( file );
file = NULL;
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::AppendToDict
//
//-----------------------------------------------------------------------------
void rvTimingCollection::AppendToDict( idDict *dict )
{
if( !mCurrentlyUpdating )
{
return;
}
for( int i = 0; i < mTimings.Num(); i++ )
{
dict->Set ( mTimings[i].mName.c_str(), va( "%0.3g\t%0.3g\t", mTimings[i].mCurValue, mTimings[i].mTotalValue ) );
}
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::InitFrame
//
//-----------------------------------------------------------------------------
void rvTimingCollection::InitFrame( bool inUse, bool displayText, bool outputFileWhenDone )
{
// Do our quick reject test to ensure this is quick when not in use.
if( !inUse )
{
if( mCurrentlyUpdating )
{
if( outputFileWhenDone )
{
OutputToFile();
}
mCurrentlyUpdating = 0;
}
return;
}
mCurrentlyUpdating = 1;
mUpdates++;
mFramesRecorded++;
if( mUpdates >= 10 && displayText )
{
// ?? If we display output every single frame, we get REALLY bogged down. It is bad.
DisplayTimingValues();
mUpdates = 0;
return;
}
// Clear only the curValues and record information.
for( int i = 0; i < mTimings.Num(); i++ )
{
if( mTimings[i].mCurValue > mTimings[i].mPeakValue )
{
mTimings[i].mPeakValue = mTimings[i].mCurValue;
}
if( mTimings[i].mLimit > 0.0 && mTimings[i].mCurValue > mTimings[i].mLimit )
{
mTimings[i].mLimitExceeded++;
}
if( mTimings[i].mLimit > 0.0 && mTimings[i].mCurValue > mTimings[i].mLimit * 5 )
{
mTimings[i].mLimitExceededTimesFive++;
}
mTimings[i].mCurValue = 0.0f;
}
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::TimingStart
//
//-----------------------------------------------------------------------------
void rvTimingCollection::_TimingStart( const char *timingName, const char *fileName, const int lineNum )
{
// Do our quick reject test to ensure this is quick when not in use.
if( !mCurrentlyUpdating )
{
return;
}
// Go up the timer list.
mCurTimer++;
assert( mCurTimer < MAX_TIMERS );
// Keep track of the current function being timed in case we nest and need to know our parent.
mTimerName[mCurTimer] = timingName;
// Set the information about this timer.
rvSingleTiming *curTiming = GetTiming( mTimerName[mCurTimer] );
if( mCurTimer == 0 )
{
curTiming->mParentName = "base";
}
else
{
curTiming->mParentName = mTimerName[mCurTimer - 1];
}
curTiming->mStartFile = fileName;
curTiming->mStartLine = lineNum;
curTiming->mDisplayLevel = mCurTimer - 1;
// Start the timer; do it last to avoid timing the rest of this function.
mTimer[mCurTimer].Clear();
mTimer[mCurTimer].Start();
}
//-----------------------------------------------------------------------------
//
// rvTimingCollection::TimingEnd
//
//-----------------------------------------------------------------------------
void rvTimingCollection::_TimingStop( double msecLimit, const char *fileName, const int lineNum )
{
// Do our quick reject test to ensure this is quick when not in use.
if( !mCurrentlyUpdating )
{
return;
}
// Stop our timer first so that we don't log time from the rest of this function.
mTimer[mCurTimer].Stop();
// Update incidental information on the timer.
rvSingleTiming *curTiming = GetTiming( mTimerName[mCurTimer] );
curTiming->mEndFile = fileName;
curTiming->mEndLine = lineNum;
curTiming->mLimit = msecLimit;
// Add the actual timing values to the rvSingleTiming
double frameTime = mTimer[mCurTimer].Milliseconds();
curTiming->mCurValue += frameTime;
curTiming->mTotalValue += frameTime;
curTiming->mTotalUpdates++;
// Go back down the timer list.
mCurTimer--;
assert( mCurTimer >= 0 );
}
#endif