|
|
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: VGUI scoreboard
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//===========================================================================//
#include "client_pch.h"
#include "vgui_vprofpanel.h"
#include <keyvalues.h>
#include "vgui_budgetpanel.h"
#include "vprof_engine.h"
#include "vprof_record.h"
#include "ivideomode.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
// positions
#define VPROF_INDENT_X XRES(20)
#define VPROF_INDENT_Y YRES(10)
// Scoreboard dimensions
#define VPROF_TITLE_SIZE_Y YRES(22)
#define X_BORDER XRES(4)
#define Y_BORDER YRES(4)
static ConVar vprof_verbose( "vprof_verbose", "1", FCVAR_ARCHIVE, "Set to one to show average and peak times" ); static ConVar vprof_unaccounted_limit( "vprof_unaccounted_limit", "0.3", FCVAR_ARCHIVE, "number of milliseconds that a node must exceed to turn red in the vprof panel" ); static ConVar vprof_warningmsec( "vprof_warningmsec", "10", FCVAR_ARCHIVE, "Above this many milliseconds render the label red to indicate slow code." );
#ifdef VPROF_ENABLED
//-----------------------------------------------------------------------------
// Singleton accessor
//-----------------------------------------------------------------------------
static CVProfPanel *g_pVProfPanel = NULL; CVProfPanel *GetVProfPanel( void ) { return g_pVProfPanel; }
static void ClearNodeClientData( CVProfNode *pNode ) { pNode->SetClientData( -1 ); if( pNode->GetSibling() ) { ClearNodeClientData( pNode->GetSibling() ); } if( pNode->GetChild() ) { ClearNodeClientData( pNode->GetChild() ); } }
void CVProfPanel::Reset() { m_pHierarchy->RemoveAll(); m_RootItem = -1; ClearNodeClientData( m_pVProfile->GetRoot() ); }
CON_COMMAND( vprof_expand_all, "Expand the whole vprof tree" ) { Msg("VProf expand all.\n"); GetVProfPanel()->ExpandAll(); }
CON_COMMAND( vprof_collapse_all, "Collapse the whole vprof tree" ) { Msg("VProf collapse all.\n"); GetVProfPanel()->CollapseAll(); }
CON_COMMAND( vprof_expand_group, "Expand a budget group in the vprof tree by name" ) { Msg("VProf expand group.\n"); if ( args.ArgC() >= 2 ) { GetVProfPanel()->ExpandGroup( args[ 1 ] ); } }
void IN_VProfDown(void) { GetVProfPanel()->UserCmd_ShowVProf(); }
void IN_VProfUp(void) { GetVProfPanel()->UserCmd_HideVProf(); }
static ConCommand startshowvprof("+showvprof", IN_VProfDown); static ConCommand endshowvprof("-showvprof", IN_VProfUp);
void ChangeVProfScopeCallback( IConVar *pConVar, const char *pOldString, float flOldValue ) { ConVarRef var( pConVar ); Msg( "VProf setting scope to %s\n", var.GetString( ) );
if ( g_pVProfPanel ) { g_pVProfPanel->Reset(); } }
ConVar vprof_scope( "vprof_scope", "", 0, "Set a specific scope to start showing vprof tree", 0, 0, 0, 0, ChangeVProfScopeCallback );
#define PROF_FONT "DefaultFixed"
class CProfileTree : public TreeView { DECLARE_CLASS_SIMPLE( CProfileTree, TreeView ); public: CProfileTree( CVProfPanel *parent, const char *panelName ); ~CProfileTree();
virtual void OnCommand( const char *cmd );
virtual void InvalidateLayout( bool layoutNow = false, bool reloadScheme = false );
virtual void ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); SetFont( pScheme->GetFont( PROF_FONT ) ); }
virtual void SetBgColor( Color color ) { BaseClass::SetBgColor( color ); }
private:
Menu *m_pEditMenu; CVProfPanel *m_pParent; };
CProfileTree::CProfileTree( CVProfPanel *parent, const char *panelName ) : BaseClass( (Panel *)parent, panelName ), m_pEditMenu( 0 ), m_pParent( parent ) { }
CProfileTree::~CProfileTree() { delete m_pEditMenu; }
void CProfileTree::InvalidateLayout( bool layoutNow, bool reloadScheme ) { BaseClass::InvalidateLayout( layoutNow, reloadScheme ); if ( GetParent() ) { GetParent()->InvalidateLayout( layoutNow, reloadScheme ); } }
void CProfileTree::OnCommand( const char *cmd ) { // Relay to parent
GetParent()->OnCommand( cmd ); }
CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t() : treeViewItem( -1 ) { }
CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t( const ColumnPanels_t& src ) { treeViewItem = src.treeViewItem; int c = src.m_Columns.Count(); for ( int i = 0; i < c; ++i ) { PanelEntry_t pe; pe.dataname = src.m_Columns[ i ].dataname; pe.label = src.m_Columns[ i ].label;
m_Columns.AddToTail( pe ); } }
void CProfileHierarchyPanel::ColumnPanels_t::AddColumn( int index, const char *name, vgui::Label *label ) { m_Columns.EnsureCount( index + 1 );
m_Columns[ index ].label = label; m_Columns[ index ].dataname = name; }
void CProfileHierarchyPanel::ColumnPanels_t::Refresh( KeyValues *kv ) { VPROF( "CProfileHierarchyPanel::ColumnPanels_t" );
int c = m_Columns.Count(); for ( int i = 0; i < c; ++i ) { vgui::Label *label = m_Columns[ i ].label; if ( !label ) continue;
const char *name = m_Columns[ i ].dataname.String(); if ( name && name[ 0 ] ) { const char *value = kv->GetString( name, "" ); if ( value ) { if ( !value[ 0 ] ) { label->SetText( "" ); label->SetVisible( false ); } else { label->SetVisible( true ); label->SetText( value ); } } else { label->SetVisible( false ); } } } }
CProfileHierarchyPanel::CProfileHierarchyPanel(vgui::Panel *parent, const char *panelName) : BaseClass(parent,panelName), m_Panels( 0, 0, PanelsLessFunc ) { }
CProfileHierarchyPanel::~CProfileHierarchyPanel() { }
void CProfileHierarchyPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { //SetProportional( true );
BaseClass::ApplySchemeSettings( pScheme ); m_itemFont = pScheme->GetFont( PROF_FONT ); SetTitleBarInfo( m_itemFont, 20 ); SetBgColor( Color(0, 0, 0, 176) ); (( CProfileTree *)GetTree())->SetBgColor( Color( 0, 0, 0, 176 ) ); }
void CProfileHierarchyPanel::SetItemColors( int id, const Color& fg, const Color& bg ) { VPROF( "CProfileHierarchyPanel::SetItemColors" ); GetTree()->SetItemFgColor( id, fg ); GetTree()->SetItemBgColor( id, bg ); ColumnPanels_t search; search.treeViewItem = id; int idx = m_Panels.Find( search ); if ( idx == m_Panels.InvalidIndex() ) { return; } ColumnPanels_t& info = m_Panels[ idx ]; int c = info.m_Columns.Count(); for ( int i = 0; i < c; ++i ) { Label *label = info.m_Columns[ i ].label; if ( !label ) continue; label->SetFgColor( fg ); label->SetBgColor( bg ); } }
void CProfileHierarchyPanel::SetItemColumnColors( int id, int col, const Color& fg, const Color& bg ) { VPROF( "CProfileHierarchyPanel::SetItemColumnColors" ); ColumnPanels_t search; search.treeViewItem = id; int idx = m_Panels.Find( search ); if ( idx == m_Panels.InvalidIndex() ) { return; } ColumnPanels_t& info = m_Panels[ idx ]; int c = info.m_Columns.Count(); if ( col < 0 || col >= c ) return;
Label *label = info.m_Columns[ col ].label; if ( !label ) return;
label->SetFgColor( fg ); label->SetBgColor( bg ); }
void CProfileHierarchyPanel::ModifyItem( KeyValues *data, int itemIndex ) { GetTree()->SetItemFgColor( itemIndex, GetFgColor() ); GetTree()->SetItemBgColor( itemIndex, GetBgColor() );
ColumnPanels_t search; search.treeViewItem = itemIndex; int idx = m_Panels.Find( search ); if ( idx == m_Panels.InvalidIndex() ) { Assert( 0 ); return; }
ColumnPanels_t& info = m_Panels[ idx ]; info.Refresh( data ); }
int CProfileHierarchyPanel::AddItem( KeyValues *data, int parentItemIndex, ColumnPanels_t& columnPanels ) { int itemIndex = GetTree()->AddItem( data, parentItemIndex ); columnPanels.treeViewItem = itemIndex; ColumnPanels_t search; search.treeViewItem = itemIndex;
int idx = m_Panels.Find( search ); if ( idx == m_Panels.InvalidIndex() ) { m_Panels.Insert( columnPanels );
int c = columnPanels.m_Columns.Count(); for ( int i = 0; i < c; ++i ) { if ( columnPanels.m_Columns[ i ].label ) { columnPanels.m_Columns[ i ].label->SetParent( this ); } } }
ModifyItem( data, itemIndex );
return itemIndex; }
void CProfileHierarchyPanel::PostChildPaint() { }
void CProfileHierarchyPanel::PerformLayout() { VPROF( "CProfileHierarchyPanel::PerformLayout" ); BaseClass::PerformLayout();
// Assume all invisible at first
HideAll();
int tall = GetTall();
int rowheight = GetTree()->GetRowHeight(); int top, visitems; bool hbarVisible = false; GetTree()->GetVBarInfo( top, visitems, hbarVisible );
int offset = -top * rowheight;
int numColumns = GetNumColumns(); // Now position column panels into the correct spot
int rows = GetNumRows(); for ( int row = 0; row < rows; ++row ) { int tvi = GetTreeItemAtRow( row );
for ( int col = 0; col < numColumns; ++col ) { int left, top, right, bottom; GetGridElementBounds( col, row, left, top, right, bottom );
ColumnPanels_t search; search.treeViewItem = tvi;
int idx = m_Panels.Find( search ); if ( idx != m_Panels.InvalidIndex() ) { ColumnPanels_t& info = m_Panels[ idx ];
if ( col >= info.m_Columns.Count() ) continue;
vgui::Label *p = info.m_Columns[ col ].label; if ( !p ) { continue; } bool vis = ( top + offset - 20 ) >= 0 && ( bottom + offset ) < tall;
p->SetParent( vis ? this : NULL ); p->SetVisible( vis ); p->SetBounds( left, top + offset, right - left, bottom - top ); p->InvalidateLayout(); } else { Assert( 0 ); } } } }
void CProfileHierarchyPanel::HideAll() { for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) ) { ColumnPanels_t& info = m_Panels[ i ]; int c = info.m_Columns.Count(); for ( int j = 0 ; j < c; ++j ) { Label *panel = info.m_Columns[ j ].label; if ( !panel ) { continue; } panel->SetVisible( false ); } } }
void CProfileHierarchyPanel::RemoveAll() { GetTree()->RemoveAll();
for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) ) { ColumnPanels_t& info = m_Panels[ i ]; int c = info.m_Columns.Count(); for ( int j = 0 ; j < c; ++j ) { delete info.m_Columns[ j ].label; } info.m_Columns.RemoveAll(); } m_Panels.RemoveAll(); InvalidateLayout(); }
void CProfileHierarchyPanel::ExpandItem(int itemIndex, bool bExpand) { GetTree()->ExpandItem( itemIndex, bExpand ); }
bool CProfileHierarchyPanel::IsItemExpanded( int itemIndex ) { return GetTree()->IsItemExpanded( itemIndex ); }
KeyValues *CProfileHierarchyPanel::GetItemData(int itemIndex) { return GetTree()->GetItemData( itemIndex ); }
//-----------------------------------------------------------------------------
// Purpose: Create the VProf panel
//-----------------------------------------------------------------------------
CVProfPanel::CVProfPanel( vgui::Panel *pParent, const char *pElementName ) : vgui::Frame( pParent, pElementName ) { m_pVProfile = g_pVProfileForDisplay;
Assert( g_pVProfPanel == NULL ); g_pVProfPanel = this;
m_RootItem = -1; m_fShowVprofHeld = false;
int x = VPROF_INDENT_X; int y = VPROF_INDENT_Y; int wide = videomode->GetModeWidth() - x * 2; int tall = videomode->GetModeHeight() - y * 2; SetBgColor(Color(0, 0, 0, 175));
// Initialize the top title.
#ifdef VPROF_ENABLED
SetTitle("VProf", false); #else
SetTitle("** VProf is not enabled **", false); #endif
SetZPos( 1002 );
CProfileTree *profileTree = new CProfileTree( this, "ProfileTree" );
m_pHierarchy = new CProfileHierarchyPanel( this, "Hierarchy" );
m_pHierarchy->SetTreeView( profileTree ); m_pHierarchy->SetNumColumns( 3 );
int treewide = wide - 780; m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
m_pHierarchy->SetColumnInfo( 1, "Group", 120 ); m_pHierarchy->SetColumnInfo( 2, "Data", 180 );
// Treeview of the hierarchical calls
m_pHierarchy->SetBounds(X_BORDER, VPROF_TITLE_SIZE_Y, wide - X_BORDER*2, tall - Y_BORDER*2 - VPROF_TITLE_SIZE_Y); m_pHierarchy->SetParent(this); m_pHierarchy->SetPaintBorderEnabled( false ); m_pHierarchy->SetPaintBackgroundEnabled( false );
SETUP_PANEL( m_pHierarchy ); SETUP_PANEL( profileTree );
// Mode selection used to populate the tree view + lists
m_pVProfCategory = new ComboBox(this, "CategoryCombo", 5, false); m_pVProfCategory->AddItem( "All Categories", NULL ); m_pVProfCategory->AddActionSignalTarget( this ); m_pVProfCategory->ActivateItem( 0 );
m_pVProfSort = new ComboBox( this, "SortCombo", 5, false ); m_pVProfSort->AddItem( "By Time", NULL ); m_pVProfSort->AddItem( "By Name", NULL ); m_pVProfSort->AddItem( "By Budget Group", NULL ); m_pVProfSort->AddActionSignalTarget( this ); m_pVProfSort->ActivateItem( 0 );
m_nLastBudgetGroupCount = 0; m_nCurrentBudgetGroup = -1;
m_pHierarchicalView = new vgui::CheckButton( this, "HierarchicalViewSelection", "" ); m_pHierarchicalView->AddActionSignalTarget( this ); m_pHierarchicalView->SetSelected( true ); m_bHierarchicalView = true;
m_pRedoSort = new vgui::Button( this, "RedoSorting", "", this, "redosort" );
m_pVerbose = new vgui::CheckButton( this, "VerboseCheckbox", "" ); m_pVerbose->AddActionSignalTarget( this ); m_pVerbose->SetSelected( vprof_verbose.GetBool() );
// Setup the playback controls.
m_pPlaybackLabel = new vgui::Label( this, "PlaybackLabel", "" ); m_pPlaybackLabel->SetBgColor( Color( 0, 0, 0, 200 ) ); m_pPlaybackLabel->SetPaintBackgroundEnabled( true ); m_pStepForward = new vgui::Button( this, "StepForward", "", this, "StepForward" ); m_pStepBack = new vgui::Button( this, "StepBack", "", this, "StepBack" ); m_pGotoButton = new vgui::Button( this, "GotoButton", "", this, "GotoButton" ); m_pPlaybackScroll = new vgui::ScrollBar( this, "PlaybackScroll", false ); m_pPlaybackScroll->SetRange( 0, 1000 ); m_pPlaybackScroll->SetRangeWindow( 30 ); m_pPlaybackScroll->AddActionSignalTarget( this ); m_iLastPlaybackTick = -1;
LoadControlSettings("Resource\\VProfPanel.res");
SetBounds( x, y, wide, tall );
vgui::ivgui()->AddTickSignal( GetVPanel() ); }
CVProfPanel::~CVProfPanel( void ) { Assert( g_pVProfPanel == this ); g_pVProfPanel = NULL; }
#define DATA_FMT_STR "%-30.30s %-30.30s %-45.45s %-10.10s"
void CVProfPanel::PerformLayout() { BaseClass::PerformLayout();
int w, h; GetSize( w, h );
int topoffset = 95; int inset = 10;
m_pHierarchy->SetBounds( inset, topoffset, w - 2 * inset, h - inset - topoffset );
int treewide = w - 900 - 20; treewide = MAX( treewide, 240 ); m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
m_pHierarchy->SetColumnInfo( 1, "Group", 125 ); char header[ 512 ]; Q_snprintf( header, sizeof( header ), DATA_FMT_STR, "Frame Calls + Time + NoChild", "Avg Calls + Time + NoChild", "Sum Calls + Time + NoChild + Peak", "L2Miss" );
m_pHierarchy->SetColumnInfo( 2, header, 775, CTreeViewListControl::CI_HEADER_LEFTALIGN ); }
//-----------------------------------------------------------------------------
// Scheme settings!
//-----------------------------------------------------------------------------
void CVProfPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme );
IBorder *border = pScheme->GetBorder( "ToolTipBorder" ); SetBorder(border);
SetBgColor(Color(0, 0, 0, 175)); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *command -
//-----------------------------------------------------------------------------
void CVProfPanel::Close() { UserCmd_HideVProf(); BaseClass::Close(); }
//-----------------------------------------------------------------------------
// Is it visible?
//-----------------------------------------------------------------------------
void CVProfPanel::OnTick() { BaseClass::OnTick(); // Did the CVProfile we're using switch behind our back?
if ( g_pVProfileForDisplay != m_pVProfile ) { Reset(); m_pVProfile = g_pVProfileForDisplay;
bool bVisible = false;
if ( VProfRecord_IsPlayingBack() ) { bVisible = true; m_iLastPlaybackTick = -1; }
m_pStepForward->SetVisible( bVisible ); m_pStepBack->SetVisible( bVisible ); m_pPlaybackLabel->SetVisible( bVisible ); m_pPlaybackScroll->SetVisible( bVisible ); m_pGotoButton->SetVisible( bVisible ); }
if ( VProfRecord_IsPlayingBack() ) { // Update the playback tick.
int iCur = VProfPlayback_GetCurrentTick(); if ( iCur != m_iLastPlaybackTick ) { char str[512]; Q_snprintf( str, sizeof( str ), "VPROF playback (tick %d, %d%%)", iCur, (int)(VProfPlayback_GetCurrentPercent() * 100) ); m_pPlaybackLabel->SetText( str ); } }
SetVisible( m_fShowVprofHeld ? true : false );
m_pRedoSort->SetVisible( !m_bHierarchicalView ); }
// 0 = By Time
// 1 = By "Text"
// 2 = By "group" then by "text"
static int g_nSortType = -1; //-----------------------------------------------------------------------------
// Visualization changed
//-----------------------------------------------------------------------------
void CVProfPanel::OnTextChanged( KeyValues *data ) { Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") ); vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel );
if( pBox == m_pVProfCategory ) { // The -1 here is for the 'All Categories' item
m_nCurrentBudgetGroup = pBox->GetActiveItem() - 1;
// NOTE: We have to reset the tree view so that it
// is populated with only the ones we want (need to eliminate everything
// that's not appropriate)
Reset(); return; } if ( pBox == m_pVProfSort ) { g_nSortType = pBox->GetActiveItem(); Reset(); return; } }
//-----------------------------------------------------------------------------
// Sort function for hierarchical data
//-----------------------------------------------------------------------------
bool ChildCostSortFunc(KeyValues *pNode1, KeyValues *pNode2) { switch ( g_nSortType ) { default: case 0: case -1: { float flTime1 = pNode1->GetFloat( "Time", -1.0f ); float flTime2 = pNode2->GetFloat( "Time", -1.0f ); return (flTime1 > flTime2); } case 1: { const char *t1 = pNode1->GetString( "Text", "" ); const char *t2 = pNode2->GetString( "Text", "" ); if( Q_stricmp( t1, t2 ) <= 0 ) return true; return false; } break; case 2: { const char *g1 = pNode1->GetString( "group", "" ); const char *g2 = pNode2->GetString( "group", "" ); int val = Q_stricmp( g1, g2 ); if( val < 0 ) return true; if ( val > 0 ) return false;
const char *t1 = pNode1->GetString( "Text", "" ); const char *t2 = pNode2->GetString( "Text", "" ); if( Q_stricmp( t1, t2 ) <= 0 ) return true; return false; } }
return false; }
//-----------------------------------------------------------------------------
// Changes the visualization method for vprof data
//-----------------------------------------------------------------------------
void CVProfPanel::OnCheckButtonChecked(Panel *panel) { if ( panel == m_pHierarchicalView ) { bool bSelected = m_pHierarchicalView->IsSelected() ? 1 : 0; if ( bSelected != m_bHierarchicalView ) { m_bHierarchicalView = bSelected; m_pHierarchy->GetTree()->SetSortFunc( m_bHierarchicalView ? NULL : ChildCostSortFunc ); m_pRedoSort->SetVisible( !m_bHierarchicalView ); Reset(); } return; }
if ( panel == m_pVerbose ) { vprof_verbose.SetValue( m_pVerbose->IsSelected() ? 1 : 0 ); return; } }
//-----------------------------------------------------------------------------
// Methods related to expand/collapse in hierarchy
//-----------------------------------------------------------------------------
void CVProfPanel::ExpandAll( void ) { int count = m_pHierarchy->GetTree()->GetHighestItemID(); int i; for( i = 0; i < count; i++ ) { if( m_pHierarchy->GetTree()->IsItemIDValid( i ) ) { m_pHierarchy->GetTree()->ExpandItem( i, true ); } } }
void CVProfPanel::CollapseAll( void ) { int count = m_pHierarchy->GetTree()->GetHighestItemID(); int i; for( i = 1; i < count; i++ ) { if( m_pHierarchy->GetTree()->IsItemIDValid( i ) ) { m_pHierarchy->GetTree()->ExpandItem( i, false ); } } }
void CVProfPanel::ExpandGroupRecursive( int nBudgetGroupID, CVProfNode *pNode ) { if( !pNode ) { return; } if( pNode->GetBudgetGroupID() == nBudgetGroupID ) { CVProfNode *pTempNode = pNode; while( pTempNode ) { if( pTempNode->GetParent() ) { int id = pTempNode->GetParent()->GetClientData(); m_pHierarchy->ExpandItem( id, true ); } pTempNode = pTempNode->GetParent(); } }
ExpandGroupRecursive( nBudgetGroupID, pNode->GetChild() ); ExpandGroupRecursive( nBudgetGroupID, pNode->GetSibling() ); }
void CVProfPanel::ExpandGroup( const char *pGroupName ) { int groupID = m_pVProfile->BudgetGroupNameToBudgetGroupID( pGroupName ); ExpandGroupRecursive( groupID, m_pVProfile->GetRoot() ); }
class CVProfLabel : public Label { DECLARE_CLASS_SIMPLE( CVProfLabel, Label ); public:
CVProfLabel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName, "" ) { //SetPaintBackgroundEnabled( false );
}
virtual void ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); SetFont( pScheme->GetFont( PROF_FONT ) ); SetBgColor( Color( 0, 0, 0, 255 ) ); } };
Label *AllocateVprofLabel( const char *panelName ) { CVProfLabel *l = new CVProfLabel( NULL, panelName ); l->SetContentAlignment( Label::a_west ); return l; }
void CVProfPanel::AddColumns( CProfileHierarchyPanel::ColumnPanels_t& cp ) { cp.AddColumn( 1, "group", AllocateVprofLabel( "group" ) ); cp.AddColumn( 2, "data", AllocateVprofLabel( "data" ) ); }
//-----------------------------------------------------------------------------
// Populate the tree
//-----------------------------------------------------------------------------
int CVProfPanel::UpdateVProfTreeEntry( KeyValues *pKeyValues, CVProfNode *pNode, int parent ) { VPROF( "UpdateVProfTreeEntry" );
CFmtStrN<1024> msg; double curTimeLessChildren = pNode->GetCurTimeLessChildren(); double avgLessChildren = ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTimeLessChildren() / (double)pNode->GetTotalCalls() : 0;
pKeyValues->SetString( "Text", pNode->GetName() ); pKeyValues->SetString( "group", m_pVProfile->GetBudgetGroupName( pNode->GetBudgetGroupID() ) );
CFmtStrN< 256 > frame; CFmtStrN< 256 > avgstr; CFmtStrN< 256 > sum; CFmtStrN< 256 > l2miss;
frame.sprintf( "[%4d] %7.2f %7.2f", pNode->GetCurCalls(), pNode->GetCurTime(), curTimeLessChildren ); pKeyValues->SetString( "frame", msg );
if( vprof_verbose.GetBool() ) { double avgCalls = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalCalls() / (double)m_pVProfile->NumFramesSampled() : 0; double avg = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTime() / (double)m_pVProfile->NumFramesSampled() : 0; double avgLessChildren = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTimeLessChildren() / (double)m_pVProfile->NumFramesSampled() : 0;
avgstr.sprintf( "[%6.2f] %6.3f %6.3f", avgCalls, avg, avgLessChildren ); sum.sprintf( "[%7d] %9.2f %9.2f %8.2fp", pNode->GetTotalCalls(), pNode->GetTotalTime(), pNode->GetTotalTimeLessChildren(), pNode->GetPeakTime() ); }
if ( m_pVProfile->UsePME() ) { l2miss.sprintf( "%5d", pNode->GetL2CacheMisses() ); }
msg.sprintf( DATA_FMT_STR, (const char *)frame, (const char *)avgstr, (const char *)sum, (const char *)l2miss ); pKeyValues->SetString( "data", msg );
pKeyValues->SetFloat( "Time", avgLessChildren );
// Add or modify a line in the hierarchy
int id = pNode->GetClientData(); if ( id == -1 ) { CProfileHierarchyPanel::ColumnPanels_t cp; AddColumns( cp ); id = m_pHierarchy->AddItem( pKeyValues, parent, cp ) ; pNode->SetClientData( id ); } else { VPROF( "UpdateVProfTreeEntry:Modify" ); m_pHierarchy->ModifyItem( pKeyValues, id ); }
// Apply color to the item
int r,g,b,a; m_pVProfile->GetBudgetGroupColor( pNode->GetBudgetGroupID(), r, g, b, a ); m_pHierarchy->SetItemColors( id, Color( r, g, b, a ), Color( 0, 0, 0, 255 ) );
if( pNode->GetBudgetGroupID() == VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) { if ( curTimeLessChildren > vprof_unaccounted_limit.GetFloat() ) { m_pHierarchy->SetItemColors( id, Color( 255, 0, 0, 255 ), Color( 0, 0, 0, 255 ) ); } }
if ( pNode->GetCurTime() > vprof_warningmsec.GetFloat() || curTimeLessChildren > vprof_warningmsec.GetFloat() ) { m_pHierarchy->SetItemColumnColors( id, 2, Color( 255, 0, 0, 255 ), Color( 63, 0, 0, 255 ) ); } return id; }
//-----------------------------------------------------------------------------
// Populate the tree
//-----------------------------------------------------------------------------
void CVProfPanel::FillTree( KeyValues *pKeyValues, CVProfNode *pNode, int parent ) { #ifdef VPROF_ENABLED
bool fIsRoot = ( pNode == m_pVProfile->GetRoot() ); if ( fIsRoot ) { if( pNode->GetChild() ) { FillTree( pKeyValues, pNode->GetChild(), parent ); } return; }
int id = parent; if (( m_nCurrentBudgetGroup < 0 ) || ( pNode->GetBudgetGroupID() == m_nCurrentBudgetGroup )) { id = UpdateVProfTreeEntry( pKeyValues, pNode, parent ); }
if( pNode->GetSibling() ) { FillTree( pKeyValues, pNode->GetSibling(), parent ); } if( pNode->GetChild() ) { FillTree( pKeyValues, pNode->GetChild(), m_bHierarchicalView ? id : parent ); } #endif
}
//-----------------------------------------------------------------------------
// Populates the budget group combo box
//-----------------------------------------------------------------------------
void CVProfPanel::PopulateBudgetGroupComboBox() { int nBudgetGroupCount = m_pVProfile->GetNumBudgetGroups(); while( m_nLastBudgetGroupCount < nBudgetGroupCount ) { m_pVProfCategory->AddItem( m_pVProfile->GetBudgetGroupName(m_nLastBudgetGroupCount), NULL ); ++m_nLastBudgetGroupCount; } }
//-----------------------------------------------------------------------------
// Populates the tree
//-----------------------------------------------------------------------------
void CVProfPanel::UpdateProfile( float filteredtime ) { #ifdef VPROF_ENABLED
//ExecuteDeferredOp();
if (IsVisible()) { PopulateBudgetGroupComboBox();
SetTitle( CFmtStr( "VProf (%s) -- %d frames sampled", m_pVProfile->IsEnabled() ? "running" : "not running", m_pVProfile->NumFramesSampled() ), false );
// It's important to cache bEnabled since calling pause can disable.
bool bEnabled = m_pVProfile->IsEnabled(); if( bEnabled ) { m_pVProfile->Pause(); }
KeyValues * pVal = new KeyValues(""); if ( !m_pHierarchy->GetTree()->GetItemCount() ) { pVal->SetString( "Text", "Call tree" ); CProfileHierarchyPanel::ColumnPanels_t cp; AddColumns( cp ); m_RootItem = m_pHierarchy->AddItem( pVal, -1, cp ); m_pHierarchy->SetItemColors( m_RootItem, Color( 255, 255, 255, 255 ), Color( 0, 0, 0, 255 ) ); m_pHierarchy->ExpandItem( m_RootItem, true ); }
m_pHierarchy->ExpandItem( m_RootItem, true );
const char *pScope = vprof_scope.GetString(); CVProfNode *pStartNode = ( pScope[0] == 0 ) ? m_pVProfile->GetRoot() : m_pVProfile->FindNode(m_pVProfile->GetRoot(), pScope ); if ( pStartNode ) { FillTree( pVal, pStartNode, m_RootItem ); } pVal->deleteThis();
if( bEnabled ) { m_pVProfile->Resume(); } }
if ( m_pVProfile->IsEnabled() ) { Assert( m_pVProfile->AtRoot() ); if ( GetBudgetPanel()->IsBudgetPanelShown() ) GetBudgetPanel()->SnapshotVProfHistory( filteredtime );
WriteRemoteVProfData(); // send out the vprof data to remote endpoints
} #endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVProfPanel::UserCmd_ShowVProf( void ) { m_fShowVprofHeld = true;
SetVisible( true ); // This is hacky . . need to at least remember the previous value to set it back.
ConVarRef cl_mouseenable( "cl_mouseenable" ); if ( cl_mouseenable.IsValid() ) { cl_mouseenable.SetValue( 0 ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVProfPanel::UserCmd_HideVProf( void ) { m_fShowVprofHeld = false;
SetVisible( false );
// This is hacky . . need to at least remember the previous value to set it back.
ConVarRef cl_mouseenable( "cl_mouseenable" ); if ( cl_mouseenable.IsValid() ) { cl_mouseenable.SetValue( 1 ); } }
//-----------------------------------------------------------------------------
void CVProfPanel::Paint() { m_pVProfile->Pause(); BaseClass::Paint(); m_pVProfile->Resume(); }
void CVProfPanel::OnCommand( const char *pCommand ) { if ( !Q_stricmp( pCommand, "StepForward" ) ) { VProfPlayback_Step(); } else if ( !Q_stricmp( pCommand, "StepBack" ) ) { int shouldReset = VProfPlayback_StepBack(); if ( shouldReset == 2 ) { Reset(); } } else if ( !Q_stricmp( pCommand, "GotoButton" ) ) { int shouldReset = VProfPlayback_SeekToPercent( (float)m_pPlaybackScroll->GetValue() / 1000.0 ); if ( shouldReset == 2 ) { Reset(); } } else if ( !Q_stricmp( pCommand, "redosort" ) ) { //
Assert( !m_bHierarchicalView ); Reset(); } }
#endif
|