© 2004 Microsoft Corporation. All rights reserved.

Figure 1 The CLR Profiling Notifications

CLR startup and shutdown events
Application domain creation and shutdown events
Assembly load and unload events
Module load and unload events
COM-callable wrapper creation and destruction events
Just-in-time (JIT) compilation events
Class load and unload events
Thread creation and destruction events
Function enter and leave events
Object allocation and garbage collection events
Transitions between managed and unmanaged code events
Context and remote boundary crossing events
CLR suspend and resume events
CLR (managed) exception events
Figure 2 Using ICorProfilerInfo from ICorProfilerCallback
HRESULT ProfilerCallback::ManagedToUnmanagedTransition( 
   FunctionID functionID, 
   COR_PRF_TRANSITION_REASON reason )
{
  HRESULT hr;
  ThreadID threadID;  // find which managed thread we are talking about
  hr = m_pProfilerInfo->GetCurrentThreadID(&threadID);
  if ( SUCCEEDED(hr) )
  {
    ................. // ....................
  }
  else
    printf( "ICorProfilerInfo::GetCurrentThreadID() FAILED" );
}
Figure 3 The Class Factory Header for the Profiler
class CClassFactory : public IclassFactory
{
   private:
     CClassFactory();

  public:
    CClassFactory( const COCLASS_REGISTER *pCoClass );
    ~CClassFactory();
        

  public:
    //
    // IUnknown 
    //
    COM_METHOD( ULONG ) AddRef();        
    COM_METHOD( ULONG ) Release();
    COM_METHOD( HRESULT ) QueryInterface( REFIID riid, 
                          void **ppInterface );
        
    //
    // IClassFactory 
    //
    COM_METHOD( HRESULT ) LockServer( BOOL fLock );
    COM_METHOD( HRESULT ) CreateInstance( IUnknown *pUnkOuter, 
                          REFIID riid, void **ppInterface );
    
  private:
    long m_refCount;
    const COCLASS_REGISTER *m_pCoClass;        
        
}; // CClassFactory 
Figure 4 The DllMain Implementation
BOOL WINAPI DllMain( HINSTANCE hInstance, 
                     DWORD dwReason, 
                     LPVOID lpReserved )
{
  // save off the instance handle for later use
  switch ( dwReason )
  {
    case DLL_PROCESS_ATTACH:
     g_hInst = hInstance;
     DisableThreadLibraryCalls( hInstance );
     break;
        
    case DLL_PROCESS_DETACH:
      // lpReserved == NULL means that we called FreeLibrary()
      // in that case do nothing
      if ( (lpReserved != NULL) && (g_pCallbackObject != NULL) )
        g_pCallbackObject->DllDetachShutdown();
      break;    
        
    default:
      break;        
  }

  return TRUE;

} // DllMain
Figure 5 Hooks for Enter-leave and Tail-leave Events
void __stdcall EnterStub( FunctionID functionID )
{
    ProfilerCallback::Enter( functionID );
}

void __stdcall LeaveStub( FunctionID functionID )
{
    ProfilerCallback::Leave( functionID );
}

void __stdcall TailcallStub( FunctionID functionID )
{
    ProfilerCallback::Tailcall( functionID );
}

void __declspec( naked ) EnterNaked()
{
    __asm
    {
        push eax
        push ecx
        push edx
        push [esp+16]
        call EnterStub
        pop edx
        pop ecx
        pop eax
        ret 4
    }
}

void __declspec( naked ) LeaveNaked()
{
    __asm
    {
        push eax
        push ecx
        push edx
        push [esp+16]
        call LeaveStub
        pop edx
        pop ecx
        pop eax
        ret 4
    }
}

void __declspec( naked ) TailcallNaked()
{
    __asm
    {
        push eax
        push ecx
        push edx
        push [esp+16]
        call TailcallStub
        pop edx
        pop ecx
        pop eax
        ret 4
    }
}
Figure 6 Snapshot of the Tool's Output

Thread ID
Function
Times Called
Exclusive Time
Inclusive Time
Callee Time
Suspended Time
Profiler Time
0x0000126c
static System.AppDomainSetup System.AppDomain:: SetupLoaderContext ( System.AppDomainSetup)
1
0.071196
0.15496
0.083701
0
0.000063
0x0000126c
void System.AppDomain:: SetupDomain ( System.LoaderOptimization )
1
0.057901
0.240687
0.182723
0
0.000063
Figure 7 Description of the Various Times

Time
Description
Inclusive
The sum of all the times below
Exclusive
Total time consumed in executing the specific function, without taking into consideration any of its callees
Callee
Total time spent in a function's callees
Suspended
Total time the CLR was suspended and the specific function was on top of the stack
Profiler
Total overhead to the execution time of the specific function because of the profiling process