etqw-sdk/source/game/misc/ProfileHelper.cpp

503 lines
12 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#include "../precompiled.h"
#pragma hdrstop
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include "ProfileHelper.h"
/*
===============================================================================
sdProfileHelper
===============================================================================
*/
/*
================
sdProfileHelper::sdProfileHelper
================
*/
sdProfileHelper::sdProfileHelper( void ) {
m_ProfileNode.SetOwner( this );
m_ProfileName = "";
m_HasCount = false;
m_HasTotal = false;
m_LogFileUpto = 0;
}
/*
================
sdProfileHelper::~sdProfileHelper
================
*/
sdProfileHelper::~sdProfileHelper( void ) {
m_ProfileNode.Remove();
}
/*
================
sdProfileHelper::~sdProfileHelper
================
*/
void sdProfileHelper::Init( const char* name, bool hasTotal, bool hasCount ) {
m_ProfileName = name;
m_HasTotal = hasTotal;
m_HasCount = hasCount;
m_ProfileNode.AddToFront( sdProfileHelperManager::GetInstance().m_InactiveProfilers );
}
/*
================
sdProfileHelper::Start
================
*/
void sdProfileHelper::Start( void ) {
if ( IsActive() ) {
return;
}
// clear the list
for ( int i = 0; i < m_SampleValues.Num(); i++ ) {
delete *m_SampleValues.GetIndex( i );
}
m_SampleValues.Clear();
if ( m_HasCount ) {
for ( int i = 0; i < m_SampleCounts.Num(); i++ ) {
delete *m_SampleCounts.GetIndex( i );
}
m_SampleCounts.Clear();
}
m_SampleUpto = 0;
m_LogSubFileUpto = 0;
m_LogFileUpto++;
m_ProfileNode.AddToFront( sdProfileHelperManager::GetInstance().m_ActiveProfilers );
}
/*
================
sdProfileHelper::Stop
================
*/
void sdProfileHelper::Stop( void ) {
if ( !IsActive() ) {
return;
}
DumpLog( NULL, m_SampleValues );
AssembleLogs( NULL );
if ( m_HasCount ) {
DumpLog( "count", m_SampleCounts );
AssembleLogs( "count" );
}
m_LogSubFileUpto++;
m_SampleUpto = 1;
m_ProfileNode.AddToFront( sdProfileHelperManager::GetInstance().m_InactiveProfilers );
}
/*
================
sdProfileHelper::IsActive
================
*/
bool sdProfileHelper::IsActive( void ) const {
if ( m_ProfileNode.ListHead() == &sdProfileHelperManager::GetInstance().m_ActiveProfilers ) {
return true;
}
return false;
}
/*
================
sdProfileHelper::Update
================
*/
void sdProfileHelper::Update( void ) {
if ( !IsActive() ) {
return;
}
m_SampleUpto++;
if ( m_SampleUpto == PROFILE_HELPER_MAX_FRAMES ) {
DumpLog( NULL, m_SampleValues );
if ( m_HasCount ) {
DumpLog( "count", m_SampleCounts );
}
m_LogSubFileUpto++;
m_SampleUpto = 1;
}
m_SampleTimes[ m_SampleUpto ] = gameLocal.time;
}
/*
================
sdProfileHelper::LogValue
================
*/
void sdProfileHelper::LogValue( const char* sampleName, double value ) {
if ( !IsActive() ) {
return;
}
sampleSet_t** infoPtr;
sampleSet_t* info;
if ( !m_SampleValues.Get( sampleName, &infoPtr ) ) {
info = new sampleSet_t;
for ( int i = 0; i < PROFILE_HELPER_MAX_FRAMES; i++ ) {
info->frameInfo[ i ] = 0.0;
}
m_SampleValues.Set( sampleName, info );
m_SampleValues.Get( sampleName, &infoPtr );
}
info = *infoPtr;
info->frameInfo[ m_SampleUpto ] += value;
if ( m_HasCount ) {
if ( !m_SampleCounts.Get( sampleName, &infoPtr ) ) {
info = new sampleSet_t;
for ( int i = 0; i < PROFILE_HELPER_MAX_FRAMES; i++ ) {
info->frameInfo[ i ] = 0.0;
}
m_SampleCounts.Set( sampleName, info );
m_SampleCounts.Get( sampleName, &infoPtr );
}
info = *infoPtr;
info->frameInfo[ m_SampleUpto ] += 1.0;
}
}
/*
================
sdProfileHelper::GetMiniLogName
================
*/
void sdProfileHelper::GetMiniLogName( const char* suffix, idStr& out, int logNum, int subLogNum ) {
const char* extraNameInfo = gameLocal.isClient ? "client" : "server";
if ( suffix == NULL ) {
out = va( "profiling/temp/%s_%s_mini_%i_%i.temp", m_ProfileName.c_str(), extraNameInfo, logNum, subLogNum );
} else {
out = va( "profiling/temp/%s_%s_%s_mini_%i_%i.temp", m_ProfileName.c_str(), suffix, extraNameInfo, logNum, subLogNum );
}
}
/*
================
sdProfileHelper::GetLogName
================
*/
void sdProfileHelper::GetLogName( const char* suffix, idStr& out, int logNum ) {
const char* extraNameInfo = gameLocal.isClient ? "client" : "server";
if ( suffix == NULL ) {
out = va( "profiling/%s_%s_%i.csv", m_ProfileName.c_str(), extraNameInfo, logNum );
} else {
out = va( "profiling/%s_%s_%s_%i.csv", m_ProfileName.c_str(), suffix, extraNameInfo, logNum );
}
}
/*
================
sdProfileHelper::DumpLog
================
*/
void sdProfileHelper::DumpLog( const char* suffix, sampleGroup_t& group ) {
idStr fileName;
GetMiniLogName( suffix, fileName, m_LogFileUpto, m_LogSubFileUpto );
idFile* miniLog = fileSystem->OpenFileWrite( fileName.c_str() );
if ( miniLog == NULL ) {
gameLocal.Warning( "sdProfileHelper::DumpLog - failed to open %s", fileName.c_str() );
return;
}
// output number of columns
if ( m_HasTotal ) {
miniLog->WriteInt( group.Num() + 2 );
} else {
miniLog->WriteInt( group.Num() + 1 );
}
// print line of titles
miniLog->WriteString( "gameLocal.time" );
for ( int i = 0; i < group.Num(); i++ ) {
miniLog->WriteString( va( "%s", group.GetKey( i ).c_str() ) );
}
if ( m_HasTotal ) {
miniLog->WriteString( "TOTAL" );
}
// print data, row by row
for ( int sample = 1; sample < m_SampleUpto; sample++ ) {
miniLog->WriteInt( m_SampleTimes[ sample ] );
double total = 0.0;
for ( int i = 0; i < group.Num(); i++ ) {
sampleSet_t* info = *group.GetIndex( i );
miniLog->WriteFloat( ( float )info->frameInfo[ sample ] );
total += info->frameInfo[ sample ];
info->frameInfo[ sample ] = 0.0;
}
if ( m_HasTotal ) {
miniLog->WriteFloat( ( float )total );
}
}
fileSystem->CloseFile( miniLog );
}
/*
================
sdProfileHelper::AssembleLogs
================
*/
void sdProfileHelper::AssembleLogs( const char* suffix ) {
// assemble all the logs for this session into one big csv file & delete the mini-logs
// first find all the logs & collate a list of titles
idList< idStr > titles;
int numLogs = 0;
//
// Initialize the titles list
//
while( 1 ) {
idStr logName;
GetMiniLogName( suffix, logName, m_LogFileUpto, numLogs );
idFile* miniLog = fileSystem->OpenFileRead( logName.c_str() );
if ( miniLog == NULL ) {
break;
}
int numColumns;
miniLog->ReadInt( numColumns );
for ( int i = 0; i < numColumns; i++ ) {
idStr title;
miniLog->ReadString( title );
titles.AddUnique( title );
}
numLogs++;
fileSystem->CloseFile( miniLog );
}
if ( numLogs == 0 ) {
gameLocal.Warning( "sdProfileHelper::AssembleLogs - no mini logs!" );
return;
}
//
// Sort the titles list, keeping gameLocal.time & TOTAL at the start
//
titles.RemoveFast( idStr( "gameLocal.time" ) );
bool hadTotal = titles.RemoveFast( idStr( "TOTAL" ) );
titles.Sort();
if ( hadTotal ) {
titles.Insert( idStr( "TOTAL" ), 0 );
}
titles.Insert( idStr( "gameLocal.time" ), 0 );
//
// Write the titles list
//
idStr fullLogName;
GetLogName( suffix, fullLogName, m_LogFileUpto );
idFile* log = fileSystem->OpenFileWrite( fullLogName.c_str() );
if ( log == NULL ) {
gameLocal.Warning( "sdProfileHelper::AssembleLogs - couldn't open file %s", fullLogName.c_str() );
return;
}
for ( int i = 0; i < titles.Num(); i++ ) {
log->Printf( "\"%s\",", titles[ i ].c_str() );
}
log->Printf( "\n" );
//
// Loop through the logs & write them all into the main log
//
idList< int > miniLogColumnToLogColumn;
idList< int > logColumnToMiniLogColumn;
idList< float > columnTimeValues;
logColumnToMiniLogColumn.AssureSize( titles.Num() );
for ( int logNum = 0; logNum < numLogs; logNum++ ) {
idStr logName;
GetMiniLogName( suffix, logName, m_LogFileUpto, logNum );
idFile* miniLog = fileSystem->OpenFileRead( logName.c_str() );
if ( miniLog == NULL ) {
gameLocal.Warning( "sdProfileHelper::AssembleLogs - couldn't open file %s", logName.c_str() );
break;
}
// create translation tables to & from the mini log & main log table
int numColumns;
miniLog->ReadInt( numColumns );
miniLogColumnToLogColumn.AssureSize( numColumns );
for ( int i = 0; i < titles.Num(); i++ ) {
logColumnToMiniLogColumn[ i ] = -1;
}
for ( int i = 0; i < numColumns; i++ ) {
idStr title;
miniLog->ReadString( title );
miniLogColumnToLogColumn[ i ] = titles.FindIndex( title );
logColumnToMiniLogColumn[ miniLogColumnToLogColumn[ i ] ] = i;
}
// go through all the samples and write them into the main file
columnTimeValues.AssureSize( numColumns );
while ( miniLog->Tell() < miniLog->Length() - 1 ) {
int time;
miniLog->ReadInt( time );
// read the samples
for ( int i = 1; i < numColumns; i++ ) {
miniLog->ReadFloat( columnTimeValues[ i ] );
}
// write the time samples
log->Printf( "%i,", time );
for ( int i = 1; i < titles.Num(); i++ ) {
if ( logColumnToMiniLogColumn[ i ] == -1 ) {
log->Printf( "0," );
} else {
log->Printf( "%.6f,", columnTimeValues[ logColumnToMiniLogColumn[ i ] ] );
}
}
log->Printf( "\n" );
}
fileSystem->CloseFile( miniLog );
fileSystem->RemoveFile( logName.c_str() );
}
fileSystem->CloseFile( log );
}
/*
===============================================================================
sdProfileHelperManagerLocal
===============================================================================
*/
/*
================
sdProfileHelperManagerLocal::sdProfileHelperManagerLocal
================
*/
sdProfileHelperManagerLocal::sdProfileHelperManagerLocal( void ) {
m_ActiveProfilers.Clear();
m_InactiveProfilers.Clear();
}
/*
================
sdProfileHelperManagerLocal::~sdProfileHelperManagerLocal
================
*/
sdProfileHelperManagerLocal::~sdProfileHelperManagerLocal( void ) {
StopAll();
m_ActiveProfilers.Clear();
m_InactiveProfilers.Clear();
}
/*
================
sdProfileHelperManagerLocal::Update
================
*/
void sdProfileHelperManagerLocal::Update( void ) {
for ( sdProfileHelper* profiler = m_ActiveProfilers.Next(); profiler != NULL; profiler = profiler->m_ProfileNode.Next() ) {
profiler->Update();
}
}
/*
================
sdProfileHelperManagerLocal::StopAll
================
*/
void sdProfileHelperManagerLocal::StopAll( void ) {
for ( sdProfileHelper* profiler = m_ActiveProfilers.Next(); profiler != NULL; ) {
sdProfileHelper* nextProfiler = profiler->m_ProfileNode.Next();
profiler->Stop();
profiler = nextProfiler;
}
}
/*
================
sdProfileHelperManagerLocal::FindProfiler
================
*/
sdProfileHelper* sdProfileHelperManagerLocal::FindProfiler( const char* name ) {
for ( sdProfileHelper* profiler = m_ActiveProfilers.Next(); profiler != NULL; profiler = profiler->m_ProfileNode.Next() ) {
if ( !idStr::Icmp( profiler->GetName(), name ) ) {
return profiler;
}
}
for ( sdProfileHelper* profiler = m_InactiveProfilers.Next(); profiler != NULL; profiler = profiler->m_ProfileNode.Next() ) {
if ( !idStr::Icmp( profiler->GetName(), name ) ) {
return profiler;
}
}
return NULL;
}
/*
================
sdProfileHelperManagerLocal::LogValue
================
*/
void sdProfileHelperManagerLocal::LogValue( const char* profileName, const char* sampleName, double value, bool create, bool hasTotal, bool hasCount ) {
sdProfileHelper* profiler = FindProfiler( profileName );
if ( profiler == NULL && create ) {
profiler = new sdProfileHelper();
profiler->Init( profileName, hasTotal, hasCount );
profiler->Start();
}
if ( profiler == NULL ) {
return;
}
if ( !profiler->IsActive() ) {
profiler->Start();
}
profiler->LogValue( sampleName, value );
}