In-Process Side-by-Side Profiling
Starting with the .NET Framework 4, multiple versions of the .NET Framework can run side by side in the same process. Profilers must be side-by-side-aware to run in this environment. Profilers that are designed to work with the .NET Framework version 2.0, .NET Framework 2.0 SP1, .NET Framework 3.0, .NET Framework 3.5, or .NET Framework 3.5 SP1 can be used in the .NET Framework version 4, if the process that is being profiled does not host multiple versions of the .NET Framework. For more information about how to use in-process side-by-side profiling, see Profiler Compatibility Settings.
Side-by-Side Awareness
A profiler is side-by-side-aware if it ensures that applications that load multiple runtimes do not cause the profiler to encounter unexpected breakages, such as access violations. Side-by-side awareness includes the following levels of support:
Profile first. The first common language runtime (CLR) version that is loaded into a process is profiled, but subsequent CLR versions are not. The profiler must be prepared for multiple CreateInstance calls to be made on its COM class factory object, but does not have to support simultaneous, active use of callbacks on multiple instances of its COM object. The profiler simply accepts the first class factory CreateInstance call and Initialize callback call, and fails the rest.
Profile one. Similar to profile first, except that the profiler lets the user choose which CLR version will be profiled, instead of simply profiling the first CLR version that is loaded.
Profile many. The user chooses one or more (possibly all) CLR versions to profile. The profiler consumes callbacks from those CLR versions and calls Info functions back into the appropriate version. This requires the profiler to track which runtime items (functions, application domains, classes, objects, and so on) belong to which CLR.
Note
A profiler that is designed for the .NET Framework 4 must be side-by-side-aware. That is, if a profiler implements the ICorProfilerCallback3 interface, it must implement one of these schemes (profile first, profile one, or profile many) to ensure that multiple runtimes do not cause the profiler to encounter unexpected breakages.
Requirements for Profile Many Support
To support the profile many option, a profiler must be able to do the following:
Associate calls to global functions with the correct runtime.
Associate the various IDs (for example, ObjectID, FunctionID, ClassID, ModuleID, AssemblyID, AppDomainID, and so on) with the correct runtime, and ensure that an ID from one runtime is never passed to another runtime's ICorProfilerCallback(2,3) interface. However, it is acceptable to pass any instruction pointer from any runtime or native code into any runtime's implementation of the ICorProfilerInfo::GetFunctionFromIP method.
Handle interactions between runtimes, such as call stacks that pass from one runtime to another.
Handle multiple instances of its class that implements ICorProfilerCallback(2,3) being active in the same process.
The profiler should typically provide a single profiler manager object that is responsible for handling global function implementations and data spanning multiple runtimes. For example:
Enter/leave/tailcall/FunctionIDMapperFunctionIDMapper Function callbacks from all runtimes. The profiler manager object will typically use the clientData parameter from FunctionIDMapper2 or ICorProfilerInfo3::SetFunctionIDMapper2 to determine the corresponding runtime.
Stack walks and shadow stacks across runtimes.
Coordinated logging among the runtimes.
The profiler must also provide a profiler object that implements the ICorProfilerCallback interfaces. The CLR instantiates this profiler object once for each active runtime. The only global object that the profiler should access is the profiler manager. The profiler should not maintain a global reference to its ICorProfilerCallback implementation, because many instances of the ICorProfilerCallback implementation may be active when the process contains multiple runtimes.
Activating Profilers
The primary activation task is the association of profilers with runtime versions.
Launching Profilers
If you want to launch a profiler in all runtimes in a given process, set the COR_PROFILER and COR_ENABLE_PROFILING environment variables. (This is the same procedure as in the .NET Framework 3.5 and previous versions.)
If you want to launch a profiler only in certain runtimes, set the COR_PROFILER and COR_ENABLE_PROFILING environment variables and do one of the following:
Fail all except the first CreateInstance call to the class factory object (profile first).
- or -
Allow all CreateInstance calls to the class factory object, and in the Initialize call, determine the version of the calling runtime. To do this, you must do both the following actions:
Execute the QueryInterface method on the CLR for the ICorProfilerInfo3 interface. If this fails, the runtime version is 1 or 2.0. Executing QueryInterface for the ICorProfilerInfo2 interface will reveal whether the runtime is a version 2.0 runtime or a version 1 runtime.
If ICorProfilerInfo3 is supported, call the GetRuntimeInformation method to obtain more information about the runtime that is being profiled.
When the version of the runtime has been determined, the profiler can decide whether to profile that runtime. If so, continue with initialization as usual. If not, return an error from Initialize. Starting with the .NET Framework 4, the profiler may return a CORPROF_E_PROFILER_CANCEL_ACTIVATION HRESULT to avoid causing an error to be logged to the Windows Application Event Log.
Attaching Profilers
An attach trigger process does the following:
Uses the ICLRMetaHost::EnumerateLoadedRuntimes method to enumerate runtimes that are loaded into the target process, and to find the runtime of interest.
Retrieves an ICLRRuntimeInfo interface from the IEnumUnknown interface that is returned from the ICLRMetaHost::EnumerateLoadedRuntimes method.
Gets an ICLRProfiling interface by calling GetInterface on the ICLRRuntimeInfo interface with CLSID_CLRProfiling and IID_ICLRProfiling.
Calls the AttachProfiler method through the ICLRProfiling interface.
For more information about attaching profilers, see Profiler Attach and Detach.
See Also
Concepts
Profiling in the .NET Framework 4