Profiling in the .NET Framework 2.0
The profiling API was enhanced in the .NET Framework version 2.0 to provide additional capabilities. The new functionality is exposed through two new interfaces: ICorProfilerCallback2 and ICorProfilerInfo2.
A profiler DLL that was written for the .NET Framework version 1.0 or 1.1 will not work correctly in the .NET Framework 2.0 common language runtime (CLR) environment. To update your profiler DLL to work with version 2.0 or later, you must implement the ICorProfilerCallback2 interface. The ICorProfilerInfo2 interface inherits from the ICorProfilerInfo interface and introduces new methods that support enhanced interaction with the CLR.
The changes are discussed in the following sections:
Generics
Code Splitting
Removal of In-Process Debugging
Callbacks with the Native Image Generator
Enhanced Garbage Collection Callbacks
Frozen Objects
Miscellaneous API Changes
In addition to the API changes, a new HRESULT, CORPROF_E_UNSUPPORTED_CALL_SEQUENCE, was added. For information about the scenarios in which this HRESULT may be returned, see CORPROF_E_UNSUPPORTED_CALL_SEQUENCE HRESULT.
Generics
The introduction of generics into the runtime has caused three changes in the profiling API:
A one-to-one mapping no longer exists between typedef tokens and ClassID values, or between MethodDef tokens and FunctionID values. This is because each class or function may be instantiated for several different types. Profiler authors should read Profiling and Runtime Notification IDs, examine how they use the ICorProfilerInfo::GetClassFromToken and ICorProfilerInfo::GetFunctionFromToken methods in their code, and rewrite their code in a generics-aware manner. The profiling API provides two new methods, ICorProfilerInfo2::GetClassFromTokenAndTypeArgs and ICorProfilerInfo2::GetFunctionFromTokenAndTypeArgs, to support generics.
A direct mapping no longer exists between a FunctionID and the ClassID it contains. Code-sharing optimizations can enable different instantiations of a generic type to share code. You can determine the ClassID of a FunctionID only when you examine them in the context of a particular activation of the function.
The existing class and function information methods in the ICorProfilerInfo interface do not provide information about type arguments for generic types and functions. The ICorProfilerInfo2::GetClassIDInfo2 and ICorProfilerInfo2::GetFunctionInfo2 methods have been provided for this purpose. Note that these methods cannot always provide this information; see Profiling and Runtime Notification IDs for more information.
Back to top
Code Splitting
The assemblies in the .NET Framework have undergone a performance optimization. Precompiled native code has been split into multiple regions per function. Therefore, the existing ICorProfilerInfo::GetCodeInfo method can no longer correctly describe the extent of a function's native code. Profilers should switch to using the more general ICorProfilerInfo2::GetCodeInfo2 method instead.
Back to top
Removal of In-Process Debugging
In the .NET Framework 2.0, in-process debugging was replaced with a set of functionality that is consistent with the profiling API. The stack snapshot (see the Profiling Overview) and object inspection feature are the result.
Back to top
Callbacks with the Native Image Generator
Significant optimizations in the Native Image Generator (NGen.exe) have moved even more work from run time to native image generation time. This has led to the following changes in the behavior of the profiling API:
For most functions, JITCachedFunctionSearch callbacks are no longer received in native images. A profiler has two options depending on how it uses callbacks:
If the profiler uses callbacks to gather information about a function, it can switch to a scheme where information is gathered about a given function only when that function is first encountered during program execution.
If the profiler uses callbacks to force a function to be just-in-time (JIT) compiled for the purposes of instrumentation, it can use profiler-enhanced native images instead. For more information, see Code Generation in the Profiling API.
For most types, ClassLoad callbacks are no longer received in native images. Profilers should use run-time evaluation techniques (also called lazy evaluation) for such classes. Profilers that are already using profiler-enhanced native images do not have to change their behavior. However, a profiler should not switch to profiler-enhanced native images unless it needs these images for other reasons, because profiler-enhanced native images are significantly different from regular images.
Back to top
Enhanced Garbage Collection Callbacks
The garbage collection callbacks have been enhanced in several ways. Callbacks now notify the profiler that garbage collection handles have been created or destroyed, provide information about the queuing of objects to be finalized, and use the Collect method to force a garbage collection. The ICorProfilerCallback2::RootReferences2 method, which is an extension of ICorProfilerCallback::RootReferences, provides information about the type of each root. Finally, the ICorProfilerCallback2::SurvivingReferences method reports the layout of objects in the heap that is caused by a non-compacting garbage collection.
Back to top
Frozen Objects
Frozen objects, which are new in the .NET Framework 2.0, are constant objects that are initialized at native image generation time and burned into the native image. Frozen objects are not relocated by garbage collection, but they may be referenced by garbage collection objects. The new ICorProfilerInfo2::EnumModuleFrozenObjects method enables profilers to enumerate frozen objects.
Back to top
Miscellaneous API Changes
The .NET Framework 2.0 also includes the following API changes:
The ICorProfilerInfo::SetFunctionReJIT method now returns E_NOIMPL. In earlier releases, calling this method resulted in deadlock.
The new ICorProfilerCallback2::ThreadNameChanged method provides notification of thread name changes.
The new ICorProfilerInfo2::GetThreadAppDomain method accepts a thread ID and returns the application domain in which that thread is executing.
Back to top