home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2005 June (DVD) / DPPRO0605DVD.iso / dotNETSDK / SETUP.EXE / netfxsd1.cab / FL_ProfilerInfo_cpp________.3643236F_FC70_11D3_A536_0090278A1BB8 < prev    next >
Encoding:
Text File  |  2002-05-06  |  46.3 KB  |  1,871 lines

  1. /****************************************************************************************
  2.  * Copyright (c) Microsoft Corporation.  All Rights Reserved.
  3.  *
  4.  * File:
  5.  *  ProfilerInfo.cpp
  6.  *
  7.  * Description:
  8.  *    
  9.  *
  10.  *
  11.  ***************************************************************************************/
  12. #include "ProfilerInfo.h"
  13.  
  14.  
  15. /***************************************************************************************
  16.  ********************                                               ********************
  17.  ********************             BaseInfo Implementation           ********************
  18.  ********************                                               ********************
  19.  ***************************************************************************************/
  20.  
  21. /***************************************************************************************
  22.  *    Method:
  23.  *
  24.  *
  25.  *    Purpose:
  26.  *
  27.  *
  28.  *    Parameters: 
  29.  *
  30.  *
  31.  *    Return value:
  32.  *
  33.  *
  34.  *    Notes:
  35.  *
  36.  ***************************************************************************************/
  37. /* public */
  38. BaseInfo::BaseInfo( ULONG id ) : 
  39.     m_id( id ),
  40.     m_isValid( TRUE )
  41. {
  42. } // ctor                 
  43.  
  44.  
  45. /***************************************************************************************
  46.  *    Method:
  47.  *
  48.  *
  49.  *    Purpose:
  50.  *
  51.  *
  52.  *    Parameters: 
  53.  *
  54.  *
  55.  *    Return value:
  56.  *
  57.  *
  58.  *    Notes:
  59.  *
  60.  ***************************************************************************************/
  61. /* public virtual */
  62. BaseInfo::~BaseInfo()
  63. {
  64. } // dtor
  65.  
  66.  
  67. /***************************************************************************************
  68.  *    Method:
  69.  *
  70.  *
  71.  *    Purpose:
  72.  *
  73.  *
  74.  *    Parameters: 
  75.  *
  76.  *
  77.  *    Return value:
  78.  *
  79.  *
  80.  *    Notes:
  81.  *
  82.  ***************************************************************************************/
  83. /* public */
  84. BOOL BaseInfo::Compare( ULONG key )
  85. {
  86.  
  87.     return (BOOL)(m_id == key);
  88.  
  89. } // BaseInfo::Compare
  90.  
  91.  
  92. /***************************************************************************************
  93.  *    Method:
  94.  *
  95.  *
  96.  *    Purpose:
  97.  *
  98.  *
  99.  *    Parameters: 
  100.  *
  101.  *
  102.  *    Return value:
  103.  *
  104.  *
  105.  *    Notes:
  106.  *
  107.  ***************************************************************************************/
  108. /* public */
  109. Comparison BaseInfo::CompareEx( ULONG key )
  110. {
  111.     Comparison result = LESS_THAN;
  112.  
  113.  
  114.     if ( key == m_id )
  115.         result = EQUAL_TO;
  116.     
  117.     else if ( key > m_id )
  118.         result =  GREATER_THAN;
  119.  
  120.  
  121.     return result;
  122.  
  123. } // BaseInfo::CompareEx
  124.  
  125.  
  126. /***************************************************************************************
  127.  *    Method:
  128.  *
  129.  *
  130.  *    Purpose:
  131.  *
  132.  *
  133.  *    Parameters: 
  134.  *
  135.  *
  136.  *    Return value:
  137.  *
  138.  *
  139.  *    Notes:
  140.  *
  141.  ***************************************************************************************/
  142. /* public */
  143. void BaseInfo::Dump( )
  144. {
  145. } // BaseInfo::Dump
  146.  
  147.  
  148. /***************************************************************************************
  149.  ********************                                               ********************
  150.  ********************             StackBaseInfo Implementation      ********************
  151.  ********************                                               ********************
  152.  ***************************************************************************************/
  153.  
  154. /***************************************************************************************
  155.  *    Method:
  156.  *
  157.  *                
  158.  *    Purpose:
  159.  *
  160.  *
  161.  *    Parameters: 
  162.  *
  163.  *
  164.  *    Return value:
  165.  *
  166.  *
  167.  *    Notes:
  168.  *
  169.  ***************************************************************************************/
  170. /* public */
  171. StackBaseInfo::StackBaseInfo( ULONG id ) : 
  172.     m_id( id )
  173. {
  174. } // ctor                 
  175.  
  176.  
  177. /***************************************************************************************
  178.  *    Method:
  179.  *
  180.  *
  181.  *    Purpose:
  182.  *
  183.  *
  184.  *    Parameters: 
  185.  *
  186.  *
  187.  *    Return value:
  188.  *
  189.  *
  190.  *    Notes:
  191.  *
  192.  ***************************************************************************************/
  193. /* public virtual */
  194. StackBaseInfo::~StackBaseInfo()
  195. {
  196. } // dtor
  197.  
  198.  
  199. /***************************************************************************************
  200.  *    Method:
  201.  *
  202.  *
  203.  *    Purpose:
  204.  *
  205.  *
  206.  *    Parameters: 
  207.  *
  208.  *
  209.  *    Return value:
  210.  *
  211.  *
  212.  *    Notes:
  213.  *
  214.  ***************************************************************************************/
  215. /* public */
  216. StackBaseInfo *StackBaseInfo::Clone()
  217. {
  218.  
  219.     return new StackBaseInfo( m_id );
  220.     
  221. } // StackBaseInfo::Clone
  222.  
  223.  
  224. /***************************************************************************************
  225.  *    Method:
  226.  *
  227.  *
  228.  *    Purpose:
  229.  *
  230.  *
  231.  *    Parameters: 
  232.  *
  233.  *
  234.  *    Return value:
  235.  *
  236.  *
  237.  *    Notes:
  238.  *
  239.  ***************************************************************************************/
  240. /* public */
  241. void StackBaseInfo::Dump()
  242. {    
  243. } // StackBaseInfo::Dump
  244.  
  245.  
  246. /***************************************************************************************
  247.  ********************                                               ********************
  248.  ********************         StackFunctionInfo Implementation      ********************
  249.  ********************                                               ********************
  250.  ***************************************************************************************/
  251.  
  252. /***************************************************************************************
  253.  *    Method:
  254.  *
  255.  *
  256.  *    Purpose:
  257.  *
  258.  *
  259.  *    Parameters: 
  260.  *
  261.  *
  262.  *    Return value:
  263.  *
  264.  *
  265.  *    Notes:
  266.  *
  267.  ***************************************************************************************/
  268. /* public */
  269. StackFunctionInfo::StackFunctionInfo() 
  270. {
  271.     //
  272.     // Initialize the timers
  273.     //
  274.     m_calleeTime.QuadPart = 0;
  275.     m_profilerTime.QuadPart = 0;
  276.     m_inclusiveTime.QuadPart = 0;
  277.     m_suspendedTime.QuadPart = 0;
  278.     m_currentInclusiveTime.QuadPart = 0;
  279.     
  280. } // ctor                 
  281.  
  282. /***************************************************************************************
  283.  *    Method:
  284.  *
  285.  *
  286.  *    Purpose:
  287.  *
  288.  *
  289.  *    Parameters: 
  290.  *
  291.  *
  292.  *    Return value:
  293.  *
  294.  *
  295.  *    Notes:
  296.  *
  297.  ***************************************************************************************/
  298. /* public virtual */
  299. StackFunctionInfo::~StackFunctionInfo()
  300. {
  301. } // dtor
  302.  
  303.  
  304. /***************************************************************************************
  305.  *    Method:
  306.  *
  307.  *
  308.  *    Purpose:
  309.  *
  310.  *
  311.  *    Parameters: 
  312.  *
  313.  *
  314.  *    Return value:
  315.  *
  316.  *
  317.  *    Notes:
  318.  *
  319.  ***************************************************************************************/
  320. /* public */
  321. StackFunctionInfo *StackFunctionInfo::Clone()
  322. {
  323.     StackFunctionInfo *pFunctionInfo;
  324.     
  325.     
  326.        pFunctionInfo = new StackFunctionInfo();
  327.     if ( pFunctionInfo != NULL )
  328.     {
  329.         pFunctionInfo->m_calleeTime.QuadPart = m_calleeTime.QuadPart;
  330.         pFunctionInfo->m_profilerTime.QuadPart = m_profilerTime.QuadPart;
  331.         pFunctionInfo->m_suspendedTime.QuadPart = m_suspendedTime.QuadPart;
  332.         pFunctionInfo->m_inclusiveTime.QuadPart = m_inclusiveTime.QuadPart;
  333.         pFunctionInfo->m_currentInclusiveTime.QuadPart = m_currentInclusiveTime.QuadPart;
  334.       }
  335.  
  336.  
  337.     return pFunctionInfo;
  338.  
  339. } // StackFunctionInfo::Clone
  340.  
  341.  
  342. /***************************************************************************************
  343.  *    Method:
  344.  *
  345.  *
  346.  *    Purpose:
  347.  *
  348.  *
  349.  *    Parameters: 
  350.  *
  351.  *
  352.  *    Return value:
  353.  *
  354.  *
  355.  *    Notes:
  356.  *
  357.  ***************************************************************************************/
  358. /* public */
  359. void StackFunctionInfo::Dump()
  360. {
  361. } // StackFunctionInfo::Dump
  362.  
  363.  
  364. /***************************************************************************************
  365.  ********************                                               ********************
  366.  ********************        FunctionTimingInfo Implementation      ********************
  367.  ********************                                               ********************
  368.  ***************************************************************************************/
  369.  
  370. /***************************************************************************************
  371.  *    Method:
  372.  *
  373.  *
  374.  *    Purpose:
  375.  *
  376.  *
  377.  *    Parameters: 
  378.  *
  379.  *
  380.  *    Return value:
  381.  *
  382.  *
  383.  *    Notes:
  384.  *
  385.  ***************************************************************************************/
  386. /* public */
  387. FunctionTimingInfo::FunctionTimingInfo( ULONG id, DWORD win32ThreadID ) : 
  388.     BaseInfo( id ),
  389.     m_timesCalled( 0 ),
  390.     m_pLatestInvocation( NULL ),
  391.     m_win32ThreadID( win32ThreadID )
  392. {
  393.     //
  394.     // Initialize the timers
  395.     //
  396.     m_calleeTime.QuadPart = 0;
  397.     m_profilerTime.QuadPart = 0;
  398.     m_suspendedTime.QuadPart = 0;
  399.     m_inclusiveTime.QuadPart = 0;
  400.  
  401.     //
  402.     // Initialize stack of invocated functions
  403.     //
  404.     m_pLatestInvocation = new CStack<StackFunctionInfo *>();
  405.  
  406. } // ctor                 
  407.  
  408.  
  409. /***************************************************************************************
  410.  *    Method:
  411.  *
  412.  *
  413.  *    Purpose:
  414.  *
  415.  *
  416.  *    Parameters: 
  417.  *
  418.  *
  419.  *    Return value:
  420.  *
  421.  *
  422.  *    Notes:
  423.  *
  424.  ***************************************************************************************/
  425. /* public virtual */
  426. FunctionTimingInfo::~FunctionTimingInfo()
  427. {
  428.     if ( m_pLatestInvocation != NULL )
  429.     {
  430.         delete m_pLatestInvocation; 
  431.         m_pLatestInvocation = NULL;
  432.     }
  433.  
  434. } // dtor
  435.  
  436.  
  437. /***************************************************************************************
  438.  *    Method:
  439.  *
  440.  *
  441.  *    Purpose:
  442.  *
  443.  *
  444.  *    Parameters: 
  445.  *
  446.  *
  447.  *    Return value:
  448.  *
  449.  *
  450.  *    Notes:
  451.  *
  452.  ***************************************************************************************/
  453. /* virtual public */
  454. void FunctionTimingInfo::Dump()
  455. {         
  456.     HRESULT    hr;
  457.     FunctionInfo *pFunctionInfo = NULL;
  458.     
  459.     
  460.     pFunctionInfo = (g_pPrfInfo->m_pFunctionTable)->Lookup( m_id );
  461.     if ( pFunctionInfo != NULL )
  462.     {
  463.         // 
  464.         // The intention is to dump the data into a semi-colon delimited list. The
  465.         // data can then be imported into a spreadsheet and then analysed. The format
  466.         // is essentially comprised of 
  467.         //
  468.         //        thread ID
  469.         //      function name and parameters
  470.         //      times called
  471.         //      exclusive time
  472.         //      inclusive time
  473.         //      callee time
  474.         //         suspended time
  475.         //      profiler time
  476.         //
  477.         
  478.         //
  479.         // Dump thread ID, return type, function name, and function 
  480.         // parameters; note, function parameters are separated by a 
  481.         // '+' sign.
  482.         //
  483.         LOG_TO_FILE( ("0x%08x;", m_win32ThreadID) )        
  484.         if ( pFunctionInfo->m_bIsStatic == TRUE )
  485.             LOG_TO_FILE( ("static ") )
  486.  
  487.  
  488.         if ( pFunctionInfo->m_returnTypeStr[0] != NULL )
  489.             LOG_TO_FILE( ("%S ", pFunctionInfo->m_returnTypeStr) )                        
  490.             
  491.             
  492.        if ( pFunctionInfo->m_functionName[0] != NULL )
  493.             LOG_TO_FILE( ("%S(", pFunctionInfo->m_functionName) )
  494.             
  495.             
  496.         if ( pFunctionInfo->m_argCount > 0 )            
  497.         {
  498.             WCHAR *parameter;
  499.             WCHAR *separator = L"+";
  500.  
  501.  
  502.             //
  503.             // Parse and dump parameters
  504.             //    
  505.             parameter = wcstok( pFunctionInfo->m_functionParameters, separator );
  506.                while ( parameter != NULL )
  507.                {
  508.                  LOG_TO_FILE( (" %S", parameter) )               
  509.                   parameter = wcstok( NULL, separator );
  510.                 if ( parameter != NULL )
  511.                     LOG_TO_FILE( (",") )
  512.                     
  513.               } // while                               
  514.         }
  515.         LOG_TO_FILE( (" );") )
  516.         
  517.         
  518.         //
  519.         // Dump statistics
  520.         //
  521.         double exclusiveTime;
  522.         
  523.         
  524.         // to compute exclusive time for the function we subtract the callee time, 
  525.         // suspended time, and profiler time from the inclusive time
  526.         exclusiveTime = ( ((double)m_inclusiveTime.QuadPart / (double)g_frequency.QuadPart) -                
  527.                             ( ((double)m_calleeTime.QuadPart / (double)g_frequency.QuadPart)    +
  528.                               ((double)m_suspendedTime.QuadPart / (double)g_frequency.QuadPart) +
  529.                               ((double)m_profilerTime.QuadPart / (double)g_frequency.QuadPart) ) );
  530.                         
  531.         LOG_TO_FILE( ("%d;%f;%f;%f;%f;%f\n", 
  532.                        m_timesCalled,
  533.                        exclusiveTime,
  534.                        ((double)m_inclusiveTime.QuadPart / (double)g_frequency.QuadPart),
  535.                        ((double)m_calleeTime.QuadPart / (double)g_frequency.QuadPart),
  536.                        ((double)m_suspendedTime.QuadPart / (double)g_frequency.QuadPart),
  537.                        ((double)m_profilerTime.QuadPart / (double)g_frequency.QuadPart)) )
  538.     }
  539.     else
  540.         LOG_TO_FILE( ("Unable to Retreive Information about the Function Name, Parameters and Return Type\n") )    
  541.  
  542. } // FunctionTimingInfo::Dump
  543.  
  544.  
  545. /***************************************************************************************
  546.  ********************                                               ********************
  547.  ********************            ThreadInfo Implementation          ********************
  548.  ********************                                               ********************
  549.  ***************************************************************************************/
  550.  
  551. /***************************************************************************************
  552.  *    Method:
  553.  *
  554.  *
  555.  *    Purpose:
  556.  *
  557.  *
  558.  *    Parameters: 
  559.  *
  560.  *
  561.  *    Return value:
  562.  *
  563.  *
  564.  *    Notes:
  565.  *
  566.  ***************************************************************************************/
  567. /* public */
  568. ThreadInfo::ThreadInfo( ThreadID threadID ) : 
  569.     BaseInfo( threadID ),        
  570.     m_hThread( NULL ), 
  571.     m_win32ThreadID( 0 ),
  572.     m_pCallStack( NULL ),
  573.     m_pFunctionTimes( NULL ),    
  574.     m_originalTID( threadID ),
  575.     m_lastPoppedFID( 0xFFFFFFFF ),
  576.     m_pLatestUnwoundFunction( NULL )
  577. {
  578.     //
  579.     // Initialize the timers
  580.     //
  581.     m_runningTime.QuadPart = 0;
  582.       m_profilerTime.QuadPart = 0;
  583.     m_suspendedTime.QuadPart = 0;
  584.     m_currentProfilerTime.QuadPart = 0;
  585.     m_currentSuspensionTime.QuadPart = 0; 
  586.  
  587.     //
  588.     // Initialize the stacks and tables
  589.     //
  590.     m_pCallStack = new CStack<StackBaseInfo *>();
  591.        m_pLatestUnwoundFunction = new CStack<StackBaseInfo *>();
  592.     m_pFunctionTimes = new Table<FunctionTimingInfo *, FunctionID>();
  593.  
  594. } // ctor                 
  595.  
  596.  
  597. /***************************************************************************************
  598.  *    Method:
  599.  *
  600.  *
  601.  *    Purpose:
  602.  *
  603.  *
  604.  *    Parameters: 
  605.  *
  606.  *
  607.  *    Return value:
  608.  *
  609.  *
  610.  *    Notes:
  611.  *
  612.  ***************************************************************************************/
  613. /* public virtual */
  614. ThreadInfo::~ThreadInfo()
  615. {
  616.     if ( m_pCallStack != NULL )
  617.     {
  618.         delete m_pCallStack; 
  619.         m_pCallStack = NULL;
  620.     }
  621.  
  622.     if ( m_pLatestUnwoundFunction != NULL )
  623.     {
  624.         delete m_pLatestUnwoundFunction; 
  625.         m_pLatestUnwoundFunction = NULL;
  626.     }
  627.  
  628.     if ( m_pFunctionTimes != NULL )
  629.     {
  630.         delete m_pFunctionTimes; 
  631.         m_pFunctionTimes = NULL;
  632.     }
  633.     
  634. } // dtor
  635.         
  636.  
  637. /***************************************************************************************
  638.  *    Method:
  639.  *
  640.  *
  641.  *    Purpose:
  642.  *
  643.  *
  644.  *    Parameters: 
  645.  *
  646.  *
  647.  *    Return value:
  648.  *
  649.  *
  650.  *    Notes:
  651.  *
  652.  ***************************************************************************************/
  653. /* public */
  654. void ThreadInfo::Dump()
  655. {    
  656.     //
  657.     // The EE is silently turning off the profiling events after the 
  658.     // shutdown callback. This behavior causes the profiler not to 
  659.     // receive any ThreadDestroyed or RuntimeThreadResumed events for 
  660.     // certain threads. To ensure that we get the best possible timings, 
  661.     // we need to update the counters (timers) assuming that the Shutdown 
  662.     // callback is made at the same time that both the RuntimethreadResumed 
  663.     // and ThreadDestroyed callbacks are made.
  664.     //
  665.     // Notice that we do not attemp to update the counters of the functions 
  666.     // in the current thread's callstack. The reason for this is to ensure 
  667.     // that that there are no frames in the callstack when the thread goes 
  668.     // away.
  669.     //
  670.     if ( m_isValid == TRUE )
  671.         UpdateTimer( NULL, &m_runningTime, STOP );
  672.     
  673.     
  674.     if ( m_currentSuspensionTime.QuadPart != 0 )
  675.         UpdateTimer( &m_suspendedTime, &m_currentSuspensionTime, STOP );
  676.  
  677.  
  678.     //
  679.     // Print out information
  680.     //    
  681.     m_pFunctionTimes->Dump();
  682.     LOG_TO_FILE( ("\n\n") )    
  683.  
  684. } // ThreadInfo::Dump
  685.  
  686.  
  687. /***************************************************************************************
  688.  *    Method:
  689.  *
  690.  *
  691.  *    Purpose:
  692.  *
  693.  *
  694.  *    Parameters: 
  695.  *
  696.  *
  697.  *    Return value:
  698.  *
  699.  *
  700.  *    Notes:
  701.  *
  702.  ***************************************************************************************/
  703. /* public */
  704. void ThreadInfo::UpdateTimer( LARGE_INTEGER *globalTimer, 
  705.                               LARGE_INTEGER *currentTimer, 
  706.                               CounterAction action )
  707. {    
  708.     //
  709.     // This function is multi-purpose:
  710.     //
  711.     //        if action == START, capture and return the current value of the timer. 
  712.     //        if action == STOP,  capture the current value of the timer, subtract 
  713.     //                            it from the value of currentTimer and return the 
  714.     //                            difference; it also accumulates the difference in 
  715.     //                            globalTimer.
  716.     //
  717.     switch ( action )
  718.     {
  719.         case START:
  720.             QueryPerformanceCounter( currentTimer );
  721.             break;
  722.         
  723.         
  724.         case STOP:
  725.             {
  726.                 LARGE_INTEGER endTime;
  727.                 
  728.  
  729.                 endTime.QuadPart = 0;
  730.                 QueryPerformanceCounter( &endTime );                
  731.                 (*currentTimer).QuadPart = (endTime.QuadPart - (*currentTimer).QuadPart);
  732.                 
  733.                 if ( globalTimer != NULL )
  734.                     (*globalTimer).QuadPart += (*currentTimer).QuadPart;
  735.             }
  736.             break;
  737.     
  738.     } // switch
  739.  
  740. } // ThreadInfo::UpdateTimer
  741.  
  742.  
  743. /***************************************************************************************
  744.  *    Method:
  745.  *
  746.  *
  747.  *    Purpose:
  748.  *
  749.  *
  750.  *    Parameters: 
  751.  *
  752.  *
  753.  *    Return value:
  754.  *
  755.  *
  756.  *    Notes:
  757.  *
  758.  ***************************************************************************************/
  759. /* public */
  760. void ThreadInfo::GetStackFunctionInfo( StackFunctionInfo **pFunctionInfo )
  761. {    
  762.     StackBaseInfo *pStackTop;
  763.  
  764.  
  765.     //
  766.     // For every managed thread that gets created during the profiling process, 
  767.     // the profiler creates an entry to the thread table. Every entry in the 
  768.     // thread table contains a list of functions that the managed thread has 
  769.     // invoked during its life. Every entry of that list contains some counters 
  770.     // for that function and a stack to track the counters from the last invocation 
  771.     // of that specific function. This is done to handle recursive or multiple 
  772.     // calls of the function. The maximum depth of that stack is equal to the 
  773.     // maximum recursive depth that was encountered for the specific function, 
  774.     // on the specific thread.  
  775.     //    
  776.     *pFunctionInfo = NULL;
  777.     pStackTop = m_pCallStack->Top();
  778.     if ( pStackTop != NULL )
  779.     {
  780.         FunctionTimingInfo *pCurrentFunction;
  781.         
  782.         
  783.         pCurrentFunction = m_pFunctionTimes->Lookup( pStackTop->m_id );    
  784.         if ( pCurrentFunction != NULL )
  785.             *pFunctionInfo = (pCurrentFunction->m_pLatestInvocation)->Top();
  786.     }
  787.  
  788. } // ThreadInfo::GetStackFunctionInfo
  789.  
  790.  
  791. /***************************************************************************************
  792.  ********************                                               ********************
  793.  ********************          FunctionInfo Implementation          ********************
  794.  ********************                                               ********************
  795.  ***************************************************************************************/
  796.  
  797. /***************************************************************************************
  798.  *    Method:
  799.  *
  800.  *
  801.  *    Purpose:
  802.  *
  803.  *
  804.  *    Parameters: 
  805.  *
  806.  *
  807.  *    Return value:
  808.  *
  809.  *
  810.  *    Notes:
  811.  *
  812.  ***************************************************************************************/
  813. /* public */
  814. FunctionInfo::FunctionInfo( FunctionID functionID ) : 
  815.     BaseInfo( functionID ),        
  816.     m_argCount( 0 ),
  817.     m_bIsStatic( FALSE )
  818. {
  819.        wcscpy( m_functionName, L"unknown" );
  820.        wcscpy( m_returnTypeStr, L"void" );
  821.     wcscpy( m_functionParameters, L"void" );
  822. } // ctor                 
  823.  
  824.  
  825. /***************************************************************************************
  826.  *    Method:
  827.  *
  828.  *
  829.  *    Purpose:
  830.  *
  831.  *
  832.  *    Parameters: 
  833.  *
  834.  *
  835.  *    Return value:
  836.  *
  837.  *
  838.  *    Notes:
  839.  *
  840.  ***************************************************************************************/
  841. /* public virtual */
  842. FunctionInfo::~FunctionInfo()
  843. {  
  844. } // dtor
  845.         
  846.  
  847. /***************************************************************************************
  848.  *    Method:
  849.  *
  850.  *
  851.  *    Purpose:
  852.  *
  853.  *
  854.  *    Parameters: 
  855.  *
  856.  *
  857.  *    Return value:
  858.  *
  859.  *
  860.  *    Notes:
  861.  *
  862.  ***************************************************************************************/
  863. /* public */
  864. void FunctionInfo::Dump()
  865. {               
  866.  
  867. } // FunctionInfo::Dump
  868.  
  869.  
  870. /***************************************************************************************
  871.  ********************                                               ********************
  872.  ********************              PrfInfo Implementation           ********************
  873.  ********************                                               ********************
  874.  ***************************************************************************************/
  875.  
  876. /***************************************************************************************
  877.  *    Method:
  878.  *
  879.  *
  880.  *    Purpose:
  881.  *
  882.  *
  883.  *    Parameters: 
  884.  *
  885.  *
  886.  *    Return value:
  887.  *
  888.  *
  889.  *    Notes:
  890.  *
  891.  ***************************************************************************************/
  892. /* public */
  893. PrfInfo::PrfInfo() :         
  894.     m_dwEventMask( 0 ),
  895.     m_pThreadTable( NULL ),
  896.     m_pProfilerInfo( NULL ),
  897.     m_bHighPrecisionSupported( FALSE )    
  898. {
  899.     //
  900.     // Initialize critical section and thread table
  901.     //
  902.     m_pThreadTable = new SList<ThreadInfo *, ThreadID>();
  903.     m_pFunctionTable = new Table<FunctionInfo *, FunctionID>();    
  904.     
  905.     //
  906.     // Determine if high precision counters are supported
  907.     //
  908.     g_frequency.QuadPart = 0;
  909.     m_bHighPrecisionSupported = QueryPerformanceFrequency( &g_frequency );    
  910.  
  911.     //
  912.     // Initialize global PrfInfo pointer
  913.     //
  914.     g_pPrfInfo = this;
  915.  
  916. } // ctor
  917.  
  918.  
  919. /***************************************************************************************
  920.  *    Method:
  921.  *
  922.  *
  923.  *    Purpose:
  924.  *
  925.  *
  926.  *    Parameters: 
  927.  *
  928.  *
  929.  *    Return value:
  930.  *
  931.  *
  932.  *    Notes:
  933.  *
  934.  ***************************************************************************************/
  935. /* virtual public */
  936. PrfInfo::~PrfInfo()
  937. {
  938.     if ( m_pProfilerInfo != NULL )
  939.     {
  940.         m_pProfilerInfo->Release();
  941.         m_pProfilerInfo = NULL;
  942.     }
  943.  
  944.     if ( m_pThreadTable != NULL )
  945.     {    
  946.         delete m_pThreadTable;
  947.         m_pThreadTable = NULL;
  948.     }
  949.     
  950.     if ( m_pFunctionTable != NULL )
  951.     {    
  952.         delete m_pFunctionTable;
  953.         m_pFunctionTable = NULL;
  954.     }
  955.  
  956.     g_pPrfInfo = NULL;
  957.  
  958. } // dtor                  
  959.  
  960.  
  961. /***************************************************************************************
  962.  *    Method:
  963.  *
  964.  *
  965.  *    Purpose:
  966.  *
  967.  *
  968.  *    Parameters: 
  969.  *
  970.  *
  971.  *    Return value:
  972.  *
  973.  *
  974.  *    Notes:
  975.  *
  976.  ***************************************************************************************/
  977. /* public */
  978. /* throws BaseException */
  979. void PrfInfo::AddThread( ThreadID threadID )
  980. {    
  981.     ThreadInfo *pThreadInfo;
  982.     LARGE_INTEGER localTimer;
  983.     
  984.       
  985.     //
  986.     // For accuracy reasons, this function starts the profiler 
  987.     // timer as well for the ThreadCreated callback
  988.     //  
  989.     localTimer.QuadPart = 0;
  990.     QueryPerformanceCounter( &localTimer );
  991.     pThreadInfo = new ThreadInfo( threadID );
  992.     if ( pThreadInfo != NULL )
  993.       {
  994.         try
  995.         {
  996.             _GetThreadInfoHelper( &pThreadInfo );
  997.             m_pThreadTable->AddEntry( pThreadInfo, threadID );
  998.             (pThreadInfo->m_runningTime).QuadPart = localTimer.QuadPart;
  999.             (pThreadInfo->m_currentProfilerTime).QuadPart = localTimer.QuadPart;
  1000.             
  1001.             QueryPerformanceCounter( &localTimer );
  1002.             (pThreadInfo->m_profilerTime).QuadPart += localTimer.QuadPart - (pThreadInfo->m_currentProfilerTime).QuadPart;
  1003.             (pThreadInfo->m_currentProfilerTime).QuadPart = 0;
  1004.            }
  1005.         catch ( BaseException *exception )
  1006.         {
  1007.             delete pThreadInfo;
  1008.             throw;                 
  1009.          }                    
  1010.     }
  1011.     else
  1012.         _THROW_EXCEPTION( "Allocation for ThreadInfo Object FAILED" )
  1013.                 
  1014. } // PrfInfo::AddThread
  1015.  
  1016.  
  1017. /***************************************************************************************
  1018.  *    Method:
  1019.  *
  1020.  *
  1021.  *    Purpose:
  1022.  *
  1023.  *
  1024.  *    Parameters: 
  1025.  *
  1026.  *
  1027.  *    Return value:
  1028.  *
  1029.  *
  1030.  *    Notes:
  1031.  *
  1032.  ***************************************************************************************/
  1033. /* public */
  1034. /* throws BaseException */
  1035. void PrfInfo::RemoveThread( ThreadID threadID )
  1036. {    
  1037.     if ( threadID != NULL )
  1038.       {
  1039.         ThreadInfo *pThreadInfo;
  1040.  
  1041.         
  1042.         pThreadInfo = m_pThreadTable->Lookup( threadID );
  1043.         if ( pThreadInfo != NULL )
  1044.         {
  1045.             _ASSERT_( pThreadInfo->m_isValid == TRUE );
  1046.             pThreadInfo->m_id = 0xbadf00d;
  1047.             pThreadInfo->m_isValid = FALSE;
  1048.             pThreadInfo->UpdateTimer( NULL, &(pThreadInfo->m_runningTime), STOP );
  1049.             
  1050.             //
  1051.             // Update the profiler timer for the thread that dies
  1052.             // and reset the m_currentProfilerTime
  1053.             //
  1054.             pThreadInfo->UpdateTimer( &(pThreadInfo->m_profilerTime), &(pThreadInfo->m_currentProfilerTime), STOP );
  1055.             (pThreadInfo->m_currentProfilerTime).QuadPart = 0;
  1056.         }
  1057.         else
  1058.             _THROW_EXCEPTION( "Thread was NOT Found in the Thread Table" )
  1059.     }
  1060.     else
  1061.         _THROW_EXCEPTION( "ThreadID is NULL" )
  1062.                         
  1063. } // PrfInfo::RemoveThread
  1064.  
  1065.  
  1066. /***************************************************************************************
  1067.  *    Method:
  1068.  *
  1069.  *
  1070.  *    Purpose:
  1071.  *
  1072.  *
  1073.  *    Parameters: 
  1074.  *
  1075.  *
  1076.  *    Return value:
  1077.  *
  1078.  *
  1079.  *    Notes:
  1080.  *
  1081.  ***************************************************************************************/
  1082. /* public */
  1083. /* throws BaseException */
  1084. void PrfInfo::AddFunction( FunctionID functionID )
  1085. {    
  1086.     FunctionInfo *pFunctionInfo;
  1087.     
  1088.  
  1089.     pFunctionInfo = new FunctionInfo( functionID );
  1090.     if ( pFunctionInfo != NULL )
  1091.       {
  1092.         try
  1093.         {
  1094.             _GetFunctionInfoHelper( &pFunctionInfo );
  1095.             m_pFunctionTable->AddEntry( pFunctionInfo, functionID );
  1096.            }
  1097.         catch ( BaseException *exception )
  1098.         {
  1099.             delete pFunctionInfo;
  1100.             throw;                 
  1101.          }                    
  1102.     }
  1103.     else
  1104.         _THROW_EXCEPTION( "Allocation for FunctionInfo Object FAILED" )
  1105.  
  1106.  
  1107. } // PrfInfo::AddFunction
  1108.  
  1109.  
  1110. /***************************************************************************************
  1111.  *    Method:
  1112.  *
  1113.  *
  1114.  *    Purpose:
  1115.  *
  1116.  *
  1117.  *    Parameters: 
  1118.  *
  1119.  *
  1120.  *    Return value:
  1121.  *
  1122.  *
  1123.  *    Notes:
  1124.  *
  1125.  ***************************************************************************************/
  1126. /* public */
  1127. /* throws BaseException */
  1128. void PrfInfo::RemoveFunction( FunctionID functionID )
  1129. {    
  1130.     if ( functionID != NULL )
  1131.       {
  1132.         FunctionInfo *pFunctionInfo;
  1133.  
  1134.         
  1135.         pFunctionInfo = m_pFunctionTable->Lookup( functionID );
  1136.         if ( pFunctionInfo != NULL )
  1137.         {
  1138.             _ASSERT_( pFunctionInfo->m_isValid == TRUE );
  1139.             pFunctionInfo->m_id = 0xbadf00d;
  1140.             pFunctionInfo->m_isValid = FALSE;
  1141.         }
  1142.         else
  1143.             _THROW_EXCEPTION( "Function was NOT Found in the Function Table" )
  1144.     }
  1145.     else
  1146.         _THROW_EXCEPTION( "FunctionID is NULL" )
  1147.                         
  1148. } // PrfInfo::RemoveFunction
  1149.  
  1150.  
  1151. /***************************************************************************************
  1152.  *    Method:
  1153.  *
  1154.  *
  1155.  *    Purpose:
  1156.  *
  1157.  *
  1158.  *    Parameters: 
  1159.  *
  1160.  *
  1161.  *    Return value:
  1162.  *
  1163.  *
  1164.  *    Notes:
  1165.  *
  1166.  ***************************************************************************************/
  1167. /* public */
  1168. /* throws BaseException */
  1169. void PrfInfo::UpdateSuspendedTimer( ThreadID threadID, CounterAction action )
  1170. {    
  1171.     if ( threadID != NULL )
  1172.       {
  1173.         ThreadInfo *pThreadInfo;
  1174.  
  1175.         
  1176.         pThreadInfo = m_pThreadTable->Lookup( threadID );
  1177.         if ( pThreadInfo != NULL )
  1178.         {
  1179.             _ASSERT_( pThreadInfo->m_isValid == TRUE );
  1180.             switch ( action )
  1181.             {
  1182.                 case START:
  1183.                     pThreadInfo->UpdateTimer( NULL, &(pThreadInfo->m_currentSuspensionTime), START );
  1184.                     break;
  1185.  
  1186.  
  1187.                 case STOP:
  1188.                     {
  1189.                         //
  1190.                         // Lookup and update the suspend time for the function in the top of the stack
  1191.                         //
  1192.                         StackFunctionInfo *pFunctionInfo = NULL;
  1193.  
  1194.  
  1195.                         pThreadInfo->UpdateTimer( &(pThreadInfo->m_suspendedTime),
  1196.                                                     &(pThreadInfo->m_currentSuspensionTime),
  1197.                                                     STOP );
  1198.                         
  1199.                         pThreadInfo->GetStackFunctionInfo( &pFunctionInfo );
  1200.                         if ( pFunctionInfo != NULL )
  1201.                             (pFunctionInfo->m_suspendedTime).QuadPart += (pThreadInfo->m_currentSuspensionTime).QuadPart;
  1202.  
  1203.  
  1204.                         (pThreadInfo->m_currentSuspensionTime).QuadPart = 0; 
  1205.                     }
  1206.                     break;
  1207.         
  1208.             } // switch
  1209.         }
  1210.         else
  1211.             _THROW_EXCEPTION( "Thread was NOT Found in the Thread Table" )
  1212.     }
  1213.     else
  1214.         _THROW_EXCEPTION( "ThreadID is NULL" )
  1215.         
  1216. } // PrfInfo::UpdateSuspendedTimer
  1217.  
  1218.  
  1219. /***************************************************************************************
  1220.  *    Method:
  1221.  *
  1222.  *
  1223.  *    Purpose:
  1224.  *
  1225.  *
  1226.  *    Parameters: 
  1227.  *
  1228.  *
  1229.  *    Return value:
  1230.  *
  1231.  *
  1232.  *    Notes:
  1233.  *
  1234.  ***************************************************************************************/
  1235. /* public */
  1236. /* throws BaseException */
  1237. void PrfInfo::UpdateOSThreadID( ThreadID managedThreadID, DWORD win32ThreadID )
  1238. {
  1239.     if ( managedThreadID != NULL )
  1240.       {
  1241.           ThreadInfo *pThreadInfo;
  1242.  
  1243.         
  1244.         pThreadInfo = m_pThreadTable->Lookup( managedThreadID );
  1245.         if ( pThreadInfo != NULL )
  1246.         {
  1247.             _ASSERT_( pThreadInfo->m_isValid == TRUE );
  1248.             pThreadInfo->m_win32ThreadID = win32ThreadID;
  1249.         }
  1250.         else
  1251.             _THROW_EXCEPTION( "Thread was NOT Found in the Thread Table" )
  1252.     }
  1253.     else
  1254.         _THROW_EXCEPTION( "ThreadID is NULL" )          
  1255.           
  1256. } // PrfInfo::UpdateOSThreadID
  1257.  
  1258.  
  1259. /***************************************************************************************
  1260.  *    Method:
  1261.  *
  1262.  *
  1263.  *    Purpose:
  1264.  *
  1265.  *
  1266.  *    Parameters: 
  1267.  *
  1268.  *
  1269.  *    Return value:
  1270.  *
  1271.  *
  1272.  *    Notes:
  1273.  *
  1274.  ***************************************************************************************/
  1275. /* public */
  1276. /* throws BaseException */
  1277. void PrfInfo::UpdateUnwindStack( FunctionID *functionID, StackAction action )
  1278. {
  1279.     HRESULT hr;
  1280.     ThreadID threadID;
  1281.  
  1282.  
  1283.     hr = m_pProfilerInfo->GetCurrentThreadID( &threadID );
  1284.     if ( SUCCEEDED( hr ) )
  1285.     {
  1286.         ThreadInfo *pThreadInfo;
  1287.         
  1288.  
  1289.         pThreadInfo =  m_pThreadTable->Lookup( threadID );
  1290.         if ( pThreadInfo != NULL )
  1291.         {
  1292.             StackBaseInfo *stackElement = NULL;
  1293.             
  1294.  
  1295.             _ASSERT_( pThreadInfo->m_isValid == TRUE );
  1296.             switch ( action )
  1297.             {
  1298.                 case PUSH:
  1299.                     {
  1300.                         stackElement = new StackBaseInfo( *functionID );
  1301.                         if ( stackElement != NULL )
  1302.                             (pThreadInfo->m_pLatestUnwoundFunction)->Push( stackElement );
  1303.                             
  1304.                           else
  1305.                             _THROW_EXCEPTION( "Allocation for Stack Element FAILED" )
  1306.                     }
  1307.                     break;
  1308.  
  1309.  
  1310.                 case POP:
  1311.                     {
  1312.                         stackElement = (pThreadInfo->m_pLatestUnwoundFunction)->Pop();
  1313.                         if ( stackElement != NULL )
  1314.                         {
  1315.                             *functionID = stackElement->m_id;
  1316.                             delete stackElement;
  1317.                         }
  1318.                         else
  1319.                             _THROW_EXCEPTION( "Stack Contains Bad Data" )
  1320.                     }
  1321.                     break;
  1322.  
  1323.             } // switch
  1324.         }
  1325.         else                 
  1326.             _THROW_EXCEPTION( "Thread Structure was not found in the thread list" )
  1327.     }
  1328.     else
  1329.         _THROW_EXCEPTION( "ICorProfilerInfo::GetCurrentThreadID() FAILED" )
  1330.     
  1331. } // PrfInfo::UpdateUnwindStack
  1332.  
  1333.  
  1334. /***************************************************************************************
  1335.  *    Method:
  1336.  *
  1337.  *
  1338.  *    Purpose:
  1339.  *
  1340.  *
  1341.  *    Parameters: 
  1342.  *
  1343.  *
  1344.  *    Return value:
  1345.  *
  1346.  *
  1347.  *    Notes:
  1348.  *
  1349.  ***************************************************************************************/
  1350. /* public */
  1351. /* throws BaseException */
  1352. void PrfInfo::UpdateCallStack( FunctionID functionID, StackAction action )
  1353. {
  1354.     HRESULT hr;
  1355.     ThreadID threadID;
  1356.  
  1357.  
  1358.     hr = m_pProfilerInfo->GetCurrentThreadID( &threadID );
  1359.     if ( SUCCEEDED( hr ) )
  1360.     {
  1361.         ThreadInfo *pThreadInfo;
  1362.         
  1363.         
  1364.         pThreadInfo = m_pThreadTable->Lookup( threadID );
  1365.         if ( pThreadInfo != NULL )
  1366.         {
  1367.             StackBaseInfo *stackElement = NULL;
  1368.             
  1369.  
  1370.             switch ( action )
  1371.             {
  1372.                 case PUSH:
  1373.                     {
  1374.                         //
  1375.                         // Push the element in the callstack of the specific thread
  1376.                         //
  1377.                         stackElement = new StackBaseInfo( functionID );
  1378.                         if ( stackElement != NULL )
  1379.                             (pThreadInfo->m_pCallStack)->Push( stackElement );
  1380.  
  1381.                         else
  1382.                             _THROW_EXCEPTION( "Allocation for StackBaseInfo FAILED" )
  1383.  
  1384.  
  1385.                         //
  1386.                         // Add the functionID to the table of function that this thread invoked
  1387.                         // if it does not already exist there
  1388.                         //
  1389.                         FunctionTimingInfo *pFunction;
  1390.                         
  1391.                         
  1392.                         pFunction = (pThreadInfo->m_pFunctionTimes)->Lookup( functionID );
  1393.                         if ( pFunction == NULL )
  1394.                         {
  1395.                             //
  1396.                             // The thread executes this method for the fisrt time
  1397.                             //
  1398.                             pFunction = new FunctionTimingInfo( functionID, pThreadInfo->m_win32ThreadID );
  1399.                             if ( pFunction == NULL )
  1400.                                 _THROW_EXCEPTION( "Allocation for FunctionTimingInfo FAILED" )
  1401.  
  1402.  
  1403.                             (pThreadInfo->m_pFunctionTimes)->AddEntry( pFunction, functionID );
  1404.                         }
  1405.                         pFunction->m_timesCalled++;
  1406.  
  1407.  
  1408.                         //
  1409.                         // Create a new stack entry and push it on the stack for the specific function
  1410.                         //
  1411.                         StackFunctionInfo *pFunctionInfo;
  1412.                         
  1413.                         
  1414.                         pFunctionInfo = new StackFunctionInfo();
  1415.                         if ( pFunctionInfo != NULL )
  1416.                         {
  1417.                             //
  1418.                             // Push it on the stack and start the inclusive time counter
  1419.                             //
  1420.                             (pFunction->m_pLatestInvocation)->Push( pFunctionInfo );
  1421.                             (pFunctionInfo->m_currentInclusiveTime).QuadPart = (pThreadInfo->m_currentProfilerTime).QuadPart;
  1422.                         }
  1423.                         else
  1424.                             _THROW_EXCEPTION( "Allocation for StackFunctionInfo FAILED" )
  1425.                     }
  1426.                     break;
  1427.                 
  1428.                 
  1429.                 case POP:
  1430.                     {
  1431.                         //
  1432.                         // Pop the current element from the callstack
  1433.                         //
  1434.                         stackElement = (pThreadInfo->m_pCallStack)->Pop();
  1435.                         if ( stackElement != NULL )
  1436.                         {
  1437.                             //
  1438.                             // Store away the popped functionID, you will need to update
  1439.                             // the timers for that ID in the EndProfilingTime
  1440.                             //
  1441.                             pThreadInfo->m_lastPoppedFID = stackElement->m_id; 
  1442.                             delete stackElement;
  1443.                         }
  1444.                         else
  1445.                             _THROW_EXCEPTION( "Stack Contains Bad Data" )
  1446.                     }
  1447.                     break;
  1448.                 
  1449.             } // switch
  1450.         }
  1451.         else                 
  1452.             _THROW_EXCEPTION( "Thread Structure was NOT Found in the Thread List" )
  1453.     }
  1454.     else
  1455.         _THROW_EXCEPTION( "ICorProfilerInfo::GetCurrentThreadID() FAILED" )
  1456.     
  1457. } // PrfInfo::UpdateCallStack
  1458.  
  1459.  
  1460. /***************************************************************************************
  1461.  *    Method:
  1462.  *
  1463.  *
  1464.  *    Purpose:
  1465.  *
  1466.  *
  1467.  *    Parameters: 
  1468.  *
  1469.  *
  1470.  *    Return value:
  1471.  *
  1472.  *
  1473.  *    Notes:
  1474.  *
  1475.  ***************************************************************************************/
  1476. /* public */
  1477. void PrfInfo::DumpTables()
  1478. {
  1479.     //
  1480.     // Dump the thread table if you actully performed profiling
  1481.     //
  1482.     if ( BASEHELPER::FetchEnvironment( LOG_ENVIRONMENT ) != 0xFF /* don't log anything */ )
  1483.     {           
  1484.            if ( (m_pThreadTable != NULL) && (m_dwEventMask != (DWORD)COR_PRF_MONITOR_NONE) )
  1485.         {
  1486.             LOG_TO_FILE( ("Thread ID;Function;Times Called;Exclusive Time;Inclusive Time;Callee Time;Suspended Time;Profiler Time\n\n") )
  1487.             m_pThreadTable->Dump();
  1488.         }
  1489.        }
  1490.     
  1491. #ifdef _TESTING_            
  1492.     //
  1493.     // For testing purposes we create a result file. The file indicates
  1494.     // whether the profiler ran without problem for a given input.
  1495.     // 
  1496.     //
  1497.     FILE *stream;
  1498.        char tempBuffer[MAX_PATH];
  1499.        char resultFile[MAX_LENGTH];
  1500.  
  1501.     
  1502.     GetWindowsDirectoryA( tempBuffer, MAX_PATH );
  1503.     
  1504.     // set sentinel values
  1505.     tempBuffer[3] = NULL;
  1506.     resultFile[0] = NULL;
  1507.     sprintf( resultFile, "%s%s", tempBuffer, TEST_FILE );
  1508.  
  1509.     //
  1510.     // create a result file and write success for testing purposes
  1511.     //
  1512.     stream = fopen( resultFile, "w" );
  1513.     if ( stream != NULL )
  1514.     {
  1515.         fprintf( stream, "0" );
  1516.         fflush( stream );
  1517.         fclose( stream );
  1518.     }
  1519.     else
  1520.        TEXT_OUTLN( "Unable to Create Result file" )
  1521. #endif // _TESTING_    
  1522.  
  1523. } // PrfInfo::DumpTables
  1524.  
  1525.  
  1526. /***************************************************************************************
  1527.  *    Method:
  1528.  *
  1529.  *
  1530.  *    Purpose:
  1531.  *
  1532.  *
  1533.  *    Parameters: 
  1534.  *
  1535.  *
  1536.  *    Return value:
  1537.  *
  1538.  *
  1539.  *    Notes:
  1540.  *
  1541.  ***************************************************************************************/
  1542. void PrfInfo::Failure( char *message )
  1543. {
  1544.     if ( message == NULL )         
  1545.          message = "**** SEVERE FAILURE: TURNING OFF APPLICABLE PROFILING EVENTS ****";  
  1546.     
  1547.     
  1548.     //
  1549.     // Display the error message and discontinue monitoring CLR events, except the 
  1550.     // IMMUTABLE ones. Turning off the IMMUTABLE events can cause crashes. The only
  1551.     // place that we can safely enable or disable immutable events is the Initialize
  1552.     // callback.
  1553.     //                  
  1554.     TEXT_OUTLN( message )
  1555.     m_pProfilerInfo->SetEventMask( (m_dwEventMask & (DWORD)COR_PRF_MONITOR_IMMUTABLE) );    
  1556.                             
  1557. } // PrfInfo::Failure
  1558.  
  1559.  
  1560. /***************************************************************************************
  1561.  *    Method:
  1562.  *
  1563.  *
  1564.  *    Purpose:
  1565.  *
  1566.  *
  1567.  *    Parameters: 
  1568.  *
  1569.  *
  1570.  *    Return value:
  1571.  *
  1572.  *
  1573.  *    Notes:
  1574.  *
  1575.  ***************************************************************************************/
  1576. /* private */
  1577. /* throws BaseException */
  1578. void PrfInfo::_GetThreadInfoHelper( ThreadInfo **ppThreadInfo )
  1579. {
  1580.        if ( m_pProfilerInfo != NULL )
  1581.     {
  1582.         HRESULT hr;
  1583.         
  1584.         
  1585.         hr = m_pProfilerInfo->GetThreadInfo( (*ppThreadInfo)->m_id, 
  1586.                                              &((*ppThreadInfo)->m_win32ThreadID) );
  1587.           if ( SUCCEEDED( hr ) )
  1588.            {
  1589.               hr = m_pProfilerInfo->GetHandleFromThread( (*ppThreadInfo)->m_id, 
  1590.                                                        &((*ppThreadInfo)->m_hThread) );      
  1591.             if ( FAILED( hr ) )
  1592.                   _THROW_EXCEPTION( "ICorProfilerInfo::GetHandleFromThread() FAILED" )    
  1593.           }
  1594.         else    
  1595.             _THROW_EXCEPTION( "ICorProfilerInfo::GetThreadInfo() FAILED" )
  1596.      }
  1597.     else
  1598.         _THROW_EXCEPTION( "ICorProfilerInfo Interface has NOT been Initialized" )        
  1599.         
  1600. } // PrfInfo::_GetThreadInfoHelper
  1601.  
  1602.  
  1603. /***************************************************************************************
  1604.  *    Method:
  1605.  *
  1606.  *
  1607.  *    Purpose:
  1608.  *
  1609.  *
  1610.  *    Parameters: 
  1611.  *
  1612.  *
  1613.  *    Return value:
  1614.  *
  1615.  *
  1616.  *    Notes:
  1617.  *
  1618.  ***************************************************************************************/
  1619. /* private */
  1620. /* throws BaseException */
  1621. void PrfInfo::_GetFunctionInfoHelper( FunctionInfo **ppFunctionInfo )
  1622. {
  1623.        if ( m_pProfilerInfo != NULL )
  1624.     {
  1625.          HRESULT hr;
  1626.  
  1627.  
  1628.          hr = BASEHELPER::GetFunctionProperties( m_pProfilerInfo,
  1629.                                                 (*ppFunctionInfo)->m_id,
  1630.                                                    &((*ppFunctionInfo)->m_bIsStatic),
  1631.                                                    &((*ppFunctionInfo)->m_argCount),
  1632.                                                    (*ppFunctionInfo)->m_returnTypeStr, 
  1633.                                                    (*ppFunctionInfo)->m_functionParameters,
  1634.                                                    (*ppFunctionInfo)->m_functionName );
  1635.         if ( FAILED( hr ) )
  1636.             LOG_TO_FILE( ("Unable to Retreive Information about the Function Name, Parameters and Return Type\n") )
  1637.      }
  1638.     else
  1639.         _THROW_EXCEPTION( "ICorProfilerInfo Interface has NOT been Initialized" )        
  1640.         
  1641.  
  1642. } // PrfInfo::_GetFunctionInfoHelper
  1643.  
  1644.  
  1645. /***************************************************************************************
  1646.  ********************                                               ********************
  1647.  ********************          TimeTracker Implementation           ********************
  1648.  ********************                                               ********************
  1649.  ***************************************************************************************/
  1650.  
  1651. /***************************************************************************************
  1652.  *    Method:
  1653.  *
  1654.  *                
  1655.  *    Purpose:
  1656.  *
  1657.  *
  1658.  *    Parameters: 
  1659.  *
  1660.  *
  1661.  *    Return value:
  1662.  *
  1663.  *
  1664.  *    Notes:
  1665.  *
  1666.  ***************************************************************************************/
  1667. /* public */
  1668. TimeTracker::TimeTracker( PrfInfo *pPrfInfo, ThreadID threadID ) : 
  1669.     m_pThreadInfo( NULL )
  1670. {
  1671.     HRESULT hr = S_OK;
  1672.     LARGE_INTEGER localTimer;
  1673.  
  1674.  
  1675.     //
  1676.     // This is a special purpose class used to capture the current value of a
  1677.     // high precision timer and store it in a data member (m_currentProfilerTime)
  1678.     // of a ThreadInfo object. A ThreadInfo object corresponds to a managed thread
  1679.     // that the CLR reported during the ThreadCreated callback. The data member can
  1680.     // be used as a basis for any timer related calculation because it holds the 
  1681.     // starting point for the current time counting operation.
  1682.     //
  1683.     // This class is typically used as a local for the whole scope of many of the 
  1684.     // callbacks. 
  1685.  
  1686.     //
  1687.     // Get the time as soon as you start
  1688.     //
  1689.     localTimer.QuadPart = 0;
  1690.     QueryPerformanceCounter( &localTimer );
  1691.     if ( threadID == NULL )
  1692.         hr = (pPrfInfo->m_pProfilerInfo)->GetCurrentThreadID( &threadID );
  1693.  
  1694.  
  1695.     if ( SUCCEEDED( hr ) )
  1696.     {    
  1697.         //
  1698.         // Find the thread object based on the threadID and store 
  1699.         // the time that tracks how much time is spent in the current 
  1700.         // callback.
  1701.         //
  1702.         m_pThreadInfo = (pPrfInfo->m_pThreadTable)->Lookup( threadID );
  1703.         
  1704.         //
  1705.         // Make sure that all other timing calculations for that thread 
  1706.         // have completed at this point
  1707.         //
  1708.         _ASSERT_( (m_pThreadInfo->m_currentProfilerTime).QuadPart == 0 );
  1709.         (m_pThreadInfo->m_currentProfilerTime).QuadPart = localTimer.QuadPart;
  1710.     }
  1711.     
  1712. } // ctor                 
  1713.  
  1714.  
  1715. /***************************************************************************************
  1716.  *    Method:
  1717.  *
  1718.  *
  1719.  *    Purpose:
  1720.  *
  1721.  *
  1722.  *    Parameters: 
  1723.  *
  1724.  *
  1725.  *    Return value:
  1726.  *
  1727.  *
  1728.  *    Notes:
  1729.  *
  1730.  ***************************************************************************************/
  1731. /* public */
  1732. TimeTracker::~TimeTracker()
  1733. {
  1734.     LARGE_INTEGER storedCounterValue;
  1735.     
  1736.     
  1737.     //
  1738.     // The destructor is used to calculate the accumulative times for the thread 
  1739.     // and the function that is on top of the callstack for the current thread. 
  1740.        //
  1741.     storedCounterValue.QuadPart = (m_pThreadInfo->m_currentProfilerTime).QuadPart;
  1742.     (m_pThreadInfo->m_currentProfilerTime).QuadPart = 0;
  1743.  
  1744.     if ( (m_pThreadInfo != NULL) && (m_pThreadInfo->m_isValid == TRUE) )
  1745.     {        
  1746.         LARGE_INTEGER localTimer;
  1747.            BOOL bInRecursiveCall = FALSE;
  1748.            StackBaseInfo *pStackTop = NULL;
  1749.         StackFunctionInfo *pFunctionInfo = NULL;
  1750.         StackFunctionInfo *pFunctionInfo2 = NULL;
  1751.         FunctionTimingInfo *pPoppedFunction = NULL;
  1752.         FunctionTimingInfo *pCurrentFunction = NULL;
  1753.  
  1754.         
  1755.         //
  1756.         // pPoppedFunction points to the entry of the function that we have just popped
  1757.         // and pFunctionInfo points to the most recent entry of its timers in the function's
  1758.         // timer stack. This pointer will be NULL if we are in case 1 or 2
  1759.         //
  1760.  
  1761.         //
  1762.         // pCurrentFunction points to the entry of the function that is on the top of the callstack
  1763.         // and pFunctionInfo points to the most recent entry of its timers in the function's
  1764.         // timer stack. This pointer will be NULL is we are in case 1 and the callstack is empty 
  1765.         //        
  1766.         _ASSERT_( storedCounterValue.QuadPart != 0 );
  1767.         if ( m_pThreadInfo->m_lastPoppedFID != 0xFFFFFFFF )
  1768.         {
  1769.             pPoppedFunction = (m_pThreadInfo->m_pFunctionTimes)->Lookup( m_pThreadInfo->m_lastPoppedFID );    
  1770.             if ( pPoppedFunction != NULL )
  1771.                pFunctionInfo = (pPoppedFunction->m_pLatestInvocation)->Pop();
  1772.         } 
  1773.         
  1774.         
  1775.         pStackTop = (m_pThreadInfo->m_pCallStack)->Top();
  1776.         if ( pStackTop != NULL )
  1777.         {
  1778.             pCurrentFunction = (m_pThreadInfo->m_pFunctionTimes)->Lookup( pStackTop->m_id );    
  1779.             if ( pCurrentFunction != NULL )
  1780.                pFunctionInfo2 = (pCurrentFunction->m_pLatestInvocation)->Top();
  1781.         } 
  1782.  
  1783.  
  1784.         //
  1785.         // Get the time just before you finish
  1786.         //
  1787.         localTimer.QuadPart = 0;
  1788.         QueryPerformanceCounter( &localTimer );
  1789.         
  1790.         
  1791.         //
  1792.         // Update the timer of the specific thread for the current
  1793.         // profiling event
  1794.         //
  1795.         (m_pThreadInfo->m_profilerTime).QuadPart += (localTimer.QuadPart - storedCounterValue.QuadPart);
  1796.  
  1797.  
  1798.  
  1799.         // Up to this point we have accessed the appropriate thread and function data
  1800.         // structures and we have made the initial computation to determine the profiler
  1801.         // time for the thread. 
  1802.         //  
  1803.         // We have the following 2 cases to consider:
  1804.         //
  1805.         //        1. A callback that is related to a leave event 
  1806.         //        2. A callback that is either not related to any function enter or leave event
  1807.         //         or strictly a function enter event
  1808.         //
  1809.  
  1810.         //
  1811.         // Case 1: Leave Event
  1812.         //
  1813.         if ( pPoppedFunction != NULL )
  1814.         {
  1815.             //
  1816.             // check if the call stack is returning from a recursive call
  1817.             //
  1818.             if ( pCurrentFunction != NULL )
  1819.                 bInRecursiveCall = ( (pCurrentFunction->m_id) == (pPoppedFunction->m_id) ) ? TRUE : FALSE;
  1820.  
  1821.  
  1822.             _ASSERT_((pFunctionInfo->m_currentInclusiveTime).QuadPart != 0);
  1823.             (pFunctionInfo->m_profilerTime).QuadPart += (localTimer.QuadPart - storedCounterValue.QuadPart);
  1824.             (pFunctionInfo->m_inclusiveTime).QuadPart += (localTimer.QuadPart - (pFunctionInfo->m_currentInclusiveTime).QuadPart);
  1825.             (pFunctionInfo->m_currentInclusiveTime).QuadPart = 0;
  1826.  
  1827.  
  1828.             //
  1829.             // Update the global counters for that function
  1830.             //
  1831.             (pPoppedFunction->m_calleeTime).QuadPart += (pFunctionInfo->m_calleeTime).QuadPart;
  1832.             (pPoppedFunction->m_profilerTime).QuadPart += (pFunctionInfo->m_profilerTime).QuadPart;
  1833.             (pPoppedFunction->m_suspendedTime).QuadPart += (pFunctionInfo->m_suspendedTime).QuadPart;
  1834.             
  1835.             //
  1836.             // do not update the inclusive time if we have a return from a recursive call
  1837.             //
  1838.             if ( bInRecursiveCall == FALSE )
  1839.                 (pPoppedFunction->m_inclusiveTime).QuadPart += (pFunctionInfo->m_inclusiveTime).QuadPart;
  1840.  
  1841.  
  1842.             //
  1843.             // Update the timers for the top function in the call stack    
  1844.             // and we do not have a recursive call
  1845.             //
  1846.             if ( (pCurrentFunction != NULL) && (pFunctionInfo2 != NULL) && ( bInRecursiveCall == FALSE ) )
  1847.                 (pFunctionInfo2->m_calleeTime).QuadPart += (pFunctionInfo->m_inclusiveTime).QuadPart;
  1848.  
  1849.            
  1850.             m_pThreadInfo->m_lastPoppedFID = 0xFFFFFFFF;
  1851.         }
  1852.         //
  1853.         // Case 2: No Enter or Leave Event, Or strictly an Enter Event
  1854.            //
  1855.         else
  1856.         {           
  1857.             if ( (pCurrentFunction != NULL) && (pFunctionInfo2 != NULL) )
  1858.                 (pFunctionInfo2->m_profilerTime).QuadPart += (localTimer.QuadPart - storedCounterValue.QuadPart);
  1859.         }
  1860.         
  1861.     
  1862.         // ensure that has been reset and clean up the Popped (copied) stack element
  1863.         _ASSERT_( m_pThreadInfo->m_lastPoppedFID == 0xFFFFFFFF );
  1864.         if ( pFunctionInfo != NULL )
  1865.             delete pFunctionInfo;
  1866.     }
  1867.  
  1868. } // dtor
  1869.  
  1870. // End of File
  1871.