//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $Workfile: $ // $Date: $ // //----------------------------------------------------------------------------- // $Log: $ // // $NoKeywords: $ //=============================================================================// #include #include #include "basetypes.h" #include "measure_section.h" #include "convar.h" // Static members CMeasureSection *CMeasureSection::s_pSections = 0; int CMeasureSection::s_nCount = 0; double CMeasureSection::m_dNextResort = 0.0; ConVar measure_resort( "measure_resort", "1.0", 0, "How often to re-sort profiling sections\n" ); ConVar game_speeds( "game_speeds","0" ); extern ConVar host_speeds; //----------------------------------------------------------------------------- // Purpose: Creates a profiling section // Input : *name - name of the section ( allocated on stack hopefully ) //----------------------------------------------------------------------------- CMeasureSection::CMeasureSection( const char *name ) { // Just point at name since it's static m_pszName = name; // Clear accumulators Reset(); SortReset(); m_dMaxTime.Init(); // Link into master list m_pNext = s_pSections; s_pSections = this; // Update count s_nCount++; } //----------------------------------------------------------------------------- // Purpose: Destroys the object //----------------------------------------------------------------------------- CMeasureSection::~CMeasureSection( void ) { m_pNext = NULL; s_nCount--; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMeasureSection::UpdateMax( void ) { if (m_dMaxTime.IsLessThan(m_dAccumulatedTime)) { m_dMaxTime.Init(); CCycleCount::Add(m_dMaxTime,m_dAccumulatedTime,m_dMaxTime); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMeasureSection::Reset( void ) { m_dAccumulatedTime.Init(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CMeasureSection::SortReset( void ) { m_dTotalTime.Init(); } //----------------------------------------------------------------------------- // Purpose: // Output : const char //----------------------------------------------------------------------------- const char *CMeasureSection::GetName( void ) { return m_pszName; } //----------------------------------------------------------------------------- // Purpose: // Output : //----------------------------------------------------------------------------- CCycleCount const& CMeasureSection::GetTotalTime( void ) { return m_dTotalTime; } //----------------------------------------------------------------------------- // Purpose: // Output : //----------------------------------------------------------------------------- CCycleCount const& CMeasureSection::GetTime( void ) { return m_dAccumulatedTime; } //----------------------------------------------------------------------------- // Purpose: // Output : //----------------------------------------------------------------------------- CCycleCount const& CMeasureSection::GetMaxTime( void ) { return m_dMaxTime; } //----------------------------------------------------------------------------- // Purpose: Accumulates a timeslice // Input : time - //----------------------------------------------------------------------------- void CMeasureSection::AddTime( CCycleCount const &rCount ) { CCycleCount::Add(m_dAccumulatedTime, rCount, m_dAccumulatedTime); CCycleCount::Add(m_dTotalTime, rCount, m_dTotalTime); } //----------------------------------------------------------------------------- // Purpose: // Output : CMeasureSection //----------------------------------------------------------------------------- CMeasureSection *CMeasureSection::GetNext( void ) { return m_pNext; } //----------------------------------------------------------------------------- // Purpose: // Output : CMeasureSection //----------------------------------------------------------------------------- CMeasureSection *CMeasureSection::GetList( void ) { return s_pSections; } //----------------------------------------------------------------------------- // Purpose: Compares accumulated time for two sections // Input : ppms1 - // ppms2 - // Output : static int //----------------------------------------------------------------------------- static int SectionCompare( const void* ppms1,const void* ppms2 ) { CMeasureSection* pms1 = *(CMeasureSection**)ppms1; CMeasureSection* pms2 = *(CMeasureSection**)ppms2; if ( pms1->GetTotalTime().IsLessThan(pms2->GetTotalTime()) ) return 1; else return -1; } //----------------------------------------------------------------------------- // Purpose: Sorts sections by time usage //----------------------------------------------------------------------------- void CMeasureSection::SortSections( void ) { // Not enough to be sortable if ( s_nCount <= 1 ) return; CMeasureSection *sortarray[ 128 ]; CMeasureSection *ms; memset(sortarray,sizeof(CMeasureSection*)*128,0); ms = GetList(); int i; int c = 0; while ( ms ) { sortarray[ c++ ] = ms; ms = ms->GetNext(); } // Sort the array alphabetically qsort( sortarray, c , sizeof( CMeasureSection * ), SectionCompare ); // Fix next pointers for ( i = 0; i < c-1; i++ ) { sortarray[ i ]->m_pNext = sortarray[ i + 1 ]; } sortarray[i]->m_pNext = NULL; // Point head of list at it s_pSections = sortarray[ 0 ]; } //----------------------------------------------------------------------------- // Purpose: Creates an instance for timing a section // Input : *ms - //----------------------------------------------------------------------------- CMeasureSectionInstance::CMeasureSectionInstance( CMeasureSection *ms ) { // Remember where to put accumulated time m_pMS = ms; if ( host_speeds.GetInt() < 3 && !game_speeds.GetInt()) return; // Get initial timestamp m_Timer.Start(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CMeasureSectionInstance::~CMeasureSectionInstance( void ) { if ( host_speeds.GetInt() < 3 && !game_speeds.GetInt()) return; // Get final timestamp m_Timer.End(); // Add time to section m_pMS->AddTime( m_Timer.GetDuration() ); } //----------------------------------------------------------------------------- // Purpose: Re-sort all data and determine whether sort keys should be reset too ( after // re-doing sort if needed ). //----------------------------------------------------------------------------- void ResetTimeMeasurements( void ) { #if defined( _DEBUG ) || defined( FORCE_MEASURE ) bool sort_reset = false; // Time to redo sort? if ( measure_resort.GetFloat() > 0.0 && GetRealTime() >= CMeasureSection::m_dNextResort ) { // Redo it CMeasureSection::SortSections(); // Set next time CMeasureSection::m_dNextResort = GetRealTime() + measure_resort.GetFloat(); // Flag to reset sort accumulator, too sort_reset = true; } // Iterate through the sections now CMeasureSection *p = CMeasureSection::GetList(); while ( p ) { // Reset regular accum. p->Reset(); // Reset sort accum less often if ( sort_reset ) { p->SortReset(); } p = p->GetNext(); } #endif }