Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1153 lines
29 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: VGUI scoreboard
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "client_pch.h"
  10. #include "vgui_vprofpanel.h"
  11. #include <keyvalues.h>
  12. #include "vgui_budgetpanel.h"
  13. #include "vprof_engine.h"
  14. #include "vprof_record.h"
  15. #include "ivideomode.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. using namespace vgui;
  19. // positions
  20. #define VPROF_INDENT_X XRES(20)
  21. #define VPROF_INDENT_Y YRES(10)
  22. // Scoreboard dimensions
  23. #define VPROF_TITLE_SIZE_Y YRES(22)
  24. #define X_BORDER XRES(4)
  25. #define Y_BORDER YRES(4)
  26. static ConVar vprof_verbose( "vprof_verbose", "1", FCVAR_ARCHIVE, "Set to one to show average and peak times" );
  27. static ConVar vprof_unaccounted_limit( "vprof_unaccounted_limit", "0.3", FCVAR_ARCHIVE,
  28. "number of milliseconds that a node must exceed to turn red in the vprof panel" );
  29. static ConVar vprof_warningmsec( "vprof_warningmsec", "10", FCVAR_ARCHIVE, "Above this many milliseconds render the label red to indicate slow code." );
  30. #ifdef VPROF_ENABLED
  31. //-----------------------------------------------------------------------------
  32. // Singleton accessor
  33. //-----------------------------------------------------------------------------
  34. static CVProfPanel *g_pVProfPanel = NULL;
  35. CVProfPanel *GetVProfPanel( void )
  36. {
  37. return g_pVProfPanel;
  38. }
  39. static void ClearNodeClientData( CVProfNode *pNode )
  40. {
  41. pNode->SetClientData( -1 );
  42. if( pNode->GetSibling() )
  43. {
  44. ClearNodeClientData( pNode->GetSibling() );
  45. }
  46. if( pNode->GetChild() )
  47. {
  48. ClearNodeClientData( pNode->GetChild() );
  49. }
  50. }
  51. void CVProfPanel::Reset()
  52. {
  53. m_pHierarchy->RemoveAll();
  54. m_RootItem = -1;
  55. ClearNodeClientData( m_pVProfile->GetRoot() );
  56. }
  57. CON_COMMAND( vprof_expand_all, "Expand the whole vprof tree" )
  58. {
  59. Msg("VProf expand all.\n");
  60. GetVProfPanel()->ExpandAll();
  61. }
  62. CON_COMMAND( vprof_collapse_all, "Collapse the whole vprof tree" )
  63. {
  64. Msg("VProf collapse all.\n");
  65. GetVProfPanel()->CollapseAll();
  66. }
  67. CON_COMMAND( vprof_expand_group, "Expand a budget group in the vprof tree by name" )
  68. {
  69. Msg("VProf expand group.\n");
  70. if ( args.ArgC() >= 2 )
  71. {
  72. GetVProfPanel()->ExpandGroup( args[ 1 ] );
  73. }
  74. }
  75. void IN_VProfDown(void)
  76. {
  77. GetVProfPanel()->UserCmd_ShowVProf();
  78. }
  79. void IN_VProfUp(void)
  80. {
  81. GetVProfPanel()->UserCmd_HideVProf();
  82. }
  83. static ConCommand startshowvprof("+showvprof", IN_VProfDown);
  84. static ConCommand endshowvprof("-showvprof", IN_VProfUp);
  85. void ChangeVProfScopeCallback( IConVar *pConVar, const char *pOldString, float flOldValue )
  86. {
  87. ConVarRef var( pConVar );
  88. Msg( "VProf setting scope to %s\n", var.GetString( ) );
  89. if ( g_pVProfPanel )
  90. {
  91. g_pVProfPanel->Reset();
  92. }
  93. }
  94. ConVar vprof_scope(
  95. "vprof_scope",
  96. "",
  97. 0,
  98. "Set a specific scope to start showing vprof tree",
  99. 0, 0, 0, 0,
  100. ChangeVProfScopeCallback );
  101. #define PROF_FONT "DefaultFixed"
  102. class CProfileTree : public TreeView
  103. {
  104. DECLARE_CLASS_SIMPLE( CProfileTree, TreeView );
  105. public:
  106. CProfileTree( CVProfPanel *parent, const char *panelName );
  107. ~CProfileTree();
  108. virtual void OnCommand( const char *cmd );
  109. virtual void InvalidateLayout( bool layoutNow = false, bool reloadScheme = false );
  110. virtual void ApplySchemeSettings( IScheme *pScheme )
  111. {
  112. BaseClass::ApplySchemeSettings( pScheme );
  113. SetFont( pScheme->GetFont( PROF_FONT ) );
  114. }
  115. virtual void SetBgColor( Color color )
  116. {
  117. BaseClass::SetBgColor( color );
  118. }
  119. private:
  120. Menu *m_pEditMenu;
  121. CVProfPanel *m_pParent;
  122. };
  123. CProfileTree::CProfileTree( CVProfPanel *parent, const char *panelName ) :
  124. BaseClass( (Panel *)parent, panelName ),
  125. m_pEditMenu( 0 ),
  126. m_pParent( parent )
  127. {
  128. }
  129. CProfileTree::~CProfileTree()
  130. {
  131. delete m_pEditMenu;
  132. }
  133. void CProfileTree::InvalidateLayout( bool layoutNow, bool reloadScheme )
  134. {
  135. BaseClass::InvalidateLayout( layoutNow, reloadScheme );
  136. if ( GetParent() )
  137. {
  138. GetParent()->InvalidateLayout( layoutNow, reloadScheme );
  139. }
  140. }
  141. void CProfileTree::OnCommand( const char *cmd )
  142. {
  143. // Relay to parent
  144. GetParent()->OnCommand( cmd );
  145. }
  146. CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t() :
  147. treeViewItem( -1 )
  148. {
  149. }
  150. CProfileHierarchyPanel::ColumnPanels_t::ColumnPanels_t( const ColumnPanels_t& src )
  151. {
  152. treeViewItem = src.treeViewItem;
  153. int c = src.m_Columns.Count();
  154. for ( int i = 0; i < c; ++i )
  155. {
  156. PanelEntry_t pe;
  157. pe.dataname = src.m_Columns[ i ].dataname;
  158. pe.label = src.m_Columns[ i ].label;
  159. m_Columns.AddToTail( pe );
  160. }
  161. }
  162. void CProfileHierarchyPanel::ColumnPanels_t::AddColumn( int index, const char *name, vgui::Label *label )
  163. {
  164. m_Columns.EnsureCount( index + 1 );
  165. m_Columns[ index ].label = label;
  166. m_Columns[ index ].dataname = name;
  167. }
  168. void CProfileHierarchyPanel::ColumnPanels_t::Refresh( KeyValues *kv )
  169. {
  170. VPROF( "CProfileHierarchyPanel::ColumnPanels_t" );
  171. int c = m_Columns.Count();
  172. for ( int i = 0; i < c; ++i )
  173. {
  174. vgui::Label *label = m_Columns[ i ].label;
  175. if ( !label )
  176. continue;
  177. const char *name = m_Columns[ i ].dataname.String();
  178. if ( name && name[ 0 ] )
  179. {
  180. const char *value = kv->GetString( name, "" );
  181. if ( value )
  182. {
  183. if ( !value[ 0 ] )
  184. {
  185. label->SetText( "" );
  186. label->SetVisible( false );
  187. }
  188. else
  189. {
  190. label->SetVisible( true );
  191. label->SetText( value );
  192. }
  193. }
  194. else
  195. {
  196. label->SetVisible( false );
  197. }
  198. }
  199. }
  200. }
  201. CProfileHierarchyPanel::CProfileHierarchyPanel(vgui::Panel *parent, const char *panelName)
  202. : BaseClass(parent,panelName),
  203. m_Panels( 0, 0, PanelsLessFunc )
  204. {
  205. }
  206. CProfileHierarchyPanel::~CProfileHierarchyPanel()
  207. {
  208. }
  209. void CProfileHierarchyPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  210. {
  211. //SetProportional( true );
  212. BaseClass::ApplySchemeSettings( pScheme );
  213. m_itemFont = pScheme->GetFont( PROF_FONT );
  214. SetTitleBarInfo( m_itemFont, 20 );
  215. SetBgColor( Color(0, 0, 0, 176) );
  216. (( CProfileTree *)GetTree())->SetBgColor( Color( 0, 0, 0, 176 ) );
  217. }
  218. void CProfileHierarchyPanel::SetItemColors( int id, const Color& fg, const Color& bg )
  219. {
  220. VPROF( "CProfileHierarchyPanel::SetItemColors" );
  221. GetTree()->SetItemFgColor( id, fg );
  222. GetTree()->SetItemBgColor( id, bg );
  223. ColumnPanels_t search;
  224. search.treeViewItem = id;
  225. int idx = m_Panels.Find( search );
  226. if ( idx == m_Panels.InvalidIndex() )
  227. {
  228. return;
  229. }
  230. ColumnPanels_t& info = m_Panels[ idx ];
  231. int c = info.m_Columns.Count();
  232. for ( int i = 0; i < c; ++i )
  233. {
  234. Label *label = info.m_Columns[ i ].label;
  235. if ( !label )
  236. continue;
  237. label->SetFgColor( fg );
  238. label->SetBgColor( bg );
  239. }
  240. }
  241. void CProfileHierarchyPanel::SetItemColumnColors( int id, int col, const Color& fg, const Color& bg )
  242. {
  243. VPROF( "CProfileHierarchyPanel::SetItemColumnColors" );
  244. ColumnPanels_t search;
  245. search.treeViewItem = id;
  246. int idx = m_Panels.Find( search );
  247. if ( idx == m_Panels.InvalidIndex() )
  248. {
  249. return;
  250. }
  251. ColumnPanels_t& info = m_Panels[ idx ];
  252. int c = info.m_Columns.Count();
  253. if ( col < 0 || col >= c )
  254. return;
  255. Label *label = info.m_Columns[ col ].label;
  256. if ( !label )
  257. return;
  258. label->SetFgColor( fg );
  259. label->SetBgColor( bg );
  260. }
  261. void CProfileHierarchyPanel::ModifyItem( KeyValues *data, int itemIndex )
  262. {
  263. GetTree()->SetItemFgColor( itemIndex, GetFgColor() );
  264. GetTree()->SetItemBgColor( itemIndex, GetBgColor() );
  265. ColumnPanels_t search;
  266. search.treeViewItem = itemIndex;
  267. int idx = m_Panels.Find( search );
  268. if ( idx == m_Panels.InvalidIndex() )
  269. {
  270. Assert( 0 );
  271. return;
  272. }
  273. ColumnPanels_t& info = m_Panels[ idx ];
  274. info.Refresh( data );
  275. }
  276. int CProfileHierarchyPanel::AddItem( KeyValues *data, int parentItemIndex, ColumnPanels_t& columnPanels )
  277. {
  278. int itemIndex = GetTree()->AddItem( data, parentItemIndex );
  279. columnPanels.treeViewItem = itemIndex;
  280. ColumnPanels_t search;
  281. search.treeViewItem = itemIndex;
  282. int idx = m_Panels.Find( search );
  283. if ( idx == m_Panels.InvalidIndex() )
  284. {
  285. m_Panels.Insert( columnPanels );
  286. int c = columnPanels.m_Columns.Count();
  287. for ( int i = 0; i < c; ++i )
  288. {
  289. if ( columnPanels.m_Columns[ i ].label )
  290. {
  291. columnPanels.m_Columns[ i ].label->SetParent( this );
  292. }
  293. }
  294. }
  295. ModifyItem( data, itemIndex );
  296. return itemIndex;
  297. }
  298. void CProfileHierarchyPanel::PostChildPaint()
  299. {
  300. }
  301. void CProfileHierarchyPanel::PerformLayout()
  302. {
  303. VPROF( "CProfileHierarchyPanel::PerformLayout" );
  304. BaseClass::PerformLayout();
  305. // Assume all invisible at first
  306. HideAll();
  307. int tall = GetTall();
  308. int rowheight = GetTree()->GetRowHeight();
  309. int top, visitems;
  310. bool hbarVisible = false;
  311. GetTree()->GetVBarInfo( top, visitems, hbarVisible );
  312. int offset = -top * rowheight;
  313. int numColumns = GetNumColumns();
  314. // Now position column panels into the correct spot
  315. int rows = GetNumRows();
  316. for ( int row = 0; row < rows; ++row )
  317. {
  318. int tvi = GetTreeItemAtRow( row );
  319. for ( int col = 0; col < numColumns; ++col )
  320. {
  321. int left, top, right, bottom;
  322. GetGridElementBounds( col, row, left, top, right, bottom );
  323. ColumnPanels_t search;
  324. search.treeViewItem = tvi;
  325. int idx = m_Panels.Find( search );
  326. if ( idx != m_Panels.InvalidIndex() )
  327. {
  328. ColumnPanels_t& info = m_Panels[ idx ];
  329. if ( col >= info.m_Columns.Count() )
  330. continue;
  331. vgui::Label *p = info.m_Columns[ col ].label;
  332. if ( !p )
  333. {
  334. continue;
  335. }
  336. bool vis = ( top + offset - 20 ) >= 0 && ( bottom + offset ) < tall;
  337. p->SetParent( vis ? this : NULL );
  338. p->SetVisible( vis );
  339. p->SetBounds( left, top + offset, right - left, bottom - top );
  340. p->InvalidateLayout();
  341. }
  342. else
  343. {
  344. Assert( 0 );
  345. }
  346. }
  347. }
  348. }
  349. void CProfileHierarchyPanel::HideAll()
  350. {
  351. for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) )
  352. {
  353. ColumnPanels_t& info = m_Panels[ i ];
  354. int c = info.m_Columns.Count();
  355. for ( int j = 0 ; j < c; ++j )
  356. {
  357. Label *panel = info.m_Columns[ j ].label;
  358. if ( !panel )
  359. {
  360. continue;
  361. }
  362. panel->SetVisible( false );
  363. }
  364. }
  365. }
  366. void CProfileHierarchyPanel::RemoveAll()
  367. {
  368. GetTree()->RemoveAll();
  369. for ( int i = m_Panels.FirstInorder(); i != m_Panels.InvalidIndex(); i = m_Panels.NextInorder( i ) )
  370. {
  371. ColumnPanels_t& info = m_Panels[ i ];
  372. int c = info.m_Columns.Count();
  373. for ( int j = 0 ; j < c; ++j )
  374. {
  375. delete info.m_Columns[ j ].label;
  376. }
  377. info.m_Columns.RemoveAll();
  378. }
  379. m_Panels.RemoveAll();
  380. InvalidateLayout();
  381. }
  382. void CProfileHierarchyPanel::ExpandItem(int itemIndex, bool bExpand)
  383. {
  384. GetTree()->ExpandItem( itemIndex, bExpand );
  385. }
  386. bool CProfileHierarchyPanel::IsItemExpanded( int itemIndex )
  387. {
  388. return GetTree()->IsItemExpanded( itemIndex );
  389. }
  390. KeyValues *CProfileHierarchyPanel::GetItemData(int itemIndex)
  391. {
  392. return GetTree()->GetItemData( itemIndex );
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Purpose: Create the VProf panel
  396. //-----------------------------------------------------------------------------
  397. CVProfPanel::CVProfPanel( vgui::Panel *pParent, const char *pElementName )
  398. : vgui::Frame( pParent, pElementName )
  399. {
  400. m_pVProfile = g_pVProfileForDisplay;
  401. Assert( g_pVProfPanel == NULL );
  402. g_pVProfPanel = this;
  403. m_RootItem = -1;
  404. m_fShowVprofHeld = false;
  405. int x = VPROF_INDENT_X;
  406. int y = VPROF_INDENT_Y;
  407. int wide = videomode->GetModeWidth() - x * 2;
  408. int tall = videomode->GetModeHeight() - y * 2;
  409. SetBgColor(Color(0, 0, 0, 175));
  410. // Initialize the top title.
  411. #ifdef VPROF_ENABLED
  412. SetTitle("VProf", false);
  413. #else
  414. SetTitle("** VProf is not enabled **", false);
  415. #endif
  416. SetZPos( 1002 );
  417. CProfileTree *profileTree = new CProfileTree( this, "ProfileTree" );
  418. m_pHierarchy = new CProfileHierarchyPanel( this, "Hierarchy" );
  419. m_pHierarchy->SetTreeView( profileTree );
  420. m_pHierarchy->SetNumColumns( 3 );
  421. int treewide = wide - 780;
  422. m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
  423. m_pHierarchy->SetColumnInfo( 1, "Group", 120 );
  424. m_pHierarchy->SetColumnInfo( 2, "Data", 180 );
  425. // Treeview of the hierarchical calls
  426. m_pHierarchy->SetBounds(X_BORDER, VPROF_TITLE_SIZE_Y, wide - X_BORDER*2, tall - Y_BORDER*2 - VPROF_TITLE_SIZE_Y);
  427. m_pHierarchy->SetParent(this);
  428. m_pHierarchy->SetPaintBorderEnabled( false );
  429. m_pHierarchy->SetPaintBackgroundEnabled( false );
  430. SETUP_PANEL( m_pHierarchy );
  431. SETUP_PANEL( profileTree );
  432. // Mode selection used to populate the tree view + lists
  433. m_pVProfCategory = new ComboBox(this, "CategoryCombo", 5, false);
  434. m_pVProfCategory->AddItem( "All Categories", NULL );
  435. m_pVProfCategory->AddActionSignalTarget( this );
  436. m_pVProfCategory->ActivateItem( 0 );
  437. m_pVProfSort = new ComboBox( this, "SortCombo", 5, false );
  438. m_pVProfSort->AddItem( "By Time", NULL );
  439. m_pVProfSort->AddItem( "By Name", NULL );
  440. m_pVProfSort->AddItem( "By Budget Group", NULL );
  441. m_pVProfSort->AddActionSignalTarget( this );
  442. m_pVProfSort->ActivateItem( 0 );
  443. m_nLastBudgetGroupCount = 0;
  444. m_nCurrentBudgetGroup = -1;
  445. m_pHierarchicalView = new vgui::CheckButton( this, "HierarchicalViewSelection", "" );
  446. m_pHierarchicalView->AddActionSignalTarget( this );
  447. m_pHierarchicalView->SetSelected( true );
  448. m_bHierarchicalView = true;
  449. m_pRedoSort = new vgui::Button( this, "RedoSorting", "", this, "redosort" );
  450. m_pVerbose = new vgui::CheckButton( this, "VerboseCheckbox", "" );
  451. m_pVerbose->AddActionSignalTarget( this );
  452. m_pVerbose->SetSelected( vprof_verbose.GetBool() );
  453. // Setup the playback controls.
  454. m_pPlaybackLabel = new vgui::Label( this, "PlaybackLabel", "" );
  455. m_pPlaybackLabel->SetBgColor( Color( 0, 0, 0, 200 ) );
  456. m_pPlaybackLabel->SetPaintBackgroundEnabled( true );
  457. m_pStepForward = new vgui::Button( this, "StepForward", "", this, "StepForward" );
  458. m_pStepBack = new vgui::Button( this, "StepBack", "", this, "StepBack" );
  459. m_pGotoButton = new vgui::Button( this, "GotoButton", "", this, "GotoButton" );
  460. m_pPlaybackScroll = new vgui::ScrollBar( this, "PlaybackScroll", false );
  461. m_pPlaybackScroll->SetRange( 0, 1000 );
  462. m_pPlaybackScroll->SetRangeWindow( 30 );
  463. m_pPlaybackScroll->AddActionSignalTarget( this );
  464. m_iLastPlaybackTick = -1;
  465. LoadControlSettings("Resource\\VProfPanel.res");
  466. SetBounds( x, y, wide, tall );
  467. vgui::ivgui()->AddTickSignal( GetVPanel() );
  468. }
  469. CVProfPanel::~CVProfPanel( void )
  470. {
  471. Assert( g_pVProfPanel == this );
  472. g_pVProfPanel = NULL;
  473. }
  474. #define DATA_FMT_STR "%-30.30s %-30.30s %-45.45s %-10.10s"
  475. void CVProfPanel::PerformLayout()
  476. {
  477. BaseClass::PerformLayout();
  478. int w, h;
  479. GetSize( w, h );
  480. int topoffset = 95;
  481. int inset = 10;
  482. m_pHierarchy->SetBounds( inset, topoffset, w - 2 * inset, h - inset - topoffset );
  483. int treewide = w - 900 - 20;
  484. treewide = MAX( treewide, 240 );
  485. m_pHierarchy->SetColumnInfo( 0, "Tree", treewide );
  486. m_pHierarchy->SetColumnInfo( 1, "Group", 125 );
  487. char header[ 512 ];
  488. Q_snprintf( header, sizeof( header ), DATA_FMT_STR,
  489. "Frame Calls + Time + NoChild",
  490. "Avg Calls + Time + NoChild",
  491. "Sum Calls + Time + NoChild + Peak",
  492. "L2Miss" );
  493. m_pHierarchy->SetColumnInfo( 2, header, 775, CTreeViewListControl::CI_HEADER_LEFTALIGN );
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Scheme settings!
  497. //-----------------------------------------------------------------------------
  498. void CVProfPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  499. {
  500. BaseClass::ApplySchemeSettings( pScheme );
  501. IBorder *border = pScheme->GetBorder( "ToolTipBorder" );
  502. SetBorder(border);
  503. SetBgColor(Color(0, 0, 0, 175));
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Purpose:
  507. // Input : *command -
  508. //-----------------------------------------------------------------------------
  509. void CVProfPanel::Close()
  510. {
  511. UserCmd_HideVProf();
  512. BaseClass::Close();
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Is it visible?
  516. //-----------------------------------------------------------------------------
  517. void CVProfPanel::OnTick()
  518. {
  519. BaseClass::OnTick();
  520. // Did the CVProfile we're using switch behind our back?
  521. if ( g_pVProfileForDisplay != m_pVProfile )
  522. {
  523. Reset();
  524. m_pVProfile = g_pVProfileForDisplay;
  525. bool bVisible = false;
  526. if ( VProfRecord_IsPlayingBack() )
  527. {
  528. bVisible = true;
  529. m_iLastPlaybackTick = -1;
  530. }
  531. m_pStepForward->SetVisible( bVisible );
  532. m_pStepBack->SetVisible( bVisible );
  533. m_pPlaybackLabel->SetVisible( bVisible );
  534. m_pPlaybackScroll->SetVisible( bVisible );
  535. m_pGotoButton->SetVisible( bVisible );
  536. }
  537. if ( VProfRecord_IsPlayingBack() )
  538. {
  539. // Update the playback tick.
  540. int iCur = VProfPlayback_GetCurrentTick();
  541. if ( iCur != m_iLastPlaybackTick )
  542. {
  543. char str[512];
  544. Q_snprintf( str, sizeof( str ), "VPROF playback (tick %d, %d%%)", iCur, (int)(VProfPlayback_GetCurrentPercent() * 100) );
  545. m_pPlaybackLabel->SetText( str );
  546. }
  547. }
  548. SetVisible( m_fShowVprofHeld ? true : false );
  549. m_pRedoSort->SetVisible( !m_bHierarchicalView );
  550. }
  551. // 0 = By Time
  552. // 1 = By "Text"
  553. // 2 = By "group" then by "text"
  554. static int g_nSortType = -1;
  555. //-----------------------------------------------------------------------------
  556. // Visualization changed
  557. //-----------------------------------------------------------------------------
  558. void CVProfPanel::OnTextChanged( KeyValues *data )
  559. {
  560. Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
  561. vgui::ComboBox *pBox = dynamic_cast<vgui::ComboBox *>( pPanel );
  562. if( pBox == m_pVProfCategory )
  563. {
  564. // The -1 here is for the 'All Categories' item
  565. m_nCurrentBudgetGroup = pBox->GetActiveItem() - 1;
  566. // NOTE: We have to reset the tree view so that it
  567. // is populated with only the ones we want (need to eliminate everything
  568. // that's not appropriate)
  569. Reset();
  570. return;
  571. }
  572. if ( pBox == m_pVProfSort )
  573. {
  574. g_nSortType = pBox->GetActiveItem();
  575. Reset();
  576. return;
  577. }
  578. }
  579. //-----------------------------------------------------------------------------
  580. // Sort function for hierarchical data
  581. //-----------------------------------------------------------------------------
  582. bool ChildCostSortFunc(KeyValues *pNode1, KeyValues *pNode2)
  583. {
  584. switch ( g_nSortType )
  585. {
  586. default:
  587. case 0:
  588. case -1:
  589. {
  590. float flTime1 = pNode1->GetFloat( "Time", -1.0f );
  591. float flTime2 = pNode2->GetFloat( "Time", -1.0f );
  592. return (flTime1 > flTime2);
  593. }
  594. case 1:
  595. {
  596. const char *t1 = pNode1->GetString( "Text", "" );
  597. const char *t2 = pNode2->GetString( "Text", "" );
  598. if( Q_stricmp( t1, t2 ) <= 0 )
  599. return true;
  600. return false;
  601. }
  602. break;
  603. case 2:
  604. {
  605. const char *g1 = pNode1->GetString( "group", "" );
  606. const char *g2 = pNode2->GetString( "group", "" );
  607. int val = Q_stricmp( g1, g2 );
  608. if( val < 0 )
  609. return true;
  610. if ( val > 0 )
  611. return false;
  612. const char *t1 = pNode1->GetString( "Text", "" );
  613. const char *t2 = pNode2->GetString( "Text", "" );
  614. if( Q_stricmp( t1, t2 ) <= 0 )
  615. return true;
  616. return false;
  617. }
  618. }
  619. return false;
  620. }
  621. //-----------------------------------------------------------------------------
  622. // Changes the visualization method for vprof data
  623. //-----------------------------------------------------------------------------
  624. void CVProfPanel::OnCheckButtonChecked(Panel *panel)
  625. {
  626. if ( panel == m_pHierarchicalView )
  627. {
  628. bool bSelected = m_pHierarchicalView->IsSelected() ? 1 : 0;
  629. if ( bSelected != m_bHierarchicalView )
  630. {
  631. m_bHierarchicalView = bSelected;
  632. m_pHierarchy->GetTree()->SetSortFunc( m_bHierarchicalView ? NULL : ChildCostSortFunc );
  633. m_pRedoSort->SetVisible( !m_bHierarchicalView );
  634. Reset();
  635. }
  636. return;
  637. }
  638. if ( panel == m_pVerbose )
  639. {
  640. vprof_verbose.SetValue( m_pVerbose->IsSelected() ? 1 : 0 );
  641. return;
  642. }
  643. }
  644. //-----------------------------------------------------------------------------
  645. // Methods related to expand/collapse in hierarchy
  646. //-----------------------------------------------------------------------------
  647. void CVProfPanel::ExpandAll( void )
  648. {
  649. int count = m_pHierarchy->GetTree()->GetHighestItemID();
  650. int i;
  651. for( i = 0; i < count; i++ )
  652. {
  653. if( m_pHierarchy->GetTree()->IsItemIDValid( i ) )
  654. {
  655. m_pHierarchy->GetTree()->ExpandItem( i, true );
  656. }
  657. }
  658. }
  659. void CVProfPanel::CollapseAll( void )
  660. {
  661. int count = m_pHierarchy->GetTree()->GetHighestItemID();
  662. int i;
  663. for( i = 1; i < count; i++ )
  664. {
  665. if( m_pHierarchy->GetTree()->IsItemIDValid( i ) )
  666. {
  667. m_pHierarchy->GetTree()->ExpandItem( i, false );
  668. }
  669. }
  670. }
  671. void CVProfPanel::ExpandGroupRecursive( int nBudgetGroupID, CVProfNode *pNode )
  672. {
  673. if( !pNode )
  674. {
  675. return;
  676. }
  677. if( pNode->GetBudgetGroupID() == nBudgetGroupID )
  678. {
  679. CVProfNode *pTempNode = pNode;
  680. while( pTempNode )
  681. {
  682. if( pTempNode->GetParent() )
  683. {
  684. int id = pTempNode->GetParent()->GetClientData();
  685. m_pHierarchy->ExpandItem( id, true );
  686. }
  687. pTempNode = pTempNode->GetParent();
  688. }
  689. }
  690. ExpandGroupRecursive( nBudgetGroupID, pNode->GetChild() );
  691. ExpandGroupRecursive( nBudgetGroupID, pNode->GetSibling() );
  692. }
  693. void CVProfPanel::ExpandGroup( const char *pGroupName )
  694. {
  695. int groupID = m_pVProfile->BudgetGroupNameToBudgetGroupID( pGroupName );
  696. ExpandGroupRecursive( groupID, m_pVProfile->GetRoot() );
  697. }
  698. class CVProfLabel : public Label
  699. {
  700. DECLARE_CLASS_SIMPLE( CVProfLabel, Label );
  701. public:
  702. CVProfLabel( Panel *parent, const char *panelName ) :
  703. BaseClass( parent, panelName, "" )
  704. {
  705. //SetPaintBackgroundEnabled( false );
  706. }
  707. virtual void ApplySchemeSettings( IScheme *pScheme )
  708. {
  709. BaseClass::ApplySchemeSettings( pScheme );
  710. SetFont( pScheme->GetFont( PROF_FONT ) );
  711. SetBgColor( Color( 0, 0, 0, 255 ) );
  712. }
  713. };
  714. Label *AllocateVprofLabel( const char *panelName )
  715. {
  716. CVProfLabel *l = new CVProfLabel( NULL, panelName );
  717. l->SetContentAlignment( Label::a_west );
  718. return l;
  719. }
  720. void CVProfPanel::AddColumns( CProfileHierarchyPanel::ColumnPanels_t& cp )
  721. {
  722. cp.AddColumn( 1, "group", AllocateVprofLabel( "group" ) );
  723. cp.AddColumn( 2, "data", AllocateVprofLabel( "data" ) );
  724. }
  725. //-----------------------------------------------------------------------------
  726. // Populate the tree
  727. //-----------------------------------------------------------------------------
  728. int CVProfPanel::UpdateVProfTreeEntry( KeyValues *pKeyValues, CVProfNode *pNode, int parent )
  729. {
  730. VPROF( "UpdateVProfTreeEntry" );
  731. CFmtStrN<1024> msg;
  732. double curTimeLessChildren = pNode->GetCurTimeLessChildren();
  733. double avgLessChildren = ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTimeLessChildren() / (double)pNode->GetTotalCalls() : 0;
  734. pKeyValues->SetString( "Text", pNode->GetName() );
  735. pKeyValues->SetString( "group", m_pVProfile->GetBudgetGroupName( pNode->GetBudgetGroupID() ) );
  736. CFmtStrN< 256 > frame;
  737. CFmtStrN< 256 > avgstr;
  738. CFmtStrN< 256 > sum;
  739. CFmtStrN< 256 > l2miss;
  740. frame.sprintf( "[%4d] %7.2f %7.2f", pNode->GetCurCalls(), pNode->GetCurTime(), curTimeLessChildren );
  741. pKeyValues->SetString( "frame", msg );
  742. if( vprof_verbose.GetBool() )
  743. {
  744. double avgCalls = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalCalls() / (double)m_pVProfile->NumFramesSampled() : 0;
  745. double avg = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTime() / (double)m_pVProfile->NumFramesSampled() : 0;
  746. double avgLessChildren = ( m_pVProfile->NumFramesSampled() > 0 ) ? (double)pNode->GetTotalTimeLessChildren() / (double)m_pVProfile->NumFramesSampled() : 0;
  747. avgstr.sprintf( "[%6.2f] %6.3f %6.3f", avgCalls, avg, avgLessChildren );
  748. sum.sprintf( "[%7d] %9.2f %9.2f %8.2fp", pNode->GetTotalCalls(), pNode->GetTotalTime(), pNode->GetTotalTimeLessChildren(), pNode->GetPeakTime() );
  749. }
  750. if ( m_pVProfile->UsePME() )
  751. {
  752. l2miss.sprintf( "%5d", pNode->GetL2CacheMisses() );
  753. }
  754. msg.sprintf( DATA_FMT_STR,
  755. (const char *)frame,
  756. (const char *)avgstr,
  757. (const char *)sum,
  758. (const char *)l2miss );
  759. pKeyValues->SetString( "data", msg );
  760. pKeyValues->SetFloat( "Time", avgLessChildren );
  761. // Add or modify a line in the hierarchy
  762. int id = pNode->GetClientData();
  763. if ( id == -1 )
  764. {
  765. CProfileHierarchyPanel::ColumnPanels_t cp;
  766. AddColumns( cp );
  767. id = m_pHierarchy->AddItem( pKeyValues, parent, cp ) ;
  768. pNode->SetClientData( id );
  769. }
  770. else
  771. {
  772. VPROF( "UpdateVProfTreeEntry:Modify" );
  773. m_pHierarchy->ModifyItem( pKeyValues, id );
  774. }
  775. // Apply color to the item
  776. int r,g,b,a;
  777. m_pVProfile->GetBudgetGroupColor( pNode->GetBudgetGroupID(), r, g, b, a );
  778. m_pHierarchy->SetItemColors( id, Color( r, g, b, a ), Color( 0, 0, 0, 255 ) );
  779. if( pNode->GetBudgetGroupID() == VPROF_BUDGET_GROUP_ID_UNACCOUNTED )
  780. {
  781. if ( curTimeLessChildren > vprof_unaccounted_limit.GetFloat() )
  782. {
  783. m_pHierarchy->SetItemColors( id, Color( 255, 0, 0, 255 ), Color( 0, 0, 0, 255 ) );
  784. }
  785. }
  786. if ( pNode->GetCurTime() > vprof_warningmsec.GetFloat() ||
  787. curTimeLessChildren > vprof_warningmsec.GetFloat() )
  788. {
  789. m_pHierarchy->SetItemColumnColors( id, 2, Color( 255, 0, 0, 255 ), Color( 63, 0, 0, 255 ) );
  790. }
  791. return id;
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Populate the tree
  795. //-----------------------------------------------------------------------------
  796. void CVProfPanel::FillTree( KeyValues *pKeyValues, CVProfNode *pNode, int parent )
  797. {
  798. #ifdef VPROF_ENABLED
  799. bool fIsRoot = ( pNode == m_pVProfile->GetRoot() );
  800. if ( fIsRoot )
  801. {
  802. if( pNode->GetChild() )
  803. {
  804. FillTree( pKeyValues, pNode->GetChild(), parent );
  805. }
  806. return;
  807. }
  808. int id = parent;
  809. if (( m_nCurrentBudgetGroup < 0 ) || ( pNode->GetBudgetGroupID() == m_nCurrentBudgetGroup ))
  810. {
  811. id = UpdateVProfTreeEntry( pKeyValues, pNode, parent );
  812. }
  813. if( pNode->GetSibling() )
  814. {
  815. FillTree( pKeyValues, pNode->GetSibling(), parent );
  816. }
  817. if( pNode->GetChild() )
  818. {
  819. FillTree( pKeyValues, pNode->GetChild(), m_bHierarchicalView ? id : parent );
  820. }
  821. #endif
  822. }
  823. //-----------------------------------------------------------------------------
  824. // Populates the budget group combo box
  825. //-----------------------------------------------------------------------------
  826. void CVProfPanel::PopulateBudgetGroupComboBox()
  827. {
  828. int nBudgetGroupCount = m_pVProfile->GetNumBudgetGroups();
  829. while( m_nLastBudgetGroupCount < nBudgetGroupCount )
  830. {
  831. m_pVProfCategory->AddItem( m_pVProfile->GetBudgetGroupName(m_nLastBudgetGroupCount), NULL );
  832. ++m_nLastBudgetGroupCount;
  833. }
  834. }
  835. //-----------------------------------------------------------------------------
  836. // Populates the tree
  837. //-----------------------------------------------------------------------------
  838. void CVProfPanel::UpdateProfile( float filteredtime )
  839. {
  840. #ifdef VPROF_ENABLED
  841. //ExecuteDeferredOp();
  842. if (IsVisible())
  843. {
  844. PopulateBudgetGroupComboBox();
  845. SetTitle( CFmtStr( "VProf (%s) -- %d frames sampled",
  846. m_pVProfile->IsEnabled() ? "running" : "not running",
  847. m_pVProfile->NumFramesSampled() ), false );
  848. // It's important to cache bEnabled since calling pause can disable.
  849. bool bEnabled = m_pVProfile->IsEnabled();
  850. if( bEnabled )
  851. {
  852. m_pVProfile->Pause();
  853. }
  854. KeyValues * pVal = new KeyValues("");
  855. if ( !m_pHierarchy->GetTree()->GetItemCount() )
  856. {
  857. pVal->SetString( "Text", "Call tree" );
  858. CProfileHierarchyPanel::ColumnPanels_t cp;
  859. AddColumns( cp );
  860. m_RootItem = m_pHierarchy->AddItem( pVal, -1, cp );
  861. m_pHierarchy->SetItemColors( m_RootItem, Color( 255, 255, 255, 255 ), Color( 0, 0, 0, 255 ) );
  862. m_pHierarchy->ExpandItem( m_RootItem, true );
  863. }
  864. m_pHierarchy->ExpandItem( m_RootItem, true );
  865. const char *pScope = vprof_scope.GetString();
  866. CVProfNode *pStartNode = ( pScope[0] == 0 ) ? m_pVProfile->GetRoot() : m_pVProfile->FindNode(m_pVProfile->GetRoot(), pScope );
  867. if ( pStartNode )
  868. {
  869. FillTree( pVal, pStartNode, m_RootItem );
  870. }
  871. pVal->deleteThis();
  872. if( bEnabled )
  873. {
  874. m_pVProfile->Resume();
  875. }
  876. }
  877. if ( m_pVProfile->IsEnabled() )
  878. {
  879. Assert( m_pVProfile->AtRoot() );
  880. if ( GetBudgetPanel()->IsBudgetPanelShown() )
  881. GetBudgetPanel()->SnapshotVProfHistory( filteredtime );
  882. WriteRemoteVProfData(); // send out the vprof data to remote endpoints
  883. }
  884. #endif
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Purpose:
  888. //-----------------------------------------------------------------------------
  889. void CVProfPanel::UserCmd_ShowVProf( void )
  890. {
  891. m_fShowVprofHeld = true;
  892. SetVisible( true );
  893. // This is hacky . . need to at least remember the previous value to set it back.
  894. ConVarRef cl_mouseenable( "cl_mouseenable" );
  895. if ( cl_mouseenable.IsValid() )
  896. {
  897. cl_mouseenable.SetValue( 0 );
  898. }
  899. }
  900. //-----------------------------------------------------------------------------
  901. // Purpose:
  902. //-----------------------------------------------------------------------------
  903. void CVProfPanel::UserCmd_HideVProf( void )
  904. {
  905. m_fShowVprofHeld = false;
  906. SetVisible( false );
  907. // This is hacky . . need to at least remember the previous value to set it back.
  908. ConVarRef cl_mouseenable( "cl_mouseenable" );
  909. if ( cl_mouseenable.IsValid() )
  910. {
  911. cl_mouseenable.SetValue( 1 );
  912. }
  913. }
  914. //-----------------------------------------------------------------------------
  915. void CVProfPanel::Paint()
  916. {
  917. m_pVProfile->Pause();
  918. BaseClass::Paint();
  919. m_pVProfile->Resume();
  920. }
  921. void CVProfPanel::OnCommand( const char *pCommand )
  922. {
  923. if ( !Q_stricmp( pCommand, "StepForward" ) )
  924. {
  925. VProfPlayback_Step();
  926. }
  927. else if ( !Q_stricmp( pCommand, "StepBack" ) )
  928. {
  929. int shouldReset = VProfPlayback_StepBack();
  930. if ( shouldReset == 2 )
  931. {
  932. Reset();
  933. }
  934. }
  935. else if ( !Q_stricmp( pCommand, "GotoButton" ) )
  936. {
  937. int shouldReset = VProfPlayback_SeekToPercent( (float)m_pPlaybackScroll->GetValue() / 1000.0 );
  938. if ( shouldReset == 2 )
  939. {
  940. Reset();
  941. }
  942. }
  943. else if ( !Q_stricmp( pCommand, "redosort" ) )
  944. {
  945. //
  946. Assert( !m_bHierarchicalView );
  947. Reset();
  948. }
  949. }
  950. #endif