2006-04-24 01:14:18 +02:00
|
|
|
/**
|
|
|
|
* =========================================================================
|
|
|
|
* File : Profile.cpp
|
|
|
|
* Project : Pyrogeneses
|
|
|
|
* Description : GPG3-style hierarchical profiler
|
|
|
|
*
|
|
|
|
* @author Mark Thompson (mark@wildfiregames.com / mot20@cam.ac.uk)
|
|
|
|
* @author Nicolai Haehnle <nicolai@wildfiregames.com>
|
|
|
|
* =========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
|
|
#include "Profile.h"
|
|
|
|
#include "ProfileViewer.h"
|
2007-01-21 04:33:52 +01:00
|
|
|
#include "lib/timer.h"
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CProfileNodeTable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class CProfileNodeTable: Implement ProfileViewer's AbstractProfileTable
|
|
|
|
* interface in order to display profiling data in-game.
|
|
|
|
*/
|
|
|
|
class CProfileNodeTable : public AbstractProfileTable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CProfileNodeTable(CProfileNode* n);
|
|
|
|
virtual ~CProfileNodeTable();
|
|
|
|
|
|
|
|
// Implementation of AbstractProfileTable interface
|
|
|
|
virtual CStr GetName();
|
|
|
|
virtual CStr GetTitle();
|
|
|
|
virtual size_t GetNumberRows();
|
|
|
|
virtual const std::vector<ProfileColumn>& GetColumns();
|
|
|
|
|
|
|
|
virtual CStr GetCellText(size_t row, size_t col);
|
|
|
|
virtual AbstractProfileTable* GetChild(size_t row);
|
|
|
|
virtual bool IsHighlightRow(size_t row);
|
|
|
|
|
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* struct ColumnDescription: The only purpose of this helper structure
|
|
|
|
* is to provide the global constructor that sets up the column
|
|
|
|
* description.
|
|
|
|
*/
|
|
|
|
struct ColumnDescription
|
|
|
|
{
|
|
|
|
std::vector<ProfileColumn> columns;
|
|
|
|
|
|
|
|
ColumnDescription()
|
|
|
|
{
|
|
|
|
columns.push_back(ProfileColumn("Name", 230));
|
|
|
|
columns.push_back(ProfileColumn("calls/frame", 100));
|
|
|
|
columns.push_back(ProfileColumn("msec/frame", 100));
|
|
|
|
columns.push_back(ProfileColumn("%/frame", 100));
|
|
|
|
columns.push_back(ProfileColumn("%/parent", 100));
|
2007-01-21 04:33:52 +01:00
|
|
|
columns.push_back(ProfileColumn("mem allocs", 100));
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// The node represented by this table
|
|
|
|
CProfileNode* node;
|
|
|
|
|
|
|
|
/// Columns description (shared by all instances)
|
|
|
|
static ColumnDescription columnDescription;
|
|
|
|
};
|
|
|
|
|
|
|
|
CProfileNodeTable::ColumnDescription CProfileNodeTable::columnDescription;
|
|
|
|
|
|
|
|
|
|
|
|
// Constructor/Destructor
|
|
|
|
CProfileNodeTable::CProfileNodeTable(CProfileNode* n)
|
|
|
|
{
|
|
|
|
node = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
CProfileNodeTable::~CProfileNodeTable()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// Short name (= name of profile node)
|
|
|
|
CStr CProfileNodeTable::GetName()
|
|
|
|
{
|
|
|
|
return node->GetName();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Title (= explanatory text plus time totals)
|
|
|
|
CStr CProfileNodeTable::GetTitle()
|
|
|
|
{
|
|
|
|
char buf[512];
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "Profiling Information for: %s (Time in node: %.3f msec/frame)", node->GetName(), node->GetFrameTime() * 1000.0f );
|
2006-09-28 22:41:12 +02:00
|
|
|
buf[sizeof(buf)-1] = '\0';
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Total number of children
|
|
|
|
size_t CProfileNodeTable::GetNumberRows()
|
|
|
|
{
|
|
|
|
return node->GetChildren()->size() + node->GetScriptChildren()->size() + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Column description
|
|
|
|
const std::vector<ProfileColumn>& CProfileNodeTable::GetColumns()
|
|
|
|
{
|
|
|
|
return columnDescription.columns;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve cell text
|
|
|
|
CStr CProfileNodeTable::GetCellText(size_t row, size_t col)
|
|
|
|
{
|
|
|
|
CProfileNode* child;
|
|
|
|
size_t nrchildren = node->GetChildren()->size();
|
|
|
|
size_t nrscriptchildren = node->GetScriptChildren()->size();
|
2007-01-21 04:33:52 +01:00
|
|
|
char buf[256] = "?";
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
if (row < nrchildren)
|
|
|
|
child = (*node->GetChildren())[row];
|
|
|
|
else if (row < nrchildren + nrscriptchildren)
|
|
|
|
child = (*node->GetScriptChildren())[row - nrchildren];
|
|
|
|
else if (row > nrchildren + nrscriptchildren)
|
|
|
|
return "!bad row!";
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// "unlogged" row
|
|
|
|
if (col == 0)
|
|
|
|
return "unlogged";
|
|
|
|
else if (col == 1)
|
|
|
|
return "";
|
|
|
|
|
|
|
|
float unlogged = node->GetFrameTime();
|
2007-01-21 04:33:52 +01:00
|
|
|
long unlogged_mallocs = node->GetFrameMallocs();
|
2006-04-24 01:14:18 +02:00
|
|
|
CProfileNode::const_profile_iterator it;
|
|
|
|
|
2007-01-21 04:33:52 +01:00
|
|
|
for (it = node->GetChildren()->begin(); it != node->GetChildren()->end(); ++it)
|
|
|
|
{
|
2006-04-24 01:14:18 +02:00
|
|
|
unlogged -= (*it)->GetFrameTime();
|
2007-01-21 04:33:52 +01:00
|
|
|
unlogged_mallocs -= (*it)->GetFrameMallocs();
|
|
|
|
}
|
|
|
|
for (it = node->GetScriptChildren()->begin(); it != node->GetScriptChildren()->end(); ++it)
|
|
|
|
{
|
2006-04-24 01:14:18 +02:00
|
|
|
unlogged -= (*it)->GetFrameTime();
|
2007-01-21 04:33:52 +01:00
|
|
|
unlogged_mallocs -= (*it)->GetFrameMallocs();
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
if (col == 2)
|
|
|
|
snprintf(buf, sizeof(buf), "%.3f", unlogged * 1000.0f);
|
|
|
|
else if (col == 3)
|
|
|
|
snprintf(buf, sizeof(buf), "%.1f", unlogged / g_Profiler.GetRoot()->GetFrameTime());
|
2007-01-21 04:33:52 +01:00
|
|
|
else if (col == 4)
|
2006-04-24 01:14:18 +02:00
|
|
|
snprintf(buf, sizeof(buf), "%.1f", unlogged * 100.0f / g_Profiler.GetRoot()->GetFrameTime());
|
2007-01-21 04:33:52 +01:00
|
|
|
else if (col == 5)
|
2007-02-25 22:11:57 +01:00
|
|
|
snprintf(buf, sizeof(buf), "%ld", unlogged_mallocs);
|
2006-09-28 22:41:12 +02:00
|
|
|
buf[sizeof(buf)-1] = '\0';
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
return CStr(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(col)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case 0:
|
|
|
|
return child->GetName();
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
#ifdef PROFILE_AMORTIZE
|
|
|
|
snprintf(buf, sizeof(buf), "%.3f", child->GetFrameCalls());
|
|
|
|
#else
|
|
|
|
snprintf(buf, sizeof(buf), "%d", child->GetFrameCalls());
|
|
|
|
#endif
|
2006-09-28 22:41:12 +02:00
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
case 2:
|
|
|
|
snprintf(buf, sizeof(buf), "%.3f", child->GetFrameTime() * 1000.0f);
|
2006-09-28 22:41:12 +02:00
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
case 3:
|
|
|
|
snprintf(buf, sizeof(buf), "%.1f", child->GetFrameTime() * 100.0 / g_Profiler.GetRoot()->GetFrameTime());
|
2006-09-28 22:41:12 +02:00
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
case 4:
|
|
|
|
snprintf(buf, sizeof(buf), "%.1f", child->GetFrameTime() * 100.0 / node->GetFrameTime());
|
2006-09-28 22:41:12 +02:00
|
|
|
break;
|
2007-01-21 04:33:52 +01:00
|
|
|
case 5:
|
2007-02-25 22:11:57 +01:00
|
|
|
snprintf(buf, sizeof(buf), "%ld", child->GetFrameMallocs());
|
2007-01-21 04:33:52 +01:00
|
|
|
break;
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
2006-09-28 22:41:12 +02:00
|
|
|
buf[sizeof(buf)-1] = '\0';
|
|
|
|
return CStr(buf);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return a pointer to the child table if the child node is expandable
|
|
|
|
AbstractProfileTable* CProfileNodeTable::GetChild(size_t row)
|
|
|
|
{
|
|
|
|
CProfileNode* child;
|
|
|
|
size_t nrchildren = node->GetChildren()->size();
|
|
|
|
size_t nrscriptchildren = node->GetScriptChildren()->size();
|
|
|
|
|
|
|
|
if (row < nrchildren)
|
|
|
|
child = (*node->GetChildren())[row];
|
|
|
|
else if (row < nrchildren + nrscriptchildren)
|
|
|
|
child = (*node->GetScriptChildren())[row - nrchildren];
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (child->CanExpand())
|
|
|
|
return child->display_table;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Highlight all script nodes
|
|
|
|
bool CProfileNodeTable::IsHighlightRow(size_t row)
|
|
|
|
{
|
|
|
|
size_t nrchildren = node->GetChildren()->size();
|
|
|
|
size_t nrscriptchildren = node->GetScriptChildren()->size();
|
|
|
|
|
|
|
|
return (row >= nrchildren && row < (nrchildren + nrscriptchildren));
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CProfileNode implementation
|
|
|
|
|
|
|
|
|
|
|
|
// Note: As with the GPG profiler, name is assumed to be a pointer to a constant string; only pointer equality is checked.
|
|
|
|
CProfileNode::CProfileNode( const char* _name, CProfileNode* _parent )
|
|
|
|
{
|
|
|
|
name = _name;
|
|
|
|
recursion = 0;
|
2007-01-21 04:33:52 +01:00
|
|
|
|
|
|
|
Reset();
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
parent = _parent;
|
|
|
|
|
|
|
|
display_table = new CProfileNodeTable(this);
|
|
|
|
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
CProfileNode::~CProfileNode()
|
|
|
|
{
|
|
|
|
profile_iterator it;
|
|
|
|
for( it = children.begin(); it != children.end(); it++ )
|
|
|
|
delete( *it );
|
|
|
|
for( it = script_children.begin(); it != script_children.end(); it++ )
|
|
|
|
delete( *it );
|
|
|
|
|
|
|
|
delete display_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CProfileNode* CProfileNode::GetChild( const char* childName ) const
|
|
|
|
{
|
|
|
|
const_profile_iterator it;
|
|
|
|
for( it = children.begin(); it != children.end(); it++ )
|
|
|
|
if( (*it)->name == childName )
|
|
|
|
return( *it );
|
|
|
|
|
|
|
|
return( NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
const CProfileNode* CProfileNode::GetScriptChild( const char* childName ) const
|
|
|
|
{
|
|
|
|
const_profile_iterator it;
|
|
|
|
for( it = script_children.begin(); it != script_children.end(); it++ )
|
|
|
|
if( (*it)->name == childName )
|
|
|
|
return( *it );
|
|
|
|
|
|
|
|
return( NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
CProfileNode* CProfileNode::GetChild( const char* childName )
|
|
|
|
{
|
|
|
|
profile_iterator it;
|
|
|
|
for( it = children.begin(); it != children.end(); it++ )
|
|
|
|
if( (*it)->name == childName )
|
|
|
|
return( *it );
|
|
|
|
|
|
|
|
CProfileNode* newNode = new CProfileNode( childName, this );
|
|
|
|
children.push_back( newNode );
|
|
|
|
return( newNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
CProfileNode* CProfileNode::GetScriptChild( const char* childName )
|
|
|
|
{
|
|
|
|
profile_iterator it;
|
|
|
|
for( it = script_children.begin(); it != script_children.end(); it++ )
|
|
|
|
if( (*it)->name == childName )
|
|
|
|
return( *it );
|
|
|
|
|
|
|
|
CProfileNode* newNode = new CProfileNode( childName, this );
|
|
|
|
script_children.push_back( newNode );
|
|
|
|
return( newNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CProfileNode::CanExpand()
|
|
|
|
{
|
|
|
|
return( !( children.empty() && script_children.empty() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileNode::Reset()
|
|
|
|
{
|
|
|
|
calls_total = 0;
|
|
|
|
calls_frame_current = 0;
|
|
|
|
#ifdef PROFILE_AMORTIZE
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < PROFILE_AMORTIZE_FRAMES; i++ )
|
|
|
|
{
|
|
|
|
calls_frame_buffer[i] = 0;
|
|
|
|
time_frame_buffer[i] = 0.0;
|
|
|
|
}
|
|
|
|
calls_frame_last = calls_frame_buffer;
|
|
|
|
calls_frame_amortized = 0.0f;
|
|
|
|
#else
|
|
|
|
calls_frame_last = 0;
|
|
|
|
#endif
|
2007-01-21 04:33:52 +01:00
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
time_total = 0.0;
|
|
|
|
time_frame_current = 0.0;
|
|
|
|
#ifdef PROFILE_AMORTIZE
|
|
|
|
time_frame_last = time_frame_buffer;
|
|
|
|
time_frame_amortized = 0.0;
|
|
|
|
#else
|
|
|
|
time_frame_last = 0.0;
|
|
|
|
#endif
|
2007-01-21 04:33:52 +01:00
|
|
|
|
|
|
|
mallocs_total = 0;
|
|
|
|
mallocs_frame_current = 0;
|
|
|
|
mallocs_frame_last = 0;
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
profile_iterator it;
|
|
|
|
for( it = children.begin(); it != children.end(); it++ )
|
|
|
|
(*it)->Reset();
|
|
|
|
for( it = script_children.begin(); it != script_children.end(); it++ )
|
|
|
|
(*it)->Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileNode::Frame()
|
|
|
|
{
|
|
|
|
calls_total += calls_frame_current;
|
|
|
|
time_total += time_frame_current;
|
2007-01-21 04:33:52 +01:00
|
|
|
mallocs_total += mallocs_frame_current;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
#ifdef PROFILE_AMORTIZE
|
|
|
|
calls_frame_amortized -= *calls_frame_last;
|
|
|
|
*calls_frame_last = calls_frame_current;
|
|
|
|
calls_frame_amortized += calls_frame_current;
|
|
|
|
time_frame_amortized -= *time_frame_last;
|
|
|
|
*time_frame_last = time_frame_current;
|
|
|
|
time_frame_amortized += time_frame_current;
|
|
|
|
if( ++calls_frame_last == ( calls_frame_buffer + PROFILE_AMORTIZE_FRAMES ) )
|
|
|
|
calls_frame_last = calls_frame_buffer;
|
|
|
|
if( ++time_frame_last == ( time_frame_buffer + PROFILE_AMORTIZE_FRAMES ) )
|
|
|
|
time_frame_last = time_frame_buffer;
|
|
|
|
#else
|
|
|
|
calls_frame_last = calls_frame_current;
|
|
|
|
time_frame_last = time_frame_current;
|
|
|
|
#endif
|
2007-01-21 04:33:52 +01:00
|
|
|
mallocs_frame_last = mallocs_frame_current;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
calls_frame_current = 0;
|
|
|
|
time_frame_current = 0.0;
|
2007-01-21 04:33:52 +01:00
|
|
|
mallocs_frame_current = 0;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
profile_iterator it;
|
|
|
|
for( it = children.begin(); it != children.end(); it++ )
|
|
|
|
(*it)->Frame();
|
|
|
|
for( it = script_children.begin(); it != script_children.end(); it++ )
|
|
|
|
(*it)->Frame();
|
|
|
|
}
|
|
|
|
|
2007-01-21 04:33:52 +01:00
|
|
|
static long get_memory_alloc_count()
|
|
|
|
{
|
|
|
|
#if HAVE_VC_DEBUG_ALLOC
|
2007-03-01 19:52:53 +01:00
|
|
|
// TODO: it's probably better to use _CrtSetAllocHook to increment a
|
|
|
|
// user-visible counter. (I didn't know that existed when I wrote this.)
|
|
|
|
|
|
|
|
// Find the number of allocations that have ever occurred, by doing a dummy
|
|
|
|
// allocation and checking its request number
|
2007-01-21 04:33:52 +01:00
|
|
|
static long bias = 0; // so we can subtract the allocations caused by this function
|
|
|
|
void* p = malloc(1);
|
|
|
|
long requestNumber = 0;
|
|
|
|
int ok = _CrtIsMemoryBlock(p, 1, &requestNumber, NULL, NULL);
|
|
|
|
UNUSED2(ok);
|
|
|
|
free(p);
|
|
|
|
++bias;
|
|
|
|
return requestNumber - bias;
|
|
|
|
#else
|
2007-03-01 19:52:53 +01:00
|
|
|
// TODO: support other compilers if it's easy.
|
|
|
|
// TODO: don't show this column of data when we don't have sensible values
|
|
|
|
// to display.
|
2007-01-21 04:33:52 +01:00
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
void CProfileNode::Call()
|
|
|
|
{
|
|
|
|
calls_frame_current++;
|
|
|
|
if( recursion++ == 0 )
|
2007-01-21 04:33:52 +01:00
|
|
|
{
|
2006-04-24 01:14:18 +02:00
|
|
|
start = get_time();
|
2007-01-21 04:33:52 +01:00
|
|
|
start_mallocs = get_memory_alloc_count();
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CProfileNode::Return()
|
|
|
|
{
|
|
|
|
if( !parent ) return( false );
|
|
|
|
|
|
|
|
if( ( --recursion == 0 ) && ( calls_frame_current != 0 ) )
|
2007-01-21 04:33:52 +01:00
|
|
|
{
|
2006-04-24 01:14:18 +02:00
|
|
|
time_frame_current += ( get_time() - start );
|
2007-01-21 04:33:52 +01:00
|
|
|
mallocs_frame_current += ( get_memory_alloc_count() - start_mallocs );
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
return( recursion == 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileNode::ScriptingInit()
|
|
|
|
{
|
|
|
|
AddProperty( L"name", (IJSObject::GetFn)&CProfileNode::JS_GetName );
|
|
|
|
/*
|
|
|
|
AddReadOnlyClassProperty( L"callsTotal", &CProfileNode::calls_total );
|
|
|
|
AddReadOnlyClassProperty( L"callsPerFrame", &CProfileNode::calls_frame_last );
|
|
|
|
AddReadOnlyClassProperty( L"timeTotal", &CProfileNode::time_total );
|
|
|
|
AddReadOnlyClassProperty( L"timePerFrame", &CProfileNode::time_frame_last );
|
|
|
|
*/
|
|
|
|
CJSObject<CProfileNode, true>::ScriptingInit( "ProfilerNode" );
|
|
|
|
}
|
|
|
|
|
|
|
|
CProfileManager::CProfileManager()
|
|
|
|
{
|
|
|
|
root = new CProfileNode( "root", NULL );
|
|
|
|
current = root;
|
|
|
|
frame_start = 0.0;
|
|
|
|
g_ProfileViewer.AddRootTable(root->display_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
CProfileManager::~CProfileManager()
|
|
|
|
{
|
|
|
|
std::map<CStr8, const char*>::iterator it;
|
|
|
|
for( it = m_internedStrings.begin(); it != m_internedStrings.end(); it++ )
|
|
|
|
delete[]( it->second );
|
|
|
|
|
|
|
|
delete( root );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileManager::Start( const char* name )
|
|
|
|
{
|
|
|
|
if( name != current->GetName() )
|
|
|
|
current = current->GetChild( name );
|
|
|
|
current->Call();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileManager::StartScript( const char* name )
|
|
|
|
{
|
|
|
|
if( name != current->GetName() )
|
|
|
|
current = current->GetScriptChild( name );
|
|
|
|
current->Call();
|
|
|
|
}
|
|
|
|
|
2007-03-01 19:52:53 +01:00
|
|
|
const char* CProfileManager::InternString( const CStr8& intern )
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
std::map<CStr8, const char*>::iterator it = m_internedStrings.find( intern );
|
|
|
|
if( it != m_internedStrings.end() )
|
|
|
|
return( it->second );
|
|
|
|
|
|
|
|
size_t length = intern.length();
|
|
|
|
char* data = new char[length + 1];
|
|
|
|
strcpy( data, intern.c_str() );
|
|
|
|
data[length] = 0;
|
|
|
|
m_internedStrings.insert( std::pair<CStr8, const char*>( intern, data ) );
|
|
|
|
return( data );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileManager::Stop()
|
|
|
|
{
|
|
|
|
if( current->Return() )
|
|
|
|
current = current->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileManager::Reset()
|
|
|
|
{
|
|
|
|
root->Reset();
|
|
|
|
start = get_time();
|
|
|
|
frame_start = get_time();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileManager::Frame()
|
|
|
|
{
|
|
|
|
root->time_frame_current = ( get_time() - frame_start );
|
|
|
|
root->Frame();
|
|
|
|
|
|
|
|
frame_start = get_time();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProfileManager::StructuralReset()
|
|
|
|
{
|
|
|
|
delete( root );
|
|
|
|
root = new CProfileNode( "root", NULL );
|
|
|
|
current = root;
|
|
|
|
g_ProfileViewer.AddRootTable(root->display_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
double CProfileManager::GetTime()
|
|
|
|
{
|
|
|
|
return( get_time() - start );
|
|
|
|
}
|
|
|
|
|
|
|
|
double CProfileManager::GetFrameTime()
|
|
|
|
{
|
|
|
|
return( get_time() - frame_start );
|
|
|
|
}
|
|
|
|
|