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.

2419 lines
68 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Real-Time Hierarchical Profiling
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "pch_tier0.h"
  8. #include "tier0/memalloc.h"
  9. #include "tier0/valve_off.h"
  10. #if defined(_WIN32) && !defined(_X360)
  11. #define WIN_32_LEAN_AND_MEAN
  12. #include <windows.h>
  13. #endif
  14. #include <assert.h>
  15. #ifdef _WIN32
  16. #pragma warning(disable:4073)
  17. #pragma init_seg( lib )
  18. #endif
  19. #pragma warning(push, 1)
  20. #pragma warning(disable:4786)
  21. #pragma warning(disable:4530)
  22. #include <map>
  23. #include <vector>
  24. #include <algorithm>
  25. #pragma warning(pop)
  26. #include "tier0/valve_on.h"
  27. #include "tier0/vprof.h"
  28. #include "tier0/l2cache.h"
  29. #include "tier0/tslist.h"
  30. #include "tier0/icommandline.h"
  31. #include "tier0/dynfunction.h"
  32. #include "strtools.h"
  33. #ifdef _X360
  34. #include "xbox/xbox_console.h"
  35. #elif defined(_PS3)
  36. #include "ps3/ps3_console.h"
  37. #else // NOT _X360:
  38. #include "tier0/memdbgon.h"
  39. #endif
  40. // NOTE: Explicitly and intentionally using STL in here to not generate any
  41. // cyclical dependencies between the low-level debug library and the higher
  42. // level data structures (toml 01-27-03)
  43. using namespace std;
  44. #ifdef VPROF_ENABLED
  45. #if defined(_X360) && !defined(_CERT) // enable PIX CPU trace:
  46. #include "tracerecording.h"
  47. #pragma comment( lib, "tracerecording.lib" )
  48. #pragma comment( lib, "xbdm.lib" )
  49. #endif
  50. //-----------------------------------------------------------------------------
  51. bool g_VProfSignalSpike;
  52. //-----------------------------------------------------------------------------
  53. CVProfile g_VProfCurrentProfile;
  54. int CVProfNode::s_iCurrentUniqueNodeID = 0;
  55. CVProfNode::~CVProfNode()
  56. {
  57. #if !defined( _WIN32 ) && !defined( POSIX )
  58. delete m_pChild;
  59. delete m_pSibling;
  60. #endif
  61. }
  62. CVProfNode *CVProfNode::GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, int budgetFlags )
  63. {
  64. // Try to find this sub node
  65. CVProfNode * child = m_pChild;
  66. while ( child )
  67. {
  68. if ( child->m_pszName == pszName )
  69. {
  70. return child;
  71. }
  72. child = child->m_pSibling;
  73. }
  74. // We didn't find it, so add it
  75. CVProfNode * node = new CVProfNode( pszName, detailLevel, this, pBudgetGroupName, budgetFlags );
  76. node->m_pSibling = m_pChild;
  77. m_pChild = node;
  78. return node;
  79. }
  80. CVProfNode *CVProfNode::GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName )
  81. {
  82. return GetSubNode( pszName, detailLevel, pBudgetGroupName, BUDGETFLAG_OTHER );
  83. }
  84. //-------------------------------------
  85. void CVProfNode::EnterScope()
  86. {
  87. m_nCurFrameCalls++;
  88. if ( m_nRecursions++ == 0 )
  89. {
  90. m_Timer.Start();
  91. #ifndef _X360
  92. if ( g_VProfCurrentProfile.UsePME() )
  93. {
  94. m_L2Cache.Start();
  95. }
  96. #else // 360 code:
  97. if ( g_VProfCurrentProfile.UsePME() || ((m_iBitFlags & kRecordL2) != 0) )
  98. {
  99. m_PMCData.Start();
  100. }
  101. if ( (m_iBitFlags & kCPUTrace) != 0)
  102. {
  103. // this node is to be recorded. Which recording mode are we in?
  104. switch ( g_VProfCurrentProfile.GetCPUTraceMode() )
  105. {
  106. case CVProfile::kFirstHitNode:
  107. case CVProfile::kAllNodesInFrame_Recording:
  108. case CVProfile::kAllNodesInFrame_RecordingMultiFrame:
  109. // we are presently recording.
  110. if ( !XTraceStartRecording( g_VProfCurrentProfile.GetCPUTraceFilename() ) )
  111. {
  112. Msg( "XTraceStartRecording failed, error code %d\n", GetLastError() );
  113. }
  114. default:
  115. // no default.
  116. break;
  117. }
  118. }
  119. #endif
  120. #ifdef VPROF_VTUNE_GROUP
  121. g_VProfCurrentProfile.PushGroup( m_BudgetGroupID );
  122. #endif
  123. }
  124. }
  125. //-------------------------------------
  126. bool CVProfNode::ExitScope()
  127. {
  128. if ( --m_nRecursions == 0 && m_nCurFrameCalls != 0 )
  129. {
  130. m_Timer.End();
  131. m_CurFrameTime += m_Timer.GetDuration();
  132. #ifndef _X360
  133. if ( g_VProfCurrentProfile.UsePME() )
  134. {
  135. m_L2Cache.End();
  136. m_iCurL2CacheMiss += m_L2Cache.GetL2CacheMisses();
  137. }
  138. #else // 360 code:
  139. if ( g_VProfCurrentProfile.UsePME() || ((m_iBitFlags & kRecordL2) != 0) )
  140. {
  141. m_PMCData.End();
  142. m_iCurL2CacheMiss += m_PMCData.GetL2CacheMisses();
  143. m_iCurLoadHitStores += m_PMCData.GetLHS();
  144. }
  145. if ( (m_iBitFlags & kCPUTrace) != 0 )
  146. {
  147. // this node is enabled to be recorded. What mode are we in?
  148. switch ( g_VProfCurrentProfile.GetCPUTraceMode() )
  149. {
  150. case CVProfile::kFirstHitNode:
  151. {
  152. // one-off recording. stop now.
  153. if ( XTraceStopRecording() )
  154. {
  155. Msg( "CPU trace finished.\n" );
  156. if ( g_VProfCurrentProfile.TraceCompleteEvent() )
  157. {
  158. // signal VXConsole that trace is completed
  159. XBX_rTraceComplete();
  160. }
  161. }
  162. // don't trace again next frame, overwriting the file.
  163. g_VProfCurrentProfile.SetCPUTraceEnabled( CVProfile::kDisabled );
  164. break;
  165. }
  166. case CVProfile::kAllNodesInFrame_Recording:
  167. case CVProfile::kAllNodesInFrame_RecordingMultiFrame:
  168. {
  169. // one-off recording. stop now.
  170. if ( XTraceStopRecording() )
  171. {
  172. if ( g_VProfCurrentProfile.GetCPUTraceMode() == CVProfile::kAllNodesInFrame_RecordingMultiFrame )
  173. {
  174. Msg( "%.3f msec in %s\n", m_CurFrameTime.GetMillisecondsF(), g_VProfCurrentProfile.GetCPUTraceFilename() );
  175. }
  176. else
  177. {
  178. Msg( "CPU trace finished.\n" );
  179. }
  180. }
  181. // Spew time info for file to allow figuring it out later
  182. g_VProfCurrentProfile.LatchMultiFrame( m_CurFrameTime.GetLongCycles() );
  183. #if 0 // This doesn't want to work on the xbox360-- MoveFile not available or file still being put down to disk?
  184. char suffix[ 32 ];
  185. _snprintf( suffix, sizeof( suffix ), "_%.3f_msecs", flMsecs );
  186. char fn[ 512 ];
  187. strncpy( fn, g_VProfCurrentProfile.GetCPUTraceFilename(), sizeof( fn ) );
  188. char *p = strrchr( fn, '.' );
  189. if ( *p )
  190. {
  191. *p = 0;
  192. }
  193. strncat( fn, suffix, sizeof( fn ) );
  194. strncat( fn, ".pix2", sizeof( fn ) );
  195. BOOL bSuccess = MoveFile( g_VProfCurrentProfile.GetCPUTraceFilename(), fn );
  196. if ( !bSuccess )
  197. {
  198. DWORD eCode = GetLastError();
  199. Msg( "Error %d\n", eCode );
  200. }
  201. #endif
  202. // we're still recording until the frame is done.
  203. // but, increment the index.
  204. g_VProfCurrentProfile.IncrementMultiTraceIndex();
  205. break;
  206. }
  207. }
  208. // g_VProfCurrentProfile.IsCPUTraceEnabled() &&
  209. }
  210. #endif
  211. #ifdef VPROF_VTUNE_GROUP
  212. g_VProfCurrentProfile.PopGroup();
  213. #endif
  214. }
  215. return ( m_nRecursions == 0 );
  216. }
  217. //-------------------------------------
  218. void CVProfNode::Pause()
  219. {
  220. if ( m_nRecursions > 0 )
  221. {
  222. m_Timer.End();
  223. m_CurFrameTime += m_Timer.GetDuration();
  224. #ifndef _X360
  225. if ( g_VProfCurrentProfile.UsePME() )
  226. {
  227. m_L2Cache.End();
  228. m_iCurL2CacheMiss += m_L2Cache.GetL2CacheMisses();
  229. }
  230. #else // 360 code:
  231. if ( g_VProfCurrentProfile.UsePME() || ((m_iBitFlags & kRecordL2) != 0) )
  232. {
  233. m_PMCData.End();
  234. m_iCurL2CacheMiss += m_PMCData.GetL2CacheMisses();
  235. m_iCurLoadHitStores += m_PMCData.GetLHS();
  236. }
  237. #endif
  238. }
  239. if ( m_pChild )
  240. {
  241. m_pChild->Pause();
  242. }
  243. if ( m_pSibling )
  244. {
  245. m_pSibling->Pause();
  246. }
  247. }
  248. //-------------------------------------
  249. void CVProfNode::Resume()
  250. {
  251. if ( m_nRecursions > 0 )
  252. {
  253. m_Timer.Start();
  254. #ifndef _X360
  255. if ( g_VProfCurrentProfile.UsePME() )
  256. {
  257. m_L2Cache.Start();
  258. }
  259. #else
  260. if ( g_VProfCurrentProfile.UsePME() || ((m_iBitFlags & kRecordL2) != 0) )
  261. {
  262. m_PMCData.Start();
  263. }
  264. #endif
  265. }
  266. if ( m_pChild )
  267. {
  268. m_pChild->Resume();
  269. }
  270. if ( m_pSibling )
  271. {
  272. m_pSibling->Resume();
  273. }
  274. }
  275. //-------------------------------------
  276. void CVProfNode::Reset()
  277. {
  278. m_nPrevFrameCalls = 0;
  279. m_PrevFrameTime.Init();
  280. m_nCurFrameCalls = 0;
  281. m_CurFrameTime.Init();
  282. m_nTotalCalls = 0;
  283. m_TotalTime.Init();
  284. m_PeakTime.Init();
  285. m_iPrevL2CacheMiss = 0;
  286. m_iCurL2CacheMiss = 0;
  287. m_iTotalL2CacheMiss = 0;
  288. #ifdef _X360
  289. m_iPrevLoadHitStores = 0;
  290. m_iCurLoadHitStores = 0;
  291. m_iTotalLoadHitStores = 0;
  292. #endif
  293. if ( m_pChild )
  294. {
  295. m_pChild->Reset();
  296. }
  297. if ( m_pSibling )
  298. {
  299. m_pSibling->Reset();
  300. }
  301. }
  302. //-------------------------------------
  303. void CVProfNode::MarkFrame()
  304. {
  305. m_nPrevFrameCalls = m_nCurFrameCalls;
  306. m_PrevFrameTime = m_CurFrameTime;
  307. m_iPrevL2CacheMiss = m_iCurL2CacheMiss;
  308. #ifdef _X360
  309. m_iPrevLoadHitStores = m_iCurLoadHitStores;
  310. #endif
  311. m_nTotalCalls += m_nCurFrameCalls;
  312. m_TotalTime += m_CurFrameTime;
  313. if ( m_PeakTime.IsLessThan( m_CurFrameTime ) )
  314. {
  315. m_PeakTime = m_CurFrameTime;
  316. }
  317. m_CurFrameTime.Init();
  318. m_nCurFrameCalls = 0;
  319. m_iTotalL2CacheMiss += m_iCurL2CacheMiss;
  320. m_iCurL2CacheMiss = 0;
  321. #ifdef _X360
  322. m_iTotalLoadHitStores += m_iCurLoadHitStores;
  323. m_iCurLoadHitStores = 0;
  324. #endif
  325. if ( m_pChild )
  326. {
  327. m_pChild->MarkFrame();
  328. }
  329. if ( m_pSibling )
  330. {
  331. m_pSibling->MarkFrame();
  332. }
  333. }
  334. //-------------------------------------
  335. void CVProfNode::ResetPeak()
  336. {
  337. m_PeakTime.Init();
  338. if ( m_pChild )
  339. {
  340. m_pChild->ResetPeak();
  341. }
  342. if ( m_pSibling )
  343. {
  344. m_pSibling->ResetPeak();
  345. }
  346. }
  347. void CVProfNode::SetCurFrameTime( unsigned long milliseconds )
  348. {
  349. m_CurFrameTime.Init( (float)milliseconds );
  350. }
  351. #ifdef DBGFLAG_VALIDATE
  352. //-----------------------------------------------------------------------------
  353. // Purpose: Ensure that all of our internal structures are consistent, and
  354. // account for all memory that we've allocated.
  355. // Input: validator - Our global validator object
  356. // pchName - Our name (typically a member var in our container)
  357. //-----------------------------------------------------------------------------
  358. void CVProfNode::Validate( CValidator &validator, tchar *pchName )
  359. {
  360. validator.Push( _T("CVProfNode"), this, pchName );
  361. m_L2Cache.Validate( validator, _T("m_L2Cache") );
  362. if ( m_pSibling )
  363. m_pSibling->Validate( validator, _T("m_pSibling") );
  364. if ( m_pChild )
  365. m_pChild->Validate( validator, _T("m_pChild") );
  366. validator.Pop( );
  367. }
  368. #endif // DBGFLAG_VALIDATE
  369. //-----------------------------------------------------------------------------
  370. struct TimeSums_t
  371. {
  372. const tchar *pszProfileScope;
  373. unsigned calls;
  374. double time;
  375. double timeLessChildren;
  376. double peak;
  377. };
  378. static bool TimeCompare( const TimeSums_t &lhs, const TimeSums_t &rhs )
  379. {
  380. return ( lhs.time > rhs.time );
  381. }
  382. static bool TimeLessChildrenCompare( const TimeSums_t &lhs, const TimeSums_t &rhs )
  383. {
  384. return ( lhs.timeLessChildren > rhs.timeLessChildren );
  385. }
  386. static bool PeakCompare( const TimeSums_t &lhs, const TimeSums_t &rhs )
  387. {
  388. return ( lhs.peak > rhs.peak );
  389. }
  390. static bool AverageTimeCompare( const TimeSums_t &lhs, const TimeSums_t &rhs )
  391. {
  392. double avgLhs = ( lhs.calls ) ? lhs.time / (double)lhs.calls : 0.0;
  393. double avgRhs = ( rhs.calls ) ? rhs.time / (double)rhs.calls : 0.0;
  394. return ( avgLhs > avgRhs );
  395. }
  396. static bool AverageTimeLessChildrenCompare( const TimeSums_t &lhs, const TimeSums_t &rhs )
  397. {
  398. double avgLhs = ( lhs.calls ) ? lhs.timeLessChildren / (double)lhs.calls : 0.0;
  399. double avgRhs = ( rhs.calls ) ? rhs.timeLessChildren / (double)rhs.calls : 0.0;
  400. return ( avgLhs > avgRhs );
  401. }
  402. static bool PeakOverAverageCompare( const TimeSums_t &lhs, const TimeSums_t &rhs )
  403. {
  404. double avgLhs = ( lhs.calls ) ? lhs.time / (double)lhs.calls : 0.0;
  405. double avgRhs = ( rhs.calls ) ? rhs.time / (double)rhs.calls : 0.0;
  406. double lhsPoA = ( avgLhs != 0 ) ? lhs.peak / avgLhs : 0.0;
  407. double rhsPoA = ( avgRhs != 0 ) ? rhs.peak / avgRhs : 0.0;
  408. return ( lhsPoA > rhsPoA );
  409. }
  410. map<CVProfNode *, double> g_TimesLessChildren;
  411. int g_TotalFrames;
  412. map<const tchar *, uintp> g_TimeSumsMap;
  413. vector<TimeSums_t> g_TimeSums;
  414. CVProfNode * g_pStartNode;
  415. const tchar * g_pszSumNode;
  416. //-------------------------------------
  417. void CVProfile::SumTimes( CVProfNode *pNode, int budgetGroupID )
  418. {
  419. if ( !pNode )
  420. return; // this generally only happens on a failed FindNode()
  421. bool bSetStartNode;
  422. if ( !g_pStartNode && _tcscmp( pNode->GetName(), g_pszSumNode ) == 0 )
  423. {
  424. g_pStartNode = pNode;
  425. bSetStartNode = true;
  426. }
  427. else
  428. bSetStartNode = false;
  429. if ( GetRoot() != pNode )
  430. {
  431. if ( g_pStartNode && pNode->GetTotalCalls() > 0 && ( budgetGroupID == -1 || pNode->GetBudgetGroupID() == budgetGroupID ) )
  432. {
  433. double timeLessChildren = pNode->GetTotalTimeLessChildren();
  434. g_TimesLessChildren.insert( make_pair( pNode, timeLessChildren ) );
  435. map<const tchar *, uintp>::iterator iter;
  436. iter = g_TimeSumsMap.find( pNode->GetName() ); // intenionally using address of string rather than string compare (toml 01-27-03)
  437. if ( iter == g_TimeSumsMap.end() )
  438. {
  439. TimeSums_t timeSums = { pNode->GetName(), static_cast<unsigned int>(pNode->GetTotalCalls()), pNode->GetTotalTime(), timeLessChildren, pNode->GetPeakTime() };
  440. g_TimeSumsMap.insert( make_pair( pNode->GetName(), g_TimeSums.size() ) );
  441. g_TimeSums.push_back( timeSums );
  442. }
  443. else
  444. {
  445. TimeSums_t &timeSums = g_TimeSums[iter->second];
  446. timeSums.calls += pNode->GetTotalCalls();
  447. timeSums.time += pNode->GetTotalTime();
  448. timeSums.timeLessChildren += timeLessChildren;
  449. if ( pNode->GetPeakTime() > timeSums.peak )
  450. timeSums.peak = pNode->GetPeakTime();
  451. }
  452. }
  453. if( ( !g_pStartNode || pNode != g_pStartNode ) && pNode->GetSibling() )
  454. {
  455. SumTimes( pNode->GetSibling(), budgetGroupID );
  456. }
  457. }
  458. if( pNode->GetChild() )
  459. {
  460. SumTimes( pNode->GetChild(), budgetGroupID );
  461. }
  462. if ( bSetStartNode )
  463. g_pStartNode = NULL;
  464. }
  465. //-------------------------------------
  466. CVProfNode *CVProfile::FindNode( CVProfNode *pStartNode, const tchar *pszNode )
  467. {
  468. if ( _tcscmp( pStartNode->GetName(), pszNode ) != 0 )
  469. {
  470. CVProfNode *pFoundNode = NULL;
  471. if ( pStartNode->GetSibling() )
  472. {
  473. pFoundNode = FindNode( pStartNode->GetSibling(), pszNode );
  474. }
  475. if ( !pFoundNode && pStartNode->GetChild() )
  476. {
  477. pFoundNode = FindNode( pStartNode->GetChild(), pszNode );
  478. }
  479. return pFoundNode;
  480. }
  481. return pStartNode;
  482. }
  483. //-------------------------------------
  484. #ifdef _X360
  485. void CVProfile::PMCDisableAllNodes(CVProfNode *pStartNode)
  486. {
  487. if (pStartNode == NULL)
  488. {
  489. pStartNode = GetRoot();
  490. }
  491. pStartNode->EnableL2andLHS(false);
  492. if ( pStartNode->GetSibling() )
  493. {
  494. PMCDisableAllNodes(pStartNode->GetSibling());
  495. }
  496. if ( pStartNode->GetChild() )
  497. {
  498. PMCDisableAllNodes(pStartNode->GetChild());
  499. }
  500. }
  501. // recursively set l2/lhs recording state for a node and all children AND SIBLINGS
  502. static void PMCRecursiveL2Set(CVProfNode *pNode, bool enableState)
  503. {
  504. if ( pNode )
  505. {
  506. pNode->EnableL2andLHS(enableState);
  507. if ( pNode->GetSibling() )
  508. {
  509. PMCRecursiveL2Set( pNode->GetSibling(), enableState );
  510. }
  511. if ( pNode->GetChild() )
  512. {
  513. PMCRecursiveL2Set( pNode->GetChild(), enableState );
  514. }
  515. }
  516. }
  517. bool CVProfile::PMCEnableL2Upon(const tchar *pszNodeName, bool bRecursive)
  518. {
  519. // PMCDisableAllNodes();
  520. CVProfNode *pNode = FindNode( GetRoot(), pszNodeName );
  521. if (pNode)
  522. {
  523. pNode->EnableL2andLHS(true);
  524. if (bRecursive)
  525. {
  526. PMCRecursiveL2Set(pNode->GetChild(), true);
  527. }
  528. return true;
  529. }
  530. else
  531. {
  532. return false;
  533. }
  534. }
  535. bool CVProfile::PMCDisableL2Upon(const tchar *pszNodeName, bool bRecursive)
  536. {
  537. // PMCDisableAllNodes();
  538. CVProfNode *pNode = FindNode( GetRoot(), pszNodeName );
  539. if ( pNode )
  540. {
  541. pNode->EnableL2andLHS( false );
  542. if ( bRecursive )
  543. {
  544. PMCRecursiveL2Set( pNode->GetChild(), false );
  545. }
  546. return true;
  547. }
  548. else
  549. {
  550. return false;
  551. }
  552. }
  553. static void DumpEnabledPMCNodesInner(CVProfNode* pNode)
  554. {
  555. if (!pNode)
  556. return;
  557. if (pNode->IsL2andLHSEnabled())
  558. {
  559. Msg( _T("\t%s\n"), pNode->GetName() );
  560. }
  561. // depth first printing clearer
  562. if ( pNode->GetChild() )
  563. {
  564. DumpEnabledPMCNodesInner(pNode->GetChild());
  565. }
  566. if ( pNode->GetSibling() )
  567. {
  568. DumpEnabledPMCNodesInner(pNode->GetChild());
  569. }
  570. }
  571. void CVProfile::DumpEnabledPMCNodes( void )
  572. {
  573. Msg( _T("Nodes enabled for PMC counters:\n") );
  574. CVProfNode *pNode = GetRoot();
  575. DumpEnabledPMCNodesInner( pNode );
  576. Msg( _T("(end)\n") );
  577. }
  578. CVProfNode *CVProfile::CPUTraceGetEnabledNode(CVProfNode *pStartNode)
  579. {
  580. if (!pStartNode)
  581. {
  582. pStartNode = GetRoot();
  583. }
  584. if ( (pStartNode->m_iBitFlags & CVProfNode::kCPUTrace) != 0 )
  585. {
  586. return pStartNode;
  587. }
  588. if (pStartNode->GetSibling())
  589. {
  590. CVProfNode *retval = CPUTraceGetEnabledNode(pStartNode->GetSibling());
  591. if (retval)
  592. return retval;
  593. }
  594. if (pStartNode->GetChild())
  595. {
  596. CVProfNode *retval = CPUTraceGetEnabledNode(pStartNode->GetChild());
  597. if (retval)
  598. return retval;
  599. }
  600. return NULL;
  601. }
  602. const char *CVProfile::SetCPUTraceFilename( const char *filename )
  603. {
  604. strncpy( m_CPUTraceFilename, filename, sizeof( m_CPUTraceFilename ) );
  605. return GetCPUTraceFilename();
  606. }
  607. /// Returns a pointer to an internal static, so you don't need to
  608. /// make temporary char buffers for this to write into. What of it?
  609. /// You're not hanging on to that pointer. That would be foolish.
  610. const char *CVProfile::GetCPUTraceFilename()
  611. {
  612. static char retBuf[256];
  613. switch ( m_iCPUTraceEnabled )
  614. {
  615. case kAllNodesInFrame_WaitingForMark:
  616. case kAllNodesInFrame_Recording:
  617. _snprintf( retBuf, sizeof( retBuf ), "e:\\%.128s%.4d.pix2", m_CPUTraceFilename, m_iSuccessiveTraceIndex );
  618. break;
  619. case kAllNodesInFrame_WaitingForMarkMultiFrame:
  620. case kAllNodesInFrame_RecordingMultiFrame:
  621. _snprintf( retBuf, sizeof( retBuf ), "e:\\%.128s_%.4d_%.4d.pix2", m_CPUTraceFilename, m_nFrameCount, m_iSuccessiveTraceIndex );
  622. break;
  623. default:
  624. _snprintf( retBuf, sizeof( retBuf ), "e:\\%.128s.pix2", m_CPUTraceFilename );
  625. }
  626. return retBuf;
  627. }
  628. bool CVProfile::TraceCompleteEvent( void )
  629. {
  630. return m_bTraceCompleteEvent;
  631. }
  632. CVProfNode *CVProfile::CPUTraceEnableForNode(const tchar *pszNodeName)
  633. {
  634. // disable whatever may be enabled already (we can only trace one node at a time)
  635. CPUTraceDisableAllNodes();
  636. CVProfNode *which = FindNode(GetRoot(), pszNodeName);
  637. if (which)
  638. {
  639. which->m_iBitFlags |= CVProfNode::kCPUTrace;
  640. return which;
  641. }
  642. else
  643. return NULL;
  644. }
  645. void CVProfile::CPUTraceDisableAllNodes(CVProfNode *pStartNode)
  646. {
  647. if (!pStartNode)
  648. {
  649. pStartNode = GetRoot();
  650. }
  651. pStartNode->m_iBitFlags &= ~CVProfNode::kCPUTrace;
  652. if (pStartNode->GetSibling())
  653. {
  654. CPUTraceDisableAllNodes(pStartNode->GetSibling());
  655. }
  656. if (pStartNode->GetChild())
  657. {
  658. CPUTraceDisableAllNodes(pStartNode->GetChild());
  659. }
  660. }
  661. #endif
  662. //-------------------------------------
  663. void CVProfile::SumTimes( const tchar *pszStartNode, int budgetGroupID )
  664. {
  665. if ( GetRoot()->GetChild() )
  666. {
  667. if ( pszStartNode == NULL )
  668. g_pStartNode = GetRoot();
  669. else
  670. g_pStartNode = NULL;
  671. g_pszSumNode = pszStartNode;
  672. SumTimes( GetRoot(), budgetGroupID );
  673. g_pStartNode = NULL;
  674. }
  675. }
  676. //-------------------------------------
  677. void CVProfile::DumpNodes( CVProfNode *pNode, int indent, bool bAverageAndCountOnly )
  678. {
  679. if ( !pNode )
  680. return; // this generally only happens on a failed FindNode()
  681. bool fIsRoot = ( pNode == GetRoot() );
  682. if ( fIsRoot || pNode == g_pStartNode )
  683. {
  684. if( bAverageAndCountOnly )
  685. {
  686. Msg( _T(" Avg Time/Frame (ms)\n") );
  687. Msg( _T("[ func+child func ] Count\n") );
  688. Msg( _T(" ---------- --------- --------\n") );
  689. }
  690. else
  691. {
  692. Msg( _T(" Sum (ms) Avg Time/Frame (ms) Avg Time/Call (ms)\n") );
  693. Msg( _T("[ func+child func ] [ func+child func ] [ func+child func ] Count Peak\n") );
  694. Msg( _T(" ---------- --------- ---------- ------ ---------- ------ -------- ------\n") );
  695. }
  696. }
  697. if ( !fIsRoot )
  698. {
  699. map<CVProfNode *, double>::iterator iterTimeLessChildren = g_TimesLessChildren.find( pNode );
  700. double dNodeTime = 0;
  701. if(iterTimeLessChildren != g_TimesLessChildren.end())
  702. dNodeTime = iterTimeLessChildren->second;
  703. if( bAverageAndCountOnly )
  704. {
  705. Msg( _T(" %10.3f %9.2f %8d"),
  706. ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTime() / (double)NumFramesSampled() : 0,
  707. ( pNode->GetTotalCalls() > 0 ) ? dNodeTime / (double)NumFramesSampled() : 0,
  708. pNode->GetTotalCalls() );
  709. }
  710. else
  711. {
  712. Msg( _T(" %10.3f %9.2f %10.3f %6.2f %10.3f %6.2f %8d %6.2f"),
  713. pNode->GetTotalTime(), dNodeTime,
  714. ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTime() / (double)NumFramesSampled() : 0,
  715. ( pNode->GetTotalCalls() > 0 ) ? dNodeTime / (double)NumFramesSampled() : 0,
  716. ( pNode->GetTotalCalls() > 0 ) ? pNode->GetTotalTime() / (double)pNode->GetTotalCalls() : 0,
  717. ( pNode->GetTotalCalls() > 0 ) ? dNodeTime / (double)pNode->GetTotalCalls() : 0,
  718. pNode->GetTotalCalls(), pNode->GetPeakTime() );
  719. }
  720. Msg( _T(" ") );
  721. for ( int i = 1; i < indent; i++ )
  722. {
  723. Msg( _T("| ") );
  724. }
  725. Msg( _T("%s\n"), pNode->GetName() );
  726. }
  727. if( pNode->GetChild() )
  728. {
  729. DumpNodes( pNode->GetChild(), indent + 1, bAverageAndCountOnly );
  730. }
  731. if( !( fIsRoot || pNode == g_pStartNode ) && pNode->GetSibling() )
  732. {
  733. DumpNodes( pNode->GetSibling(), indent, bAverageAndCountOnly );
  734. }
  735. }
  736. //-------------------------------------
  737. #if defined( VPROF_VXCONSOLE_EXISTS )
  738. static void CalcBudgetGroupTimes_Recursive( CVProfNode *pNode, unsigned int *groupTimes, int numGroups, float flScale )
  739. {
  740. int groupID;
  741. CVProfNode *nodePtr;
  742. groupID = pNode->GetBudgetGroupID();
  743. if ( groupID >= numGroups )
  744. {
  745. return;
  746. }
  747. groupTimes[groupID] += flScale*pNode->GetPrevTimeLessChildren();
  748. nodePtr = pNode->GetSibling();
  749. if ( nodePtr )
  750. {
  751. CalcBudgetGroupTimes_Recursive( nodePtr, groupTimes, numGroups, flScale );
  752. }
  753. nodePtr = pNode->GetChild();
  754. if ( nodePtr )
  755. {
  756. CalcBudgetGroupTimes_Recursive( nodePtr, groupTimes, numGroups, flScale );
  757. }
  758. }
  759. static void CalcBudgetGroupL2CacheMisses_Recursive( CVProfNode *pNode, unsigned int *groupTimes, int numGroups, float flScale )
  760. {
  761. int groupID;
  762. CVProfNode *nodePtr;
  763. groupID = pNode->GetBudgetGroupID();
  764. if ( groupID >= numGroups )
  765. {
  766. return;
  767. }
  768. groupTimes[groupID] += flScale*pNode->GetPrevL2CacheMissLessChildren();
  769. nodePtr = pNode->GetSibling();
  770. if ( nodePtr )
  771. {
  772. CalcBudgetGroupL2CacheMisses_Recursive( nodePtr, groupTimes, numGroups, flScale );
  773. }
  774. nodePtr = pNode->GetChild();
  775. if ( nodePtr )
  776. {
  777. CalcBudgetGroupL2CacheMisses_Recursive( nodePtr, groupTimes, numGroups, flScale );
  778. }
  779. }
  780. static void CalcBudgetGroupLHS_Recursive( CVProfNode *pNode, unsigned int *groupTimes, int numGroups, float flScale )
  781. {
  782. int groupID;
  783. CVProfNode *nodePtr;
  784. groupID = pNode->GetBudgetGroupID();
  785. if ( groupID >= numGroups )
  786. {
  787. return;
  788. }
  789. groupTimes[groupID] += flScale*pNode->GetPrevLoadHitStoreLessChildren();
  790. nodePtr = pNode->GetSibling();
  791. if ( nodePtr )
  792. {
  793. CalcBudgetGroupLHS_Recursive( nodePtr, groupTimes, numGroups, flScale );
  794. }
  795. nodePtr = pNode->GetChild();
  796. if ( nodePtr )
  797. {
  798. CalcBudgetGroupLHS_Recursive( nodePtr, groupTimes, numGroups, flScale );
  799. }
  800. }
  801. void CVProfile::VXConsoleReportMode( VXConsoleReportMode_t mode )
  802. {
  803. m_ReportMode = mode;
  804. }
  805. void CVProfile::VXConsoleReportScale( VXConsoleReportMode_t mode, float flScale )
  806. {
  807. m_pReportScale[mode] = flScale;
  808. }
  809. //-----------------------------------------------------------------------------
  810. // Send the all the counter attributes once to VXConsole at profiling start
  811. //-----------------------------------------------------------------------------
  812. void CVProfile::VXProfileStart()
  813. {
  814. const char *names[XBX_MAX_PROFILE_COUNTERS];
  815. COLORREF colors[XBX_MAX_PROFILE_COUNTERS];
  816. int numGroups;
  817. int counterGroup;
  818. const char *pGroupName;
  819. int i;
  820. int r,g,b,a;
  821. // vprof system must be running
  822. if ( m_enabled <= 0 || !m_UpdateMode )
  823. {
  824. return;
  825. }
  826. if ( m_UpdateMode & VPROF_UPDATE_BUDGET )
  827. {
  828. // update budget profiling
  829. numGroups = g_VProfCurrentProfile.GetNumBudgetGroups();
  830. if ( numGroups > XBX_MAX_PROFILE_COUNTERS )
  831. {
  832. numGroups = XBX_MAX_PROFILE_COUNTERS;
  833. }
  834. for ( i=0; i<numGroups; i++ )
  835. {
  836. names[i] = g_VProfCurrentProfile.GetBudgetGroupName( i );
  837. g_VProfCurrentProfile.GetBudgetGroupColor( i, r, g, b, a );
  838. colors[i] = XMAKECOLOR( r, g, b );
  839. }
  840. // send all the profile attributes
  841. XBX_rSetProfileAttributes( "cpu", numGroups, names, colors );
  842. }
  843. if ( m_UpdateMode & (VPROF_UPDATE_TEXTURE_GLOBAL|VPROF_UPDATE_TEXTURE_PERFRAME) )
  844. {
  845. // update texture profiling
  846. numGroups = 0;
  847. counterGroup = (m_UpdateMode & VPROF_UPDATE_TEXTURE_GLOBAL) ? COUNTER_GROUP_TEXTURE_GLOBAL : COUNTER_GROUP_TEXTURE_PER_FRAME;
  848. for ( i=0; i<g_VProfCurrentProfile.GetNumCounters(); i++ )
  849. {
  850. if ( g_VProfCurrentProfile.GetCounterGroup( i ) == counterGroup )
  851. {
  852. // strip undesired prefix
  853. pGroupName = g_VProfCurrentProfile.GetCounterName( i );
  854. if ( !stricmp( pGroupName, "texgroup_frame_" ) )
  855. {
  856. pGroupName += 15;
  857. }
  858. else if ( !stricmp( pGroupName, "texgroup_global_" ) )
  859. {
  860. pGroupName += 16;
  861. }
  862. names[numGroups] = pGroupName;
  863. g_VProfCurrentProfile.GetBudgetGroupColor( numGroups, r, g, b, a );
  864. colors[numGroups] = XMAKECOLOR( r, g, b );
  865. numGroups++;
  866. if ( numGroups == XBX_MAX_PROFILE_COUNTERS )
  867. {
  868. break;
  869. }
  870. }
  871. }
  872. // send all the profile attributes
  873. XBX_rSetProfileAttributes( "texture", numGroups, names, colors );
  874. }
  875. }
  876. //-----------------------------------------------------------------------------
  877. // Send the counters to VXConsole
  878. //-----------------------------------------------------------------------------
  879. void CVProfile::VXProfileUpdate()
  880. {
  881. int i;
  882. int counterGroup;
  883. int numGroups;
  884. unsigned int groupData[XBX_MAX_PROFILE_COUNTERS];
  885. // vprof system must be running
  886. if ( m_enabled <= 0 || !m_UpdateMode )
  887. {
  888. return;
  889. }
  890. if ( m_UpdateMode & VPROF_UPDATE_BUDGET )
  891. {
  892. // send the cpu counters
  893. numGroups = g_VProfCurrentProfile.GetNumBudgetGroups();
  894. if ( numGroups > XBX_MAX_PROFILE_COUNTERS )
  895. {
  896. numGroups = XBX_MAX_PROFILE_COUNTERS;
  897. }
  898. memset( groupData, 0, numGroups * sizeof( unsigned int ) );
  899. CVProfNode *pNode = g_VProfCurrentProfile.GetRoot();
  900. if ( pNode && pNode->GetChild() )
  901. {
  902. switch ( m_ReportMode )
  903. {
  904. default:
  905. case VXCONSOLE_REPORT_TIME:
  906. CalcBudgetGroupTimes_Recursive( pNode->GetChild(), groupData, numGroups, m_pReportScale[VXCONSOLE_REPORT_TIME] );
  907. break;
  908. case VXCONSOLE_REPORT_L2CACHE_MISSES:
  909. CalcBudgetGroupL2CacheMisses_Recursive( pNode->GetChild(), groupData, numGroups, m_pReportScale[VXCONSOLE_REPORT_L2CACHE_MISSES] );
  910. break;
  911. case VXCONSOLE_REPORT_LOAD_HIT_STORE:
  912. CalcBudgetGroupLHS_Recursive( pNode->GetChild(), groupData, numGroups, m_pReportScale[VXCONSOLE_REPORT_LOAD_HIT_STORE] );
  913. break;
  914. }
  915. }
  916. XBX_rSetProfileData( "cpu", numGroups, groupData );
  917. }
  918. if ( m_UpdateMode & ( VPROF_UPDATE_TEXTURE_GLOBAL|VPROF_UPDATE_TEXTURE_PERFRAME ) )
  919. {
  920. // send the texture counters
  921. numGroups = 0;
  922. counterGroup = ( m_UpdateMode & VPROF_UPDATE_TEXTURE_GLOBAL ) ? COUNTER_GROUP_TEXTURE_GLOBAL : COUNTER_GROUP_TEXTURE_PER_FRAME;
  923. for ( i = 0; i < g_VProfCurrentProfile.GetNumCounters(); i++ )
  924. {
  925. if ( g_VProfCurrentProfile.GetCounterGroup( i ) == counterGroup )
  926. {
  927. // get the size in bytes
  928. groupData[numGroups++] = g_VProfCurrentProfile.GetCounterValue( i );
  929. if ( numGroups == XBX_MAX_PROFILE_COUNTERS )
  930. {
  931. break;
  932. }
  933. }
  934. }
  935. XBX_rSetProfileData( "texture", numGroups, groupData );
  936. }
  937. }
  938. void CVProfile::VXEnableUpdateMode( int event, bool bEnable )
  939. {
  940. // enable or disable the updating of specified events
  941. if ( bEnable )
  942. {
  943. m_UpdateMode |= event;
  944. }
  945. else
  946. {
  947. m_UpdateMode &= ~event;
  948. }
  949. // force a resend of possibly affected attributes
  950. VXProfileStart();
  951. }
  952. #define MAX_VPROF_NODES_IN_LIST 4096
  953. static void VXBuildNodeList_r( CVProfNode *pNode, xVProfNodeItem_t *pNodeList, int *pNumNodes )
  954. {
  955. if ( !pNode )
  956. {
  957. return;
  958. }
  959. if ( *pNumNodes >= MAX_VPROF_NODES_IN_LIST )
  960. {
  961. // list full
  962. return;
  963. }
  964. // add to list
  965. pNodeList[*pNumNodes].pName = (const char *)pNode->GetName();
  966. pNodeList[*pNumNodes].pBudgetGroupName = g_VProfCurrentProfile.GetBudgetGroupName( pNode->GetBudgetGroupID() );
  967. int r, g, b, a;
  968. g_VProfCurrentProfile.GetBudgetGroupColor( pNode->GetBudgetGroupID(), r, g, b, a );
  969. pNodeList[*pNumNodes].budgetGroupColor = XMAKECOLOR( r, g, b );
  970. pNodeList[*pNumNodes].totalCalls = pNode->GetTotalCalls();
  971. pNodeList[*pNumNodes].inclusiveTime = pNode->GetTotalTime();
  972. pNodeList[*pNumNodes].exclusiveTime = pNode->GetTotalTimeLessChildren();
  973. (*pNumNodes)++;
  974. CVProfNode *nodePtr = pNode->GetSibling();
  975. if ( nodePtr )
  976. {
  977. VXBuildNodeList_r( nodePtr, pNodeList, pNumNodes );
  978. }
  979. nodePtr = pNode->GetChild();
  980. if ( nodePtr )
  981. {
  982. VXBuildNodeList_r( nodePtr, pNodeList, pNumNodes );
  983. }
  984. }
  985. void CVProfile::VXSendNodes( void )
  986. {
  987. Pause();
  988. xVProfNodeItem_t *pNodeList = (xVProfNodeItem_t *)stackalloc( MAX_VPROF_NODES_IN_LIST * sizeof(xVProfNodeItem_t) );
  989. int numNodes = 0;
  990. VXBuildNodeList_r( GetRoot(), pNodeList, &numNodes );
  991. // send to vxconsole
  992. XBX_rVProfNodeList( numNodes, pNodeList );
  993. Resume();
  994. }
  995. #endif
  996. //-------------------------------------
  997. static void DumpSorted( const tchar *pszHeading, double totalTime, bool (*pfnSort)( const TimeSums_t &, const TimeSums_t & ), int maxLen = 999999 )
  998. {
  999. unsigned i;
  1000. vector<TimeSums_t> sortedSums;
  1001. sortedSums = g_TimeSums;
  1002. sort( sortedSums.begin(), sortedSums.end(), pfnSort );
  1003. Msg( _T("%s\n"), pszHeading);
  1004. Msg( _T(" Scope Calls Calls/Frame Time+Child Pct Time Pct Avg/Frame Avg/Call Avg-NoChild Peak\n"));
  1005. Msg( _T(" ---------------------------------------------------- ----------- ----------- ----------- ------ ----------- ------ ----------- ----------- ----------- -----------\n"));
  1006. for ( i = 0; i < sortedSums.size() && i < (unsigned)maxLen; i++ )
  1007. {
  1008. double avg = ( sortedSums[i].calls ) ? sortedSums[i].time / (double)sortedSums[i].calls : 0.0;
  1009. double avgLessChildren = ( sortedSums[i].calls ) ? sortedSums[i].timeLessChildren / (double)sortedSums[i].calls : 0.0;
  1010. Msg( _T(" %52.52s%12d%12.3f%12.3f%7.2f%12.3f%7.2f%12.3f%12.3f%12.3f%12.3f\n"),
  1011. sortedSums[i].pszProfileScope,
  1012. sortedSums[i].calls,
  1013. (float)sortedSums[i].calls / (float)g_TotalFrames,
  1014. sortedSums[i].time,
  1015. min( ( sortedSums[i].time / totalTime ) * 100.0, 100.0 ),
  1016. sortedSums[i].timeLessChildren,
  1017. min( ( sortedSums[i].timeLessChildren / totalTime ) * 100.0, 100.0 ),
  1018. sortedSums[i].time / (float)g_TotalFrames,
  1019. avg,
  1020. avgLessChildren,
  1021. sortedSums[i].peak );
  1022. }
  1023. }
  1024. #if defined( _X360 )
  1025. // Dump information on all nodes with PMC recording
  1026. static void DumpPMC( CVProfNode *pNode, bool &bPrintHeader, uint64 L2thresh = 1, uint64 LHSthresh = 1 )
  1027. {
  1028. if (!pNode) return;
  1029. uint64 l2 = pNode->GetL2CacheMisses();
  1030. uint64 lhs = pNode->GetLoadHitStores();
  1031. if ( l2 > L2thresh &&
  1032. lhs > LHSthresh )
  1033. {
  1034. // met threshold.
  1035. if (bPrintHeader)
  1036. {
  1037. // print header
  1038. Msg( _T("-- 360 PMC information --\n") );
  1039. Msg( _T("Scope L2/call L2/frame LHS/call LHS/frame\n") );
  1040. Msg( _T("---------------------------------------------------- --------- --------- --------- ---------\n") );
  1041. bPrintHeader = false;
  1042. }
  1043. // print
  1044. float calls = pNode->GetTotalCalls();
  1045. float frames = g_TotalFrames;
  1046. Msg( _T("%52.52s %9.2f %9.2f %9.2f %9.2f\n"), pNode->GetName(), l2/calls, l2/frames, lhs/calls, lhs/frames );
  1047. }
  1048. if ( pNode->GetSibling() )
  1049. {
  1050. DumpPMC( pNode->GetSibling(), bPrintHeader, L2thresh, LHSthresh );
  1051. }
  1052. if ( pNode->GetChild() )
  1053. {
  1054. DumpPMC( pNode->GetChild(), bPrintHeader, L2thresh, LHSthresh );
  1055. }
  1056. }
  1057. #endif
  1058. //-------------------------------------
  1059. void CVProfile::OutputReport( int type, const tchar *pszStartNode, int budgetGroupID )
  1060. {
  1061. Msg( _T("******** BEGIN VPROF REPORT ********\n"));
  1062. #ifdef _MSC_VER
  1063. #if (_MSC_VER < 1300)
  1064. Msg( _T(" (note: this report exceeds the output capacity of MSVC debug window. Use console window or console log.) \n"));
  1065. #endif
  1066. #endif
  1067. g_TotalFrames = max( NumFramesSampled() - 1, 1 );
  1068. if ( NumFramesSampled() == 0 || GetTotalTimeSampled() == 0)
  1069. Msg( _T("No samples\n") );
  1070. else
  1071. {
  1072. if ( type & VPRT_SUMMARY )
  1073. {
  1074. Msg( _T("-- Summary --\n") );
  1075. Msg( _T("%d frames sampled for %.2f seconds\n"), g_TotalFrames, GetTotalTimeSampled() / 1000.0 );
  1076. Msg( _T("Average %.2f fps, %.2f ms per frame\n"), 1000.0 / ( GetTotalTimeSampled() / g_TotalFrames ), GetTotalTimeSampled() / g_TotalFrames );
  1077. Msg( _T("Peak %.2f ms frame\n"), GetPeakFrameTime() );
  1078. double timeAccountedFor = 100.0 - ( m_Root.GetTotalTimeLessChildren() / m_Root.GetTotalTime() );
  1079. Msg( _T("%.0f pct of time accounted for\n"), min( 100.0, timeAccountedFor ) );
  1080. Msg( _T("\n") );
  1081. }
  1082. if ( pszStartNode == NULL )
  1083. {
  1084. pszStartNode = GetRoot()->GetName();
  1085. }
  1086. SumTimes( pszStartNode, budgetGroupID );
  1087. // Dump the hierarchy
  1088. if ( type & VPRT_HIERARCHY )
  1089. {
  1090. Msg( _T("-- Hierarchical Call Graph --\n"));
  1091. if ( pszStartNode == NULL )
  1092. g_pStartNode = NULL;
  1093. else
  1094. g_pStartNode = FindNode( GetRoot(), pszStartNode );
  1095. DumpNodes( (!g_pStartNode) ? GetRoot() : g_pStartNode, 0, false );
  1096. Msg( _T("\n") );
  1097. }
  1098. if ( type & VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY )
  1099. {
  1100. Msg( _T("-- Hierarchical Call Graph --\n"));
  1101. if ( pszStartNode == NULL )
  1102. g_pStartNode = NULL;
  1103. else
  1104. g_pStartNode = FindNode( GetRoot(), pszStartNode );
  1105. DumpNodes( (!g_pStartNode) ? GetRoot() : g_pStartNode, 0, true );
  1106. Msg( _T("\n") );
  1107. }
  1108. int maxLen = ( type & VPRT_LIST_TOP_ITEMS_ONLY ) ? 25 : 999999;
  1109. if ( type & VPRT_LIST_BY_TIME )
  1110. {
  1111. DumpSorted( _T("-- Profile scopes sorted by time (including children) --"), GetTotalTimeSampled(), TimeCompare, maxLen );
  1112. Msg( _T("\n") );
  1113. }
  1114. if ( type & VPRT_LIST_BY_TIME_LESS_CHILDREN )
  1115. {
  1116. DumpSorted( _T("-- Profile scopes sorted by time (without children) --"), GetTotalTimeSampled(), TimeLessChildrenCompare, maxLen );
  1117. Msg( _T("\n") );
  1118. }
  1119. if ( type & VPRT_LIST_BY_AVG_TIME )
  1120. {
  1121. DumpSorted( _T("-- Profile scopes sorted by average time (including children) --"), GetTotalTimeSampled(), AverageTimeCompare, maxLen );
  1122. Msg( _T("\n") );
  1123. }
  1124. if ( type & VPRT_LIST_BY_AVG_TIME_LESS_CHILDREN )
  1125. {
  1126. DumpSorted( _T("-- Profile scopes sorted by average time (without children) --"), GetTotalTimeSampled(), AverageTimeLessChildrenCompare, maxLen );
  1127. Msg( _T("\n") );
  1128. }
  1129. if ( type & VPRT_LIST_BY_PEAK_TIME )
  1130. {
  1131. DumpSorted( _T("-- Profile scopes sorted by peak --"), GetTotalTimeSampled(), PeakCompare, maxLen);
  1132. Msg( _T("\n") );
  1133. }
  1134. if ( type & VPRT_LIST_BY_PEAK_OVER_AVERAGE )
  1135. {
  1136. DumpSorted( _T("-- Profile scopes sorted by peak over average (including children) --"), GetTotalTimeSampled(), PeakOverAverageCompare, maxLen );
  1137. Msg( _T("\n") );
  1138. }
  1139. // TODO: Functions by time less children
  1140. // TODO: Functions by time averages
  1141. // TODO: Functions by peak
  1142. // TODO: Peak deviation from average
  1143. g_TimesLessChildren.clear();
  1144. g_TimeSumsMap.clear();
  1145. g_TimeSums.clear();
  1146. #ifdef _X360
  1147. bool bPrintedHeader = true;
  1148. DumpPMC( FindNode( GetRoot(), pszStartNode ), bPrintedHeader );
  1149. #endif
  1150. }
  1151. Msg( _T("******** END VPROF REPORT ********\n"));
  1152. }
  1153. //=============================================================================
  1154. CVProfile::CVProfile()
  1155. : m_Root( _T("Root"), 0, NULL, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, 0 ),
  1156. m_pCurNode( &m_Root ),
  1157. m_nFrames( 0 ),
  1158. m_enabled( 0 ), // don't change this. if m_enabled is anything but zero coming out of this constructor, vprof will break.
  1159. m_pausedEnabledDepth( 0 ),
  1160. m_fAtRoot( true )
  1161. {
  1162. #ifdef VPROF_VTUNE_GROUP
  1163. m_GroupIDStackDepth = 1;
  1164. m_GroupIDStack[0] = 0; // VPROF_BUDGETGROUP_OTHER_UNACCOUNTED
  1165. #endif
  1166. m_TargetThreadId = ThreadGetCurrentId();
  1167. // Go ahead and allocate 32 slots for budget group names
  1168. MEM_ALLOC_CREDIT();
  1169. m_pBudgetGroups = new CVProfile::CBudgetGroup[32];
  1170. m_nBudgetGroupNames = 0;
  1171. m_nBudgetGroupNamesAllocated = 32;
  1172. // Add these here so that they will always be in the same order.
  1173. // VPROF_BUDGETGROUP_OTHER_UNACCOUNTED has to be FIRST!!!!
  1174. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1175. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_WORLD_RENDERING, BUDGETFLAG_CLIENT );
  1176. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING, BUDGETFLAG_CLIENT );
  1177. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_GAME, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1178. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_PLAYER, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1179. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_NPCS, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1180. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_SERVER_ANIM, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1181. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_CLIENT_ANIMATION, BUDGETFLAG_CLIENT );
  1182. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_PHYSICS, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1183. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_STATICPROP_RENDERING, BUDGETFLAG_CLIENT );
  1184. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_MODEL_RENDERING, BUDGETFLAG_CLIENT );
  1185. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING,BUDGETFLAG_CLIENT );
  1186. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_LIGHTCACHE, BUDGETFLAG_CLIENT );
  1187. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING, BUDGETFLAG_CLIENT );
  1188. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_SHADOW_RENDERING, BUDGETFLAG_CLIENT );
  1189. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_DETAILPROP_RENDERING, BUDGETFLAG_CLIENT );
  1190. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_PARTICLE_RENDERING, BUDGETFLAG_CLIENT );
  1191. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_ROPES, BUDGETFLAG_CLIENT );
  1192. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_DLIGHT_RENDERING, BUDGETFLAG_CLIENT );
  1193. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OTHER_NETWORKING, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1194. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OTHER_SOUND, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1195. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OTHER_VGUI, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1196. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OTHER_FILESYSTEM, BUDGETFLAG_OTHER | BUDGETFLAG_SERVER );
  1197. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_PREDICTION, BUDGETFLAG_CLIENT );
  1198. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_INTERPOLATION, BUDGETFLAG_CLIENT );
  1199. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_SWAP_BUFFERS, BUDGETFLAG_CLIENT );
  1200. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OCCLUSION, BUDGETFLAG_CLIENT );
  1201. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_OVERLAYS, BUDGETFLAG_CLIENT );
  1202. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_TOOLS, BUDGETFLAG_OTHER | BUDGETFLAG_CLIENT );
  1203. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_TEXTURE_CACHE, BUDGETFLAG_CLIENT );
  1204. BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_REPLAY, BUDGETFLAG_SERVER );
  1205. // BudgetGroupNameToBudgetGroupID( VPROF_BUDGETGROUP_DISP_HULLTRACES );
  1206. m_bPMEInit = false;
  1207. m_bPMEEnabled = false;
  1208. #ifdef VPROF_VXCONSOLE_EXISTS
  1209. m_bTraceCompleteEvent = false;
  1210. m_iSuccessiveTraceIndex = 0;
  1211. m_ReportMode = VXCONSOLE_REPORT_TIME;
  1212. m_pReportScale[VXCONSOLE_REPORT_TIME] = 1000.0f;
  1213. m_pReportScale[VXCONSOLE_REPORT_L2CACHE_MISSES] = 1.0f;
  1214. m_pReportScale[VXCONSOLE_REPORT_LOAD_HIT_STORE] = 0.1f;
  1215. m_nFrameCount = 0;
  1216. m_nFramesRemaining = 1;
  1217. m_WorstCycles = 0;
  1218. m_WorstTraceFilename[ 0 ] = 0;
  1219. m_UpdateMode = 0;
  1220. #endif
  1221. #ifdef _X360
  1222. m_iCPUTraceEnabled = kDisabled;
  1223. #endif
  1224. }
  1225. CVProfile::~CVProfile()
  1226. {
  1227. Term();
  1228. }
  1229. void CVProfile::FreeNodes_R( CVProfNode *pNode )
  1230. {
  1231. CVProfNode *pNext;
  1232. for ( CVProfNode *pChild = pNode->GetChild(); pChild; pChild = pNext )
  1233. {
  1234. pNext = pChild->GetSibling();
  1235. FreeNodes_R( pChild );
  1236. }
  1237. if ( pNode == GetRoot() )
  1238. {
  1239. pNode->m_pChild = NULL;
  1240. }
  1241. else
  1242. {
  1243. delete pNode;
  1244. }
  1245. }
  1246. void CVProfile::Term()
  1247. {
  1248. int i;
  1249. for( i = 0; i < m_nBudgetGroupNames; i++ )
  1250. {
  1251. delete [] m_pBudgetGroups[i].m_pName;
  1252. }
  1253. delete m_pBudgetGroups;
  1254. m_nBudgetGroupNames = m_nBudgetGroupNamesAllocated = 0;
  1255. m_pBudgetGroups = NULL;
  1256. int n;
  1257. for( n = 0; n < m_NumCounters; n++ )
  1258. {
  1259. delete [] m_CounterNames[n];
  1260. m_CounterNames[n] = NULL;
  1261. }
  1262. m_NumCounters = 0;
  1263. // Free the nodes.
  1264. if ( GetRoot() )
  1265. {
  1266. FreeNodes_R( GetRoot() );
  1267. }
  1268. }
  1269. #define COLORMIN 160
  1270. #define COLORMAX 255
  1271. static int g_ColorLookup[4] =
  1272. {
  1273. COLORMIN,
  1274. COLORMAX,
  1275. COLORMIN+(COLORMAX-COLORMIN)/3,
  1276. COLORMIN+((COLORMAX-COLORMIN)*2)/3,
  1277. };
  1278. #define GET_BIT( val, bitnum ) ( ( val >> bitnum ) & 0x1 )
  1279. void CVProfile::GetBudgetGroupColor( int budgetGroupID, int &r, int &g, int &b, int &a )
  1280. {
  1281. budgetGroupID = budgetGroupID % ( 1 << 6 );
  1282. int index;
  1283. index = GET_BIT( budgetGroupID, 0 ) | ( GET_BIT( budgetGroupID, 5 ) << 1 );
  1284. r = g_ColorLookup[index];
  1285. index = GET_BIT( budgetGroupID, 1 ) | ( GET_BIT( budgetGroupID, 4 ) << 1 );
  1286. g = g_ColorLookup[index];
  1287. index = GET_BIT( budgetGroupID, 2 ) | ( GET_BIT( budgetGroupID, 3 ) << 1 );
  1288. b = g_ColorLookup[index];
  1289. a = 255;
  1290. }
  1291. // return -1 if it doesn't exist.
  1292. int CVProfile::FindBudgetGroupName( const tchar *pBudgetGroupName )
  1293. {
  1294. int i;
  1295. for( i = 0; i < m_nBudgetGroupNames; i++ )
  1296. {
  1297. if( _tcsicmp( pBudgetGroupName, m_pBudgetGroups[i].m_pName ) == 0 )
  1298. {
  1299. return i;
  1300. }
  1301. }
  1302. return -1;
  1303. }
  1304. int CVProfile::AddBudgetGroupName( const tchar *pBudgetGroupName, int budgetFlags )
  1305. {
  1306. MEM_ALLOC_CREDIT();
  1307. tchar *pNewString = new tchar[ _tcslen( pBudgetGroupName ) + 1 ];
  1308. _tcscpy( pNewString, pBudgetGroupName );
  1309. if( m_nBudgetGroupNames + 1 > m_nBudgetGroupNamesAllocated )
  1310. {
  1311. m_nBudgetGroupNamesAllocated *= 2;
  1312. m_nBudgetGroupNamesAllocated = max( m_nBudgetGroupNames + 6, m_nBudgetGroupNamesAllocated );
  1313. CBudgetGroup *pNew = new CBudgetGroup[ m_nBudgetGroupNamesAllocated ];
  1314. for ( int i=0; i < m_nBudgetGroupNames; i++ )
  1315. pNew[i] = m_pBudgetGroups[i];
  1316. delete [] m_pBudgetGroups;
  1317. m_pBudgetGroups = pNew;
  1318. }
  1319. m_pBudgetGroups[m_nBudgetGroupNames].m_pName = pNewString;
  1320. m_pBudgetGroups[m_nBudgetGroupNames].m_BudgetFlags = budgetFlags;
  1321. m_nBudgetGroupNames++;
  1322. if( m_pNumBudgetGroupsChangedCallBack )
  1323. {
  1324. (*m_pNumBudgetGroupsChangedCallBack)();
  1325. }
  1326. #if defined( VPROF_VXCONSOLE_EXISTS )
  1327. // re-start with all the known budgets
  1328. VXProfileStart();
  1329. #endif
  1330. return m_nBudgetGroupNames - 1;
  1331. }
  1332. int CVProfile::BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName, int budgetFlagsToORIn )
  1333. {
  1334. int budgetGroupID = FindBudgetGroupName( pBudgetGroupName );
  1335. if( budgetGroupID == -1 )
  1336. {
  1337. budgetGroupID = AddBudgetGroupName( pBudgetGroupName, budgetFlagsToORIn );
  1338. }
  1339. else
  1340. {
  1341. m_pBudgetGroups[budgetGroupID].m_BudgetFlags |= budgetFlagsToORIn;
  1342. }
  1343. return budgetGroupID;
  1344. }
  1345. int CVProfile::BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName )
  1346. {
  1347. return BudgetGroupNameToBudgetGroupID( pBudgetGroupName, BUDGETFLAG_OTHER );
  1348. }
  1349. int CVProfile::GetNumBudgetGroups( void )
  1350. {
  1351. return m_nBudgetGroupNames;
  1352. }
  1353. void CVProfile::RegisterNumBudgetGroupsChangedCallBack( void (*pCallBack)(void) )
  1354. {
  1355. m_pNumBudgetGroupsChangedCallBack = pCallBack;
  1356. }
  1357. void CVProfile::HideBudgetGroup( int budgetGroupID, bool bHide )
  1358. {
  1359. if( budgetGroupID != -1 )
  1360. {
  1361. if ( bHide )
  1362. m_pBudgetGroups[budgetGroupID].m_BudgetFlags |= BUDGETFLAG_HIDDEN;
  1363. else
  1364. m_pBudgetGroups[budgetGroupID].m_BudgetFlags &= ~BUDGETFLAG_HIDDEN;
  1365. }
  1366. }
  1367. int *CVProfile::FindOrCreateCounter( const tchar *pName, CounterGroup_t eCounterGroup )
  1368. {
  1369. Assert( m_NumCounters+1 < MAXCOUNTERS );
  1370. if ( m_NumCounters + 1 >= MAXCOUNTERS || !InTargetThread() )
  1371. {
  1372. static int dummy;
  1373. return &dummy;
  1374. }
  1375. int i;
  1376. for( i = 0; i < m_NumCounters; i++ )
  1377. {
  1378. if( _tcsicmp( m_CounterNames[i], pName ) == 0 )
  1379. {
  1380. // found it!
  1381. return &m_Counters[i];
  1382. }
  1383. }
  1384. // NOTE: These get freed in ~CVProfile.
  1385. MEM_ALLOC_CREDIT();
  1386. tchar *pNewName = new tchar[_tcslen( pName ) + 1];
  1387. _tcscpy( pNewName, pName );
  1388. m_Counters[m_NumCounters] = 0;
  1389. m_CounterGroups[m_NumCounters] = (char)eCounterGroup;
  1390. m_CounterNames[m_NumCounters++] = pNewName;
  1391. return &m_Counters[m_NumCounters-1];
  1392. }
  1393. void CVProfile::ResetCounters( CounterGroup_t eCounterGroup )
  1394. {
  1395. int i;
  1396. for( i = 0; i < m_NumCounters; i++ )
  1397. {
  1398. if ( m_CounterGroups[i] == eCounterGroup )
  1399. m_Counters[i] = 0;
  1400. }
  1401. }
  1402. int CVProfile::GetNumCounters() const
  1403. {
  1404. return m_NumCounters;
  1405. }
  1406. const tchar *CVProfile::GetCounterName( int index ) const
  1407. {
  1408. Assert( index >= 0 && index < m_NumCounters );
  1409. return m_CounterNames[index];
  1410. }
  1411. int CVProfile::GetCounterValue( int index ) const
  1412. {
  1413. Assert( index >= 0 && index < m_NumCounters );
  1414. return m_Counters[index];
  1415. }
  1416. const tchar *CVProfile::GetCounterNameAndValue( int index, int &val ) const
  1417. {
  1418. Assert( index >= 0 && index < m_NumCounters );
  1419. val = m_Counters[index];
  1420. return m_CounterNames[index];
  1421. }
  1422. CounterGroup_t CVProfile::GetCounterGroup( int index ) const
  1423. {
  1424. Assert( index >= 0 && index < m_NumCounters );
  1425. return (CounterGroup_t)m_CounterGroups[index];
  1426. }
  1427. #ifdef _X360
  1428. void CVProfile::LatchMultiFrame( int64 cycles )
  1429. {
  1430. if ( cycles > m_WorstCycles )
  1431. {
  1432. strncpy( m_WorstTraceFilename, GetCPUTraceFilename(), sizeof( m_WorstTraceFilename ) );
  1433. m_WorstCycles = cycles;
  1434. }
  1435. }
  1436. void CVProfile::SpewWorstMultiFrame()
  1437. {
  1438. CCycleCount cc( m_WorstCycles );
  1439. Msg( "%s == %.3f msec\n", m_WorstTraceFilename, cc.GetMillisecondsF() );
  1440. }
  1441. #endif
  1442. #ifdef DBGFLAG_VALIDATE
  1443. #ifdef _WIN64
  1444. #error the below is presumably broken on 64 bit
  1445. #endif // _WIN64
  1446. const int k_cSTLMapAllocOffset = 4;
  1447. #define GET_INTERNAL_MAP_ALLOC_PTR( pMap ) \
  1448. ( * ( (void **) ( ( ( byte * ) ( pMap ) ) + k_cSTLMapAllocOffset ) ) )
  1449. //-----------------------------------------------------------------------------
  1450. // Purpose: Ensure that all of our internal structures are consistent, and
  1451. // account for all memory that we've allocated.
  1452. // Input: validator - Our global validator object
  1453. // pchName - Our name (typically a member var in our container)
  1454. //-----------------------------------------------------------------------------
  1455. void CVProfile::Validate( CValidator &validator, tchar *pchName )
  1456. {
  1457. validator.Push( _T("CVProfile"), this, pchName );
  1458. m_Root.Validate( validator, _T("m_Root") );
  1459. for ( int iBudgetGroup=0; iBudgetGroup < m_nBudgetGroupNames; iBudgetGroup++ )
  1460. validator.ClaimMemory( m_pBudgetGroups[iBudgetGroup].m_pName );
  1461. validator.ClaimMemory( m_pBudgetGroups );
  1462. // The std template map class allocates memory internally, but offer no way to get
  1463. // access to their pointer. Since this is for debug purposes only and the
  1464. // std template classes don't change, just look at the well-known offset. This
  1465. // is arguably sick and wrong, kind of like marrying a squirrel.
  1466. validator.ClaimMemory( GET_INTERNAL_MAP_ALLOC_PTR( &g_TimesLessChildren ) );
  1467. validator.ClaimMemory( GET_INTERNAL_MAP_ALLOC_PTR( &g_TimeSumsMap ) );
  1468. validator.Pop( );
  1469. }
  1470. #endif // DBGFLAG_VALIDATE
  1471. #endif // VPROF_ENABLED
  1472. #ifdef RAD_TELEMETRY_ENABLED
  1473. #ifdef POSIX
  1474. extern "C" char *
  1475. __realpath_chk (const char *buf, char *resolved, size_t resolvedlen)
  1476. {
  1477. return realpath (buf, resolved);
  1478. }
  1479. #endif
  1480. TelemetryData g_Telemetry;
  1481. static HTELEMETRY g_tmContext;
  1482. static TmU8 *g_pTmMemoryArena = NULL;
  1483. static bool g_TelemetryLoaded = false;
  1484. static unsigned int g_TelemetryFrameCount = 0;
  1485. static bool g_fTelemetryLevelChanged = false;
  1486. struct ThreadNameInfo_t
  1487. {
  1488. TSLNodeBase_t base;
  1489. ThreadId_t ThreadID;
  1490. char szName[ 64 ];
  1491. };
  1492. static CTSSimpleList< ThreadNameInfo_t > g_ThreadNamesList;
  1493. static bool g_bThreadNameArrayChanged = false;
  1494. static int g_ThreadNameArrayCount = 0;
  1495. static ThreadNameInfo_t g_ThreadNameArray[32];
  1496. void TelemetryThreadSetDebugName( ThreadId_t id, const char *pszName )
  1497. {
  1498. ThreadNameInfo_t *pThreadNameInfo = new ThreadNameInfo_t;
  1499. if( id == ( uint32 )-1 )
  1500. {
  1501. id = ThreadGetCurrentId();
  1502. }
  1503. pThreadNameInfo->ThreadID = id;
  1504. strncpy( pThreadNameInfo->szName, pszName, ARRAYSIZE( pThreadNameInfo->szName ) );
  1505. pThreadNameInfo->szName[ ARRAYSIZE( pThreadNameInfo->szName ) - 1 ] = 0;
  1506. g_ThreadNamesList.Push( pThreadNameInfo );
  1507. g_bThreadNameArrayChanged = true;
  1508. }
  1509. const int TELEMETRY_ARENA_SIZE = 32 * 1024 * 1024; // How much memory we want Telemetry to use.
  1510. static bool TelemetryInitialize()
  1511. {
  1512. if( g_tmContext )
  1513. {
  1514. TmConnectionStatus status = TM_GET_CONNECTION_STATUS( g_tmContext );
  1515. if( status == TMCS_CONNECTED || status == TMCS_CONNECTING )
  1516. return true;
  1517. }
  1518. TmErrorCode retVal;
  1519. if( !g_TelemetryLoaded )
  1520. {
  1521. // Pass in 0 if you want to use the release mode DLL or 1 if you want to
  1522. // use the checked DLL. The checked DLL is compiled with optimizations but
  1523. // does extra run time checks and reporting.
  1524. int nLoadTelemetry = TM_LOAD_TELEMETRY( 0 );
  1525. retVal = TM_STARTUP();
  1526. if ( retVal != TM_OK )
  1527. {
  1528. Warning( "TelemetryInit() failed: tmStartup() returned %d, tmLoadTelemetry() returned %d.\n", retVal, nLoadTelemetry );
  1529. return false;
  1530. }
  1531. if( !g_pTmMemoryArena )
  1532. {
  1533. g_pTmMemoryArena = new TmU8[ TELEMETRY_ARENA_SIZE ];
  1534. }
  1535. retVal = TM_INITIALIZE_CONTEXT( &g_tmContext, g_pTmMemoryArena, TELEMETRY_ARENA_SIZE );
  1536. if ( retVal != TM_OK )
  1537. {
  1538. delete [] g_pTmMemoryArena;
  1539. g_pTmMemoryArena = NULL;
  1540. Warning( "TelemetryInit() failed: tmInitializeContext() returned %d.\n", retVal );
  1541. return false;
  1542. }
  1543. g_TelemetryLoaded = true;
  1544. }
  1545. char *pGameName = "csgo";
  1546. #if defined( IS_WINDOWS_PC )
  1547. char baseExeFilename[512];
  1548. if( GetModuleFileName ( GetModuleHandle( NULL ), baseExeFilename, sizeof( baseExeFilename ) ) )
  1549. {
  1550. char *pExt = strrchr( baseExeFilename, '.' );
  1551. if( pExt )
  1552. *pExt = 0;
  1553. char *pSeparator = strrchr( baseExeFilename, '\\' );
  1554. pGameName = pSeparator ? ( pSeparator + 1 ) : baseExeFilename;
  1555. }
  1556. // If you've got \\perforce\symbols on your _NT_SYMBOL_PATH, tmOpen() can take a massively long
  1557. // time in the symInitialize() routine. Since we don't really need that, kill it here.
  1558. putenv( "_NT_SYMBOL_PATH=" );
  1559. #endif
  1560. const char *pServerAddress = g_Telemetry.ServerAddress[0] ? g_Telemetry.ServerAddress : "localhost";
  1561. TmConnectionType tmType = TMCT_TCP; // !V_tier0_stricmp( pServerAddress, "FILE" ) ? TMCT_FILE : TMCT_TCP;
  1562. Msg( "TELEMETRY: Calling tmOpen( %s )...\n", pServerAddress );
  1563. char szBuildInfo[ 2048 ];
  1564. _snprintf( szBuildInfo, ARRAYSIZE( szBuildInfo ), "%s: %s", __DATE__ __TIME__, Plat_GetCommandLine() );
  1565. szBuildInfo[ ARRAYSIZE( szBuildInfo ) - 1 ] = 0;
  1566. TmU32 TmOpenFlags = TMOF_DEFAULT | TMOF_MINIMAL_CONTEXT_SWITCHES;
  1567. /* TmOpenFlags |= TMOF_DISABLE_CONTEXT_SWITCHES | TMOF_INIT_NETWORKING*/
  1568. retVal = TM_OPEN( g_tmContext, pGameName, szBuildInfo, pServerAddress, tmType,
  1569. TELEMETRY_DEFAULT_PORT, TmOpenFlags, 1000 );
  1570. if ( retVal != TM_OK )
  1571. {
  1572. Warning( "TelemetryInitialize() failed: tmOpen returned %d.\n", retVal );
  1573. return false;
  1574. }
  1575. Msg( "Telemetry initialized at level %u.\n", g_Telemetry.Level );
  1576. #ifdef LINUX
  1577. printf( "Telemetry initialized at level %u.\n", g_Telemetry.Level );
  1578. #endif
  1579. if( g_bThreadNameArrayChanged )
  1580. {
  1581. // Go through and add any new thread names we got in our thread safe list to our thread names array.
  1582. for( ThreadNameInfo_t *pThreadNameInfo = g_ThreadNamesList.Pop();
  1583. pThreadNameInfo;
  1584. pThreadNameInfo = g_ThreadNamesList.Pop() )
  1585. {
  1586. if( g_ThreadNameArrayCount < ARRAYSIZE( g_ThreadNameArray ) )
  1587. {
  1588. g_ThreadNameArray[ g_ThreadNameArrayCount ] = *pThreadNameInfo;
  1589. g_ThreadNameArrayCount++;
  1590. }
  1591. delete pThreadNameInfo;
  1592. }
  1593. for( int i = 0; i < g_ThreadNameArrayCount; i++ )
  1594. {
  1595. tmThreadName( g_tmContext, g_ThreadNameArray[i].ThreadID, g_ThreadNameArray[i].szName );
  1596. }
  1597. g_bThreadNameArrayChanged = false;
  1598. }
  1599. // Default Zone Filter value to .5ms if they haven't set it already.
  1600. if( !g_Telemetry.ZoneFilterVal )
  1601. g_Telemetry.ZoneFilterVal = 500;
  1602. // Init plot data
  1603. for( int i = 0; i < TELEMETRY_ZONE_PLOT_SLOT_MAX; ++i )
  1604. {
  1605. g_Telemetry.m_ZonePlot[i].m_Name = NULL;
  1606. g_Telemetry.m_ZonePlot[i].m_CurrFrameTime = 0;
  1607. }
  1608. return true;
  1609. }
  1610. #if 0
  1611. //an instance of TM_API_STRUCT that points to stubbed out functions
  1612. class CTM_API_STRUCT_Stub : public TM_API_STRUCT
  1613. {
  1614. public:
  1615. inline CTM_API_STRUCT_Stub( void ) {}; //this empty default constructor works around warning C4701 "potentially uninitialized local variable * used" in code below. We initialize it and use it in 2 different scopes that use the same boolean
  1616. const CTM_API_STRUCT_Stub &operator=( const TM_API_STRUCT &Existing );
  1617. void LinkToStubs( void ); //replaces all known function pointers with stubbed versions
  1618. };
  1619. #endif
  1620. static void TelemetryShutdown( bool InDtor = false )
  1621. {
  1622. if( g_tmContext )
  1623. {
  1624. // Msg can't be called here as tier0 may have already been shut down...
  1625. if( !InDtor )
  1626. {
  1627. Msg( "Shutting down telemetry.\n" );
  1628. }
  1629. TmConnectionStatus status = TM_GET_CONNECTION_STATUS( g_tmContext );
  1630. if( status == TMCS_CONNECTED || status == TMCS_CONNECTING )
  1631. TM_CLOSE( g_tmContext );
  1632. #if 0
  1633. CTM_API_STRUCT_Stub stubbedApiStruct;
  1634. //Tm__Zone usage saves off a copy of g_tmContext and will attempt to use that pointer when leaving scope.
  1635. //This include threads that we're not especially great at shutting down yet.
  1636. //If we happen to own the memory that the context points at, we'll just stub out the pointers instead of completely deleting the memory
  1637. const bool bUseLazyShutdownStubs = IsPlatformWindowsPC() &&
  1638. ( ( g_tmContext >= ( HTELEMETRY ) g_pTmMemoryArena ) && ( g_tmContext < ( HTELEMETRY )( g_pTmMemoryArena + TELEMETRY_ARENA_SIZE ) ) ); //we completely own the memory that the context points at
  1639. if ( bUseLazyShutdownStubs )
  1640. {
  1641. if( !InDtor )
  1642. {
  1643. Msg( "Using lazy telemetry shutdown stub functions\n\tArena: %p, Context: %p\n", g_pTmMemoryArena, g_tmContext ); //previous testing has shown that the context is at the start of the arena
  1644. }
  1645. stubbedApiStruct = *(TM_API_STRUCT *)g_tmContext; // a bit of future proofing to ensure that we'll use whatever was in the old struct if we fail to initialize a particular stub
  1646. stubbedApiStruct.LinkToStubs();
  1647. }
  1648. #endif
  1649. //discontinue new usage of the context before shutting it down (multithreading)
  1650. memset( g_Telemetry.tmContext, 0, sizeof( g_Telemetry.tmContext ) );
  1651. HTELEMETRY hShutdown = g_tmContext;
  1652. g_tmContext = NULL;
  1653. TM_SHUTDOWN_CONTEXT( hShutdown );
  1654. #if 0
  1655. if ( bUseLazyShutdownStubs )
  1656. {
  1657. //there's a window where this context will be in an unknown state
  1658. memcpy( hShutdown, &stubbedApiStruct, sizeof( TM_API_STRUCT ) );
  1659. }
  1660. else
  1661. #endif
  1662. if ( !IsPlatformWindowsPC() ) //actual test should be "do we probably have outstanding threads"
  1663. {
  1664. delete [] g_pTmMemoryArena;
  1665. g_pTmMemoryArena = NULL;
  1666. }
  1667. TM_SHUTDOWN();
  1668. g_TelemetryLoaded = false;
  1669. }
  1670. }
  1671. // Helper class to initialize Telemetry.
  1672. class CTelemetryRegister
  1673. {
  1674. public:
  1675. CTelemetryRegister() {}
  1676. ~CTelemetryRegister() { TelemetryShutdown( true ); }
  1677. } g_TelemetryRegister;
  1678. PLATFORM_INTERFACE void TelemetrySetLevel( unsigned int Level )
  1679. {
  1680. DevMsg( "TelemetrySetLevel changed from 0x%x to 0x%x (ZoneFilterVal:%d)\n", g_Telemetry.Level, Level, g_Telemetry.ZoneFilterVal );
  1681. if( Level != g_Telemetry.Level )
  1682. {
  1683. g_Telemetry.Level = Level;
  1684. g_TelemetryFrameCount = g_Telemetry.FrameCount;
  1685. g_fTelemetryLevelChanged = true;
  1686. }
  1687. }
  1688. #if defined( IS_WINDOWS_PC )
  1689. #include <psapi.h>
  1690. typedef BOOL ( WINAPI *GetProcessMemoryInfo_t )( HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb );
  1691. static CDynamicFunction< GetProcessMemoryInfo_t > DynGetProcessMemoryInfo( "psapi.dll", "GetProcessMemoryInfo" );
  1692. #endif
  1693. static void TelemetryPlots()
  1694. {
  1695. if( g_Telemetry.playbacktick )
  1696. {
  1697. TM_PLOT_U32( TELEMETRY_LEVEL1, TMPT_INTEGER, 0, g_Telemetry.playbacktick, "game/PlaybackTick" );
  1698. g_Telemetry.playbacktick = 0;
  1699. }
  1700. if( g_Telemetry.dotatime )
  1701. {
  1702. TM_PLOT_F32( TELEMETRY_LEVEL1, TMPT_NONE, 0, g_Telemetry.dotatime, "game/DotaTime" );
  1703. g_Telemetry.dotatime = 0.0f;
  1704. }
  1705. for( int i = 0; i < g_VProfCurrentProfile.GetNumCounters(); i++ )
  1706. {
  1707. if( g_VProfCurrentProfile.GetCounterGroup( i ) == COUNTER_GROUP_TELEMETRY )
  1708. {
  1709. int val;
  1710. const char *name = g_VProfCurrentProfile.GetCounterNameAndValue( i, val );
  1711. TM_PLOT_I32( TELEMETRY_LEVEL1, TMPT_INTEGER, 0, val, name );
  1712. }
  1713. }
  1714. g_VProfCurrentProfile.ResetCounters( COUNTER_GROUP_TELEMETRY );
  1715. // Send plot value collected using TM_ZONE_PLOT macro
  1716. // Data sent as a percentage of a 16ms frame (so that Telemetry display the data nicely in the Timeline view)
  1717. for( int i = 0; i < TELEMETRY_ZONE_PLOT_SLOT_MAX; ++i )
  1718. {
  1719. TelemetryZonePlotData* pData = &g_Telemetry.m_ZonePlot[i];
  1720. if (pData->m_Name)
  1721. {
  1722. TM_PLOT_F32(
  1723. TELEMETRY_LEVEL1,
  1724. TMPT_TIME_MS,
  1725. TMPF_NONE,
  1726. (pData->m_CurrFrameTime * g_Telemetry.flRDTSCToMilliSeconds),
  1727. "(frametimes)%s(ms)", pData->m_Name );
  1728. }
  1729. pData->m_Name = NULL;
  1730. pData->m_CurrFrameTime = 0;
  1731. }
  1732. TM_PLOT_F32(
  1733. TELEMETRY_LEVEL1,
  1734. TMPT_TIME_MS,
  1735. TMPF_NONE,
  1736. 16.666f,
  1737. "(frametimes)%s(ms)", "Ref 16ms" );
  1738. }
  1739. PLATFORM_INTERFACE void TelemetryTick()
  1740. {
  1741. if( !g_Telemetry.Level && g_Telemetry.DemoTickStart && ( (uint32)g_Telemetry.playbacktick > g_Telemetry.DemoTickStart ) )
  1742. {
  1743. TelemetrySetLevel( 2 );
  1744. g_Telemetry.DemoTickStart = 0;
  1745. }
  1746. if( g_Telemetry.Level && g_Telemetry.DemoTickEnd && ( (uint32)g_Telemetry.playbacktick > g_Telemetry.DemoTickEnd ) )
  1747. {
  1748. TelemetrySetLevel( 0 );
  1749. g_Telemetry.DemoTickEnd = ( uint32 )-1;
  1750. }
  1751. if ( ( g_tmContext ) && ( g_Telemetry.Level > 0 ) )
  1752. {
  1753. TelemetryPlots();
  1754. }
  1755. static double s_d0 = Plat_FloatTime();
  1756. static TmU64 s_t0 = TM_FAST_TIME();
  1757. // People can NIL out contexts in the TelemetryData structure to control
  1758. // the level and what sections to log. We always need to do ticks though,
  1759. // so use the master context for this.
  1760. if( g_tmContext )
  1761. {
  1762. TM_TICK( g_tmContext );
  1763. }
  1764. if( g_tmContext )
  1765. {
  1766. static uint32 s_ZoneFilterValLast = 0;
  1767. if( s_ZoneFilterValLast != g_Telemetry.ZoneFilterVal )
  1768. {
  1769. g_fTelemetryLevelChanged = true;
  1770. s_ZoneFilterValLast = g_Telemetry.ZoneFilterVal;
  1771. }
  1772. TmU64 s_t1 = TM_FAST_TIME();
  1773. double s_d1 = Plat_FloatTime();
  1774. g_Telemetry.flRDTSCToMilliSeconds = 1000.0f / ( ( s_t1 - s_t0 ) / ( s_d1 - s_d0 ) );
  1775. // Msg( "g_Telemetry.flRDTSCToMilliSeconds: %f time:%f\n", g_Telemetry.flRDTSCToMilliSeconds, ( s_t1 - s_t0 ) * g_Telemetry.flRDTSCToMilliSeconds );
  1776. s_d0 = s_d1;
  1777. s_t0 = s_t1;
  1778. if( g_TelemetryFrameCount && !TM_IS_PAUSED( g_tmContext ) )
  1779. {
  1780. g_TelemetryFrameCount--;
  1781. if( !g_TelemetryFrameCount )
  1782. {
  1783. TelemetrySetLevel( 0 );
  1784. }
  1785. }
  1786. }
  1787. if( g_fTelemetryLevelChanged )
  1788. {
  1789. g_fTelemetryLevelChanged = false;
  1790. memset( g_Telemetry.tmContext, 0, sizeof( g_Telemetry.tmContext ) );
  1791. // Mask of all zeros just enables level 0.
  1792. if( g_Telemetry.Level == 0x80000000 )
  1793. g_Telemetry.Level = 1;
  1794. unsigned int Level = g_Telemetry.Level;
  1795. bool IsMask = ( Level & 0x80000000 ) ? true : false;
  1796. Level &= ~0x80000000;
  1797. if( Level == 0 )
  1798. {
  1799. // Calling shutdown here invalidates all the telemetry context handles, and background
  1800. // threads in the middle of Tm__Zone'd calls will crash. So pause things for now.
  1801. TelemetryShutdown();
  1802. }
  1803. else
  1804. {
  1805. if( !TelemetryInitialize() )
  1806. {
  1807. g_Telemetry.Level = 0;
  1808. }
  1809. else
  1810. {
  1811. TM_PAUSE( g_tmContext, 0 );
  1812. if( IsMask )
  1813. {
  1814. for( unsigned int i = 0; i < ARRAYSIZE( g_Telemetry.tmContext ); i++)
  1815. {
  1816. if( (1 << i) & Level)
  1817. {
  1818. g_Telemetry.tmContext[ i ] = g_tmContext;
  1819. }
  1820. }
  1821. }
  1822. else
  1823. {
  1824. Level = MIN( Level, ARRAYSIZE( g_Telemetry.tmContext ) );
  1825. for( unsigned int i = 0; i < Level; i++ )
  1826. {
  1827. g_Telemetry.tmContext[i] = g_tmContext;
  1828. }
  1829. }
  1830. }
  1831. }
  1832. // TM_SET_TIMELINE_SECTION_NAME( g_tmContext, "Level:0x%x", g_Telemetry.Level );
  1833. // To disable various telemetry features, use the tmEnable() function as so:
  1834. // TM_ENABLE( g_tmContext, TMO_SUPPORT_PLOT, 0 );
  1835. }
  1836. }
  1837. #if 0
  1838. const CTM_API_STRUCT_Stub &CTM_API_STRUCT_Stub::operator=( const TM_API_STRUCT &Existing )
  1839. {
  1840. memcpy( this, &Existing, sizeof( TM_API_STRUCT ) );
  1841. return *this;
  1842. }
  1843. #undef TM_API
  1844. typedef char const * tmStubCSTR;
  1845. #define tmStubRETURN_TmErrorCode return TM_OK;
  1846. #define tmStubRETURN_TmU32 return 0;
  1847. #define tmStubRETURN_void return;
  1848. #define tmStubRETURN_TmConnectionStatus return TMCS_DISCONNECTED;
  1849. #define tmStubRETURN_TmU64 return 0;
  1850. #define tmStubRETURN_int return 0;
  1851. #define tmStubRETURN_char return 0;
  1852. #define tmStubRETURN_TmI32 return 0;
  1853. #define tmStubRETURN_tmStubCSTR return "";
  1854. #define TM_API( ret, name, params ) inline ret RADEXPLINK name##Stub params { tmStubRETURN_##ret }
  1855. #if defined TM_PPU
  1856. #define TM_NUM_SPUS 6
  1857. TM_API( TmErrorCode, tmPPUCoreGetListener, ( HTELEMETRY cx, int const kNdx, TmU32 *pListener ) );
  1858. TM_API( TmErrorCode, tmPPUCoreRegisterSPUProgram, ( HTELEMETRY cx, TmU64 const kGuid, void const *imagebase, unsigned int const kImageSize, int const kRdOnlyOffset ) );
  1859. #endif
  1860. #if defined TM_IPC_HOST && defined __RADWIN__
  1861. TM_API( TmErrorCode, tmWin32CoreListenSHAREDMEM, ( HTELEMETRY cx, char const *name ) );
  1862. #endif
  1863. #if defined TM_SPU
  1864. TM_API( TmErrorCode, tmSPUCoreBindContextToListener, ( HTELEMETRY *pcx, void * mem, TmU32 kPPUListener, char const *imagename, ...) );
  1865. TM_API( TmErrorCode, tmSPUCoreUpdateTime, ( HTELEMETRY cx ) );
  1866. TM_API( TmErrorCode, tmSPUCoreFlushImage, ( HTELEMETRY cx ) );
  1867. #endif
  1868. TM_API( TmU32, tmCoreGetVersion, ( void ) );
  1869. TM_API( TmErrorCode, tmCoreCheckVersion, ( HTELEMETRY cx, TmU32 const major, TmU32 const minor, TmU32 const build, TmU32 const cust ) );
  1870. TM_API( TmErrorCode, tmCoreGetPlatformInformation, ( void* obj, TmPlatformInformation const kInfo, void* dst, TmU32 const kDstSize ) );
  1871. TM_API( TmErrorCode, tmCoreGetLastError, ( HTELEMETRY cx ) );
  1872. #ifndef TM_SPU
  1873. TM_API( TmErrorCode, tmCoreStartup, ( void ) );
  1874. TM_API( TmErrorCode, tmCoreInitializeContext, ( EXPOUT HTELEMETRY * pcx, void * pArena, TmU32 const kArenaSize ) );
  1875. TM_API( void, tmCoreShutdownContext, ( HTELEMETRY cx ) );
  1876. TM_API( void, tmCoreShutdown, ( void ) );
  1877. #endif
  1878. TM_API( TmErrorCode, tmCoreGetSessionName, ( HTELEMETRY cx, char *dst, int const kDstSize ) );
  1879. TM_API( TmConnectionStatus, tmCoreGetConnectionStatus, ( HTELEMETRY cx ) );
  1880. #ifndef TM_SPU
  1881. TM_API( TmErrorCode, tmCoreOpen, ( HTELEMETRY cx, char const * kpAppName,
  1882. char const * kpBuildInfo,
  1883. char const * kpServerAddress,
  1884. TmConnectionType const kConnection,
  1885. TmU16 const kServerPort,
  1886. TmU32 const kFlags,
  1887. int const kTimeoutMS ) );
  1888. #endif
  1889. TM_API( void, tmCoreClose, ( HTELEMETRY cx ) );
  1890. TM_API( void , tmCoreSetDebugZoneLevel, ( HTELEMETRY cx, int const v ) );
  1891. TM_API( void , tmCoreCheckDebugZoneLevel, ( HTELEMETRY cx, int const v ) );
  1892. TM_API( void , tmCoreUnwindToDebugZoneLevel, ( HTELEMETRY cx, int const v ) );
  1893. TM_API( tmStubCSTR, tmCoreDynamicString, ( HTELEMETRY cx, char const * s ) );
  1894. TM_API( void, tmCoreClearStaticString, ( HTELEMETRY cx, char const * s ) );
  1895. TM_API( void, tmCoreSetVariable, ( HTELEMETRY cx, char const *kpKey, TmU32* pFormatCode, char const *kpValueFmt, ... ) );
  1896. TM_API( void, tmCoreSetTimelineSectionName, ( HTELEMETRY cx, TmU32 *pFormatCode, char const * kpFmt, ... ) );
  1897. TM_API( void, tmCoreThreadName, ( HTELEMETRY cx, TmU32 const kThreadID, TmU32 *pFormatCode, char const * kpFmt, ... ) );
  1898. TM_API( void, tmCoreGetFormatCode, ( TmU32* pCode, char const * kpFmt ) );
  1899. TM_API( void, tmCoreEnable, ( HTELEMETRY cx, TmOption const kOption, int const kValue ) );
  1900. TM_API( int , tmCoreIsEnabled, ( HTELEMETRY cx, TmOption const kOption ) );
  1901. TM_API( void, tmCoreSetParameter, ( HTELEMETRY cx, TmParameter const kParam, void const *kpValue ) );
  1902. TM_API( void, tmCoreTick, ( HTELEMETRY cx ) );
  1903. TM_API( void, tmCoreFlush, ( HTELEMETRY cx ) );
  1904. TM_API( void, tmCorePause, ( HTELEMETRY cx, int const kPause ) );
  1905. TM_API( int, tmCoreIsPaused, ( HTELEMETRY cx ) );
  1906. TM_API( void, tmCoreEnter, (HTELEMETRY cx, TmU64 *matchid, TmU32 const kThreadId, TmU64 const kThreshold, TmU32 const kFlags, char const *kpLocation, TmU32 const kLine, TmU32* pFmtCode, char const *kpFmt, ... ) );
  1907. TM_API( void, tmCoreLeave, ( HTELEMETRY cx, TmU64 const kMatchID, TmU32 const kThreadId, char const *kpLocation, int const kLine ) );
  1908. TM_API( void, tmCoreEmitAccumulationZone, ( HTELEMETRY cx, TmU64 * pAccum, TmU64 const kZoneTotal, TmU32 const kCount, TmU32 const kZoneFlags, char const *kpLocation, TmU32 const kLine, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1909. TM_API( TmU64, tmCoreGetLastContextSwitchTime, (HTELEMETRY cx) );
  1910. TM_API( void, tmCoreLockName, ( HTELEMETRY cx, void const *kpPtr, TmU32* pFmtCode, char const * kpFmt, ... ) );
  1911. TM_API( void, tmCoreSetLockState, ( HTELEMETRY cx, void const *kpPtr, TmLockState const kState, char const * kLocation, TmU32 const kLine, TmU32 *pFormatCode, char const *kpFmt, ... ) );
  1912. TM_API( int, tmCoreSetLockStateMinTime, ( HTELEMETRY cx, void* buf, void const *kpPtr, TmLockState const kState, char const * kLocation, TmU32 const kLine, TmU32 *pFormatCode, char const *kpFmt, ... ) );
  1913. TM_API( void, tmCoreBeginTimeSpan, ( HTELEMETRY cx, TmU64 const kId, TmU32 const kFlags, TmU64 const kTime, char const *kpLocation, TmU32 const kLine, TmU32 *pFmtCode, char const *kpFmt, ... ) );
  1914. TM_API( void, tmCoreEndTimeSpan, ( HTELEMETRY cx, TmU64 const kId, TmU32 const kFlags, TmU64 const kTime, char const *kpLocation, TmU32 const kLine, TmU32 *pFmtCode, char const *kpFmt, ... ) );
  1915. TM_API( void, tmCoreSignalLockCount, ( HTELEMETRY cx, char const *kpLocation, TmU32 const kLine, void const * kPtr, TmU32 const kCount, TmU32* pFmtCode, char const *kpName, ... ) );
  1916. TM_API( void, tmCoreTryLock, ( HTELEMETRY cx, TmU64 *matchid, TmU64 const kThreshold, char const *kpLocation, TmU32 const kLine, void const * kPtr, TmU32* pFmtCode, char const *kpFmt, ... ) );
  1917. TM_API( void, tmCoreEndTryLock, ( HTELEMETRY cx, TmU64 const kMatchId, char const *kpLocation, int const kLine, TmU32* pFmt, void const * kPtr, TmLockResult const kResult ) );
  1918. TM_API( TmI32, tmCoreGetStati, ( HTELEMETRY cx, TmStat const kStat ) );
  1919. TM_API( void, tmCoreMessage, ( HTELEMETRY cx, TmU32 const kFlags, TmU32* pFmtCode, char const * kpFmt, ... ) );
  1920. TM_API( void, tmCoreAlloc, ( HTELEMETRY cx, void const * kPtr, TmU64 const kSize, char const *kpLocation, TmU32 const kLine, TmU32 *pFmtCode, char const *kpFmt, ... ) );
  1921. TM_API( void, tmCoreFree, ( HTELEMETRY cx, void const * kpPtr, char const *kpLocation, int const kLine, TmU32 *pFmtCode ) );
  1922. TM_API( void, tmCorePlot, ( HTELEMETRY cx, TmPlotType const kType, TmU32 const kFlags, float const kValue, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1923. TM_API( void, tmCorePlotI32, ( HTELEMETRY cx, TmPlotType const kType, TmU32 const kFlags, TmI32 const kValue, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1924. TM_API( void, tmCorePlotU32, ( HTELEMETRY cx, TmPlotType const kType, TmU32 const kFlags, TmU32 const kValue, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1925. TM_API( void, tmCorePlotI64, ( HTELEMETRY cx, TmPlotType const kType, TmU32 const kFlags, TmI64 const kValue, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1926. TM_API( void, tmCorePlotU64, ( HTELEMETRY cx, TmPlotType const kType, TmU32 const kFlags, TmU64 const kValue, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1927. TM_API( void, tmCorePlotF64, ( HTELEMETRY cx, TmPlotType const kType, TmU32 const kFlags, double const kValue, TmU32 *pFmtCode, char const * kpFmt, ... ) );
  1928. TM_API( void, tmCoreBlob, ( HTELEMETRY cx, void const * kpData, int const kDataSize, char const *kpPluginIdentifier, TmU32* pFmtCode, char const * kpFmt, ... ) );
  1929. TM_API( void, tmCoreDisjointBlob, ( HTELEMETRY cx, int const kNumPieces, void const ** kpData, int const *kDataSize, char const *kpPluginIdentifier, TmU32* pFmtCode, char const * kpFmt, ... ) );
  1930. TM_API( void, tmCoreUpdateSymbolData, ( HTELEMETRY cx ) );
  1931. TM_API( int, tmCoreSendCallStack, ( HTELEMETRY cx, TmCallStack const * kpCallStack, int const kSkip ) );
  1932. TM_API( int, tmCoreGetCallStack, ( HTELEMETRY cx, TmCallStack * pCallStack ) );
  1933. #undef TM_API
  1934. void CTM_API_STRUCT_Stub::LinkToStubs( void )
  1935. {
  1936. #if defined( TM_API_S )
  1937. #undef TM_API_S
  1938. #endif
  1939. //#define TM_API_S(name) name = GenerateStubFunction( TM_FUNCTION_TYPE(name)(NULL) );
  1940. #define TM_API_S(name) name = name##Stub;
  1941. #if ( TelemetryBuildNumber != 31 )
  1942. #error This section needs to get updated with the latest TM_API_STRUCT definitions whenever we update to a new telemetry sdk.
  1943. #endif
  1944. //======================================================================================================================
  1945. // Copy/paste the TM_API_S(*) contents of TM_API_STRUCT (from Rad's telemetry.h) here to stub out each of the functions
  1946. //======================================================================================================================
  1947. TM_API_S( tmCoreCheckVersion );
  1948. TM_API_S( tmCoreUpdateSymbolData );
  1949. TM_API_S( tmCoreGetLastContextSwitchTime );
  1950. #ifndef __RADSPU__
  1951. TM_API_S( tmCoreTick );
  1952. #endif
  1953. TM_API_S( tmCoreFlush );
  1954. TM_API_S( tmCoreDynamicString );
  1955. TM_API_S( tmCoreClearStaticString );
  1956. TM_API_S( tmCoreSetVariable );
  1957. TM_API_S( tmCoreGetFormatCode );
  1958. TM_API_S( tmCoreGetSessionName );
  1959. TM_API_S( tmCoreGetLastError );
  1960. TM_API_S( tmCoreShutdownContext );
  1961. TM_API_S( tmCoreGetConnectionStatus );
  1962. TM_API_S( tmCoreSetTimelineSectionName );
  1963. TM_API_S( tmCoreEnable );
  1964. TM_API_S( tmCoreIsEnabled );
  1965. #ifndef __RADSPU__
  1966. TM_API_S( tmCoreOpen );
  1967. #endif
  1968. TM_API_S( tmCoreClose );
  1969. TM_API_S( tmCorePause );
  1970. TM_API_S( tmCoreIsPaused );
  1971. TM_API_S( tmCoreEnter );
  1972. TM_API_S( tmCoreLeave );
  1973. TM_API_S( tmCoreThreadName );
  1974. TM_API_S( tmCoreLockName );
  1975. TM_API_S( tmCoreTryLock );
  1976. TM_API_S( tmCoreEndTryLock );
  1977. TM_API_S( tmCoreSignalLockCount );
  1978. TM_API_S( tmCoreSetLockState );
  1979. TM_API_S( tmCoreAlloc );
  1980. TM_API_S( tmCoreFree );
  1981. TM_API_S( tmCoreGetStati );
  1982. TM_API_S( tmCoreBeginTimeSpan );
  1983. TM_API_S( tmCoreEndTimeSpan );
  1984. TM_API_S( tmCorePlot );
  1985. TM_API_S( tmCorePlotI32 );
  1986. TM_API_S( tmCorePlotU32 );
  1987. TM_API_S( tmCorePlotI64 );
  1988. TM_API_S( tmCorePlotU64 );
  1989. TM_API_S( tmCorePlotF64 );
  1990. TM_API_S( tmCoreBlob );
  1991. TM_API_S( tmCoreDisjointBlob );
  1992. TM_API_S( tmCoreMessage );
  1993. TM_API_S( tmCoreSendCallStack );
  1994. TM_API_S( tmCoreGetCallStack );
  1995. TM_API_S( tmCoreSetDebugZoneLevel );
  1996. TM_API_S( tmCoreCheckDebugZoneLevel );
  1997. TM_API_S( tmCoreUnwindToDebugZoneLevel );
  1998. TM_API_S( tmCoreEmitAccumulationZone );
  1999. TM_API_S( tmCoreSetLockStateMinTime );
  2000. TM_API_S( tmCoreSetParameter );
  2001. #if defined __RADPS3__ && !defined TM_API_STATIC
  2002. TM_API_S( tmPPUCoreGetListener );
  2003. TM_API_S( tmPPUCoreRegisterSPUProgram );
  2004. #endif
  2005. #undef TM_API_S
  2006. }
  2007. #endif
  2008. #endif // RAD_TELEMETRY_ENABLED