Code Generation in the Profiling API
This topic discusses the flow of Microsoft intermediate language (MSIL) code to native code and how a profiler can control code generation.
Automatic Versus Manual Code Generation
The MSIL in a .NET Framework assembly can be compiled to native code in one of two ways:
Manual compilation: The Native Image Generator (NGen.exe) tool can be used to create a native image.
Automatic compilation: The common language runtime (CLR) may perform just-in-time (JIT) compilation at run time.
Both NGen.exe and the JIT compiler provide flags that control code generation.
When an assembly is loaded, the CLR first looks for a native image for the assembly. If it cannot find a native image with the right set of code-generation flags, the CLR will JIT-compile the functions in the assembly as they are needed during the run. Even when a native image is found and loaded, the CLR may JIT-compile some of the functions in the assembly.
Profiler Control over Code Generation
The profiler uses the flags in the following table to control code generation.
Flag |
Effect |
---|---|
COR_PRF_USE_PROFILE_IMAGES |
(Requires the .NET Framework version 2.0.) Causes the native image search to look for profiler-enhanced images (ngen /profile). If the search fails to find a profiler-enhanced native image for a given assembly, the CLR will instead JIT-compile the methods in that assembly as they are needed. Has no effect on JIT-compiled code. |
COR_PRF_DISABLE_INLINING |
Has no effect on the native image search. In JIT compilation, disables inlining. All other optimizations remain in effect. |
COR_PRF_DISABLE_OPTIMIZATIONS |
Has no effect on the native image search. In JIT compilation, disables all optimizations, including inlining. |
COR_PRF_MONITOR_ENTERLEAVE |
Causes the native image search to look for profiler-enhanced images (ngen /profile). In JIT compilation, inserts enter/leave hooks into the generated code. |
COR_PRF_MONITOR_CODE_TRANSITIONS |
Causes the native image search to look for profiler-enhanced images (ngen /profile). In JIT compilation, inserts hooks at managed/unmanaged transition points. |
Profilers and Native Images
When NGen.exe creates a native image, it does much of the work that the CLR generally performs at run time (for example, class loading and function compilation). As a result, in cases where work was done at NGen time, the following profiler callbacks will not be received at run time:
Profiler-Enhanced Native Images
Creating a native image with NGen.exe turns on a set of code-generation flags that make the image easier to profile, as follows:
Enter/leave hooks are inserted into the code.
Managed/unmanaged transition hooks are inserted into the code.
ICorProfilerCallback::JITCachedFunctionSearchStarted and ICorProfilerCallback::JITCachedFunctionSearchFinished notifications are issued as each function in the native image is invoked for the first time.
ICorProfilerCallback::ClassLoadStarted and ICorProfilerCallback::ClassLoadFinished notifications are issued as each class in the native image is used for the first time.
Performance Considerations
The method you use to profile your NGen-generated application depends on two considerations: the data that you need to acquire, and the effect of embedded profiling hooks on your application.
As discussed earlier in this topic, there are two basic NGen profiling scenarios:
Regular native images (NGen-generated images without profiling hooks): These images do not cause any profiling overhead. However, the class load/unload callbacks are not available for regular native images. To handle this situation, a profiler that does not want to request profiler-enhanced native images will have to gather data about FunctionIDs or ClassIDs as the IDs are encountered. For example, a sampling profiler will not encounter a FunctionID when the FunctionID is first JIT-compiled or loaded from an NGen-generated image, because the class load/unload callbacks are not issued for regular NGen-generated images. The profiler will encounter the FunctionID later, when a sample shows that the process was executing at an instruction pointer (IP) inside the body of the function’s compiled code. In this case, the profiler could query for information about the function during the sampling, or it could log the FunctionID or its associated metadata token for querying even later. Therefore, the profiler will query for information about the FunctionID or ClassID only at the last possible moment (when it detects that the ID is actually used) instead of earlier, when the ID is first produced.
Profiler-enhanced native images (NGen-generated images with embedded profiling hooks): These images are larger, and they differ significantly from regular images. In addition, the behavior of the application may be different when it includes profiler hooks. Therefore, you should use profiler-enhanced native images only if the potential performance and behavioral consequences (overhead) are acceptable.