Setting Up a Profiling Environment

In previous topics, we described what occurs when the application and profiler are running. But how are the two connected when an application is started? The common language runtime (CLR) makes the connection during its initialization in each process. It decides whether to connect to a profiler. If it decides to connect, it locates the profiler by checking the value of two environment variables in the following order:

  • COR_ENABLE_PROFILING: The CLR connects to a profiler only if this environment variable exists and is set to 1.

  • COR_PROFILER: If the COR_ENABLE_PROFILING check passes, the CLR connects to the profiler that has this CLSID or ProgID, which must have been stored previously in the registry. The COR_PROFILER environment variable is defined as a string, as shown in the following two examples.

    set COR_PROFILER={32E2F4DA-1BEA-47ea-88F9-C5DAF691C94A}
    set COR_PROFILER="MyProfiler"
    

Therefore, to profile a CLR application, you must set the COR_ENABLE_PROFILING and COR_PROFILER environment variables before you run the application. In addition, you must make sure that the profiler DLL is registered.

Environment Variable Scope

How you set the COR_ENABLE_PROFILING and COR_PROFILER environment variables will determine their scope of influence. You can set these variables in one of the following ways:

  • If you set the variables in an ICorDebug::CreateProcess call, they will apply only to the application that you are running at the time. (They will also apply to other applications started by that application that inherit the environment.)

  • If you set the variables in a Command Prompt window, they will apply to all applications that are started from that window.

  • If you set the variables at the user level, they will apply to all applications that you start with Windows Explorer. A Command Prompt window that you open after you set the variables will have these environment settings, and so will any application that you start from that window. To set environment variables at the user level, right-click My Computer, click Properties, click the Advanced tab, click Environment Variables, and add the variables to the User variables list.

  • If you set the variables at the computer level, they will apply to all applications that are started on that computer. A Command Prompt window that you open on that computer will have these environment settings, and so will any application that you start from that window. This means that every managed process on that computer will start with your profiler. To set environment variables at the computer level, right-click My Computer, click Properties, click the Advanced tab, click Environment Variables, add the variables to the System variables list, and then restart your computer. After restarting, the variables will be available system-wide.

If you are profiling a Windows Service, you must restart your computer after you set the environment variables and register the profiler DLL. For more information about these considerations, see Profiling a Windows Service.

Additional Considerations

  • The profiler class implements the ICorProfilerCallback and ICorProfilerCallback2 interfaces. In the .NET Framework version 2.0, a profiler must implement ICorProfilerCallback2. If it does not, ICorProfilerCallback2 will not be loaded.

  • Only one profiler can profile a process at one time in a given environment. You can register two different profilers in different environments, but each must profile separate processes.The profiler must be implemented as an in-process COM server DLL, which is mapped into the same address space as the process that is being profiled. This means that the profiler runs in-process. The .NET Framework does not support any other type of COM server. For example, if a profiler wants to monitor applications from a remote computer, it must implement collector agents on each computer. These agents will batch results and communicate them to the central data collection computer.

  • Because the profiler is a COM object that is instantiated in-process, each profiled application will have its own copy of the profiler. Therefore, a single profiler instance does not have to handle data from multiple applications. However, you will have to add logic to the profiler's logging code to prevent log file overwrites from other profiled applications.

Initializing the Profiler

When both environment variable checks pass, the CLR creates an instance of the profiler in a similar manner to the COM CoCreateInstance function. The profiler is not loaded through a direct call to CoCreateInstance. Therefore, a call to CoInitialize, which requires setting the threading model, is avoided. The CLR then calls the ICorProfilerCallback::Initialize method in the profiler. The signature of this method is as follows.

HRESULT Initialize(IUnknown *pICorProfilerInfoUnk)

The profiler must query pICorProfilerInfoUnk for an ICorProfilerInfo or ICorProfilerInfo2 interface pointer and save it so that it can request more information later during profiling.

Setting Event Notifications

The profiler then calls the ICorProfilerInfo::SetEventMask method to specify which categories of notifications it is interested in. For example, if the profiler is interested only in function enter and leave notifications and garbage collection notifications, it specifies the following.

ICorProfilerInfo* pInfo;
pICorProfilerInfoUnk->QueryInterface(IID_ICorProfilerInfo, (void**)&pInfo);
pInfo->SetEventMask(COR_PRF_MONITOR_ENTERLEAVE | COR_PRF_MONITOR_GC)

By setting the notifications mask in this manner, the profiler can limit which notifications it receives. This approach helps the user build a simple or special-purpose profiler. It also reduces CPU time that would be wasted sending notifications that the profiler would just ignore.

Certain profiler events are immutable. This means that as soon as these events are set in the ICorProfilerCallback::Initialize callback, they cannot be turned off and new events cannot be turned on. Attempts to change an immutable event will result in ICorProfilerInfo::SetEventMask returning a failed HRESULT.

See Also

Other Resources

Profiling in the .NET Framework

Profiling Overview