</GeeksWantMore>
Shortcomings in v1.x
In the introduction we took a look at the ngen.exe tool of the .NET Framework v1.x. Although the principle is great (and it's being used by dotnetfx.exe during installation of the BCL assemblies), it has some serious drawbacks. An overview:
- Native images cannot be shared across application domains, which renders ngen.exe useless for ASP.NET and other scenarios where more than one application domain is involved.
- Managed assemblies have dependencies (at least mscorlib.dll is required). When an assembly is ngen-ed, stuctural information about those dependencies is introduced in the native image. A change of such a dependency will invalidate the native image which was generated by ngen, falling back on JIT compilation instead. Imagine what would happen if System.dll changes (e.g. by applying a service pack).
- Ngen is invoked on a single assembly, not on an entire application. It's up to the developer to make sure dependencies are ngen-ed as well.
- The ngen.exe tool doesn't use the standard assembly probing rules to locate the specified assembly. Instead, it just looks in the current folder.
- NGen can only run synchronously. You have to wait till the compilation to native code has completed.
- There is no support for a thing called "hardbinding". Although only handy in somewhat rare situations, hardbinding can be useful.
Hardbinding eliminates additional costs associated with maintaining "call stubs" which are introduced in code to call methods etc in another assembly. Because the target is not known at compile-time, the virtual address at runtime is unknown. Instead, a little stub function is created which is responsible to calculate that virtual address of the call target. Once the address is found, the call is "backpatched" in order to bypass the stub and call the target directly. However, because of this a code page which was read-only in the past, now needs to be changed to writable (to apply the backpatch) and thus it cannot be shared anymore. Reduction of sharable pages can hurt performance.
Whidbey's new NGen technology
Overview of ngen.exe
NGen 2.0 tries to solve a series of the aforementioned shortcomings. Start by opening a Visual Studio 2005 Command Prompt and launch the new ngen.exe tool. This is the output:
C:\>ngen
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Usage: ngen <action> [args] [/nologo] [/silent] [/verbose]
ngen /? or /help
/nologo - Prevents displaying of logo
/silent - Prevents displaying of success messages
/verbose - Displays verbose output for debugging
Actions:
ngen install <assembly name> [scenarios] [config] [/queue[:[1|2|3]]
Generate native images for an assembly and its dependencies
and install them in the Native Images Cache
NGen now works on applications, not on stand-alone assemblies.
If /queue is specified compilation job is queued up. If a priority
is not specified, the default priority used is 3.
Can run asynchronously by using a queue. More info follows later.
ngen uninstall <assembly name> [scenarios] [config]
Delete the native images of an assembly and its dependencies from
the Native Images Cache.
ngen update [/queue]
Update native images that have become invalid
If /queue is specified compilation jobs are queued up.
ngen display [assembly name]
Display the ngen state
ngen executeQueuedItems [1|2|3]
Executes queued compilation jobs.
If priority is not specified all queued compilation jobs are done.
If priority is specified compilation jobs with greater or equal.
priority than the specified are done.
ngen queue [pause|continue|status]
Allows the user to pause and continue the NGen Service Queue, and to
query its status.
Scenarios:
/Debug - Generate images that can be used under a debugger
/Profile - Generate images that can be used under a profiler
/NoDependencies - Generate the minimal number of native images
required by this scenario
Config:
/ExeConfig:<path to exe> - Use the configuration of the specified
executable assembly
/AppBase:<path to appbase directory> - Use the specified directory as
the appbase
I've annotated the output above with red text, pointing to some of the shortcomings addressed in the new version. First of all, dependencies are also ngen-ed automatically because the tool detects all dependencies automatically. An easy sample will show this:
- Open a Visual Studio 2005 Command Prompt.
- Create a new file testhelper.cs using Notepad:
public class TestHelper
{
public string GetMessage()
{
return "Test";
}
}
- Create a new file test.cs using Notepad:
class Test
{
public static void Main()
{
System.Console.WriteLine(new TestHelper().GetMessage());
}
}
- Compile both files and run:
C:\temp>csc -t:library testhelper.cs
Microsoft (R) Visual C# 2005 Compiler version 8.00.50215.44
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50215
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
C:\temp>csc -r:testhelper.dll test.cs
Microsoft (R) Visual C# 2005 Compiler version 8.00.50215.44
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50215
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
C:\temp>test
Test
- Open %windir%\assembly\NativeImages_v2.0.50215_32 in another Visual Studio 2005 Command Prompt window. You should find no folder called test or testhelper.
- Switch back to the first command prompt window and execute ngen as follows (new syntax!):
C:\temp>ngen install test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Installing assembly C:\temp\test.exe
Compiling 2 assemblies:
Compiling assembly C:\temp\test.exe ...
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Compiling assembly testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null ...
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
- Now native images for both test and testhelper should be present in the assembly\NativeImages_v2.0.50215_32 folder. The new filename of native images contains .ni. in the middle between the original filename and the extension. So, the following dir command shows us all of the native images for test* assemblies:
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test*.ni.* /s
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32\test\8714e29e626e8e3e8323436ee93dd387
08/31/2005 05:54 PM 12,800 test.ni.exe
1 File(s) 12,800 bytes
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32\testhelper\b6c46520e8eb8c37b273b092ff53c2fa
08/31/2005 05:54 PM 12,288 testhelper.ni.dll
1 File(s) 12,288 bytes
Total Files Listed:
2 File(s) 25,088 bytes
0 Dir(s) 119,786,254,336 bytes free
- Again you can use ildasm and/or fuslogvw to find out more:
- ildasm.exe should only show the manifest in the native image files test.ni.exe and testhelper.ni.dll (note: the /Adv flag for ildasm.exe has been removed and is on by default; use View, Headers to view the COR Header)
- fuslogvw.exe now has a Settings button to eliminate the need to go to the registry to change the logging level (select "Log all binds to disk") and also has a "Log Categories" section where you can choose "Native Images" from
Now, how does ngen.exe determine the dependencies of a given assembly? The answer is the IL header which contains all static "imports" in the assembly:
// Metadata version: v2.0.50215
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.assembly extern testhelper
{
.ver 0:0:0:0
}
Now, what happens if we want to uninstall the native images for our test.exe application. Let's run it to get a clue about this (warning: make sure to cd out of the NativeImages_v2.0.50215_32\test* directories if these are still open in some command prompt window):
C:\temp>ngen uninstall test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Uninstalling assembly C:\temp\test.exe
and
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test*
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32
File Not Found
As you can see, also the testhelper.dll native image has disappeared. There has to be some kind of dependency tracking, right? Let's do another test:
- In the folder where testhelper.dll resides, create a new file called test2.cs with the following code in it:
class Test2
{
public static void Main()
{
System.Console.WriteLine(new TestHelper().GetMessage());
}
}
- Compile the test2.cs file:
C:\temp>csc -r:testhelper.dll test2.cs
Microsoft (R) Visual C# 2005 Compiler version 8.00.50215.44
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50215
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
- Now send both apps to the NGen cache:
C:\temp>ngen install test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Installing assembly C:\temp\test.exe
Compiling 2 assemblies:
Compiling assembly C:\temp\test.exe ...
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Compiling assembly testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null ...
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
C:\temp>ngen install test2.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Installing assembly C:\temp\test2.exe
Compiling 1 assembly:
Compiling assembly C:\temp\test2.exe ...
test2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
- In the other command prompt window, check the existence of the expected folders:
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test*
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32
08/31/2005 06:12 PM <DIR> test
08/31/2005 06:12 PM <DIR> test2
08/31/2005 06:12 PM <DIR> testhelper
0 File(s) 0 bytes
3 Dir(s) 119,785,574,400 bytes free
- Now uninstall test.exe using ngen:
C:\temp>ngen uninstall test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Uninstalling assembly C:\temp\test.exe
- Check the NGen cache again:
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test*
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32
08/31/2005 06:12 PM <DIR> test2
08/31/2005 06:12 PM <DIR> testhelper
0 File(s) 0 bytes
2 Dir(s) 119,785,574,400 bytes free
- Cool, testhelper is still alive and kicking out there. Dependency tracking does its job.
So, now the question you'll be asking yourself probably: where does the CLR keep track of these dependencies? The answer is the registry, more specifically in the following key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\NativeImagesIndex\v2.0.50215_32. In the Registry Editor, search for "test" starting from the specified key and you should find both the test2 and testhelper entries. For example, I have a key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion\NativeImagesIndex\v2.0.50215_32\IL\2988d581\392c9598\f1over here for the testhelper assembly. The subkey InvertDependencies contains links to the assemblies depending on the current one. An overview of the local situation:
- IL\2988d581\392c9598\f1
- DisplayName: testhelper,0.0.0.0,,
- InvertDependencies: 1793d581\fe08a65\d2, 5b607b80\66bc3064\a1
- IL\6897b81\795befb3\f8
- DisplayName: test2,0.0.0.0,,
- InvertDependencies: 5b607b80\66bc3064\a1
- NI\1793d581\fe08a65\d2
- DisplayName: testhelper,0.0.0.0,,
- MVID: 6B DA A9 0D 8E 31 A3 38 96 05 C7 87 17 C8 65 98
- NI\5b607b80\66bc3064\a1
- DisplayName: test2,0.0.0.0,,
- MVID: 2C 25 C4 D5 6F 30 FB 3F B3 CA AC 5F 2D 46 5B 52
The NI keys contain information about the native images, i.e. testhelper and test2. The MVID points to the subdirectory in the NativeImages_v2.0.50215_32 folder where the native image resides. E.g. testhelper lives on my system in C:\WINDOWS\assembly\NativeImages_v2.0.50215_32\testhelper\6bdaa90d8e31a3389605c78717c86598. In the IL part you'll find the InvertDependencies list for each assembly in the NGen cache. As you can see, testhelper is needed for testhelper itself (the native image) and test2. This means that a change to testhelper will cause an ngen to occur to testhelper and test2, because these native images would be invalidated by changing testhelper.
Note: Do not confuse these mechanisms with the old COM registration mechanism. COM suffers from the infamous DLL Hell, whileas the .NET Framework does not suffer from this problem (cf. versioning). Furthermore, the use of the registry for "registration" and "dependency tracking" is a ngen-only thing in the world of .NET, assemblies can be xcopy deployed. Also notice that the assemblies act as a kind of stubs to the native images when such a native image exists. You can't delete the testhelper.dll file in order to run test.exe or test2.exe although it resides in the NGen cache. If you'd like to do this, you'll need to register the assembly in the GAC (thus requiring strong naming). Thus, ngen.exe is not a .NET look-alike for regsvr32.exe.
So far, we've seen the ngen install and ngen uninstall actions. It's worth to mention that a fully-qualified assembly name can be used to perform the install action. Notice that such a fully-qualified name in .NET v2.0 has now 5 components: name (test), version (0.0.0.0), culture (neutral), public key token (...) and processor architecture (MSIL). Two other useful features (flags at the command line) are:
- Scenarios: used to generate native images that can be used by a debugger (/debug) or a profiler (/profile) or to generate a minimum number of native images by not ngen-ing dependencies (/nodependencies).
- Config: /ExeConfig to point to a configuration file (.exe.config) that contains additional information used by ngen and /AppBase to override assembly probing settings by specifying an "appbase directory" to search for assemblies in.
Another useful action is the ngen display action. An example is shown below:
C:\temp>ngen display test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
NGEN Roots:
C:\temp\test.exe
NGEN Roots that depend on "C:\temp\test.exe":
C:\temp\test.exe
Native Images:
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Using verbose output (add /verbose) you get a lot more information however:
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
NGEN Roots:
C:\temp\test.exe
ScenarioDefault --no debug or profile scenario present
C:\temp\test.exe
DisplayName = test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Native image = {CC9FE28A-004D-38EB-82F9-3D97AB21A051}
Hard Dependencies:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Soft Dependencies:
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null --what we were looking for; "forward dependency"
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
DisplayName = mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Native image = {DAAB7D0D-ABB0-394D-82EF-037B571B1032}
Hard Dependencies:
Soft Dependencies:
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
DisplayName = testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Native image = {346E10F6-8E71-3605-91A2-C732FC2D5866} --the location of testhelper can be derived from the GUID: F6106E34718EA29166582DFC32C7 by a bytewise revert of each "GUID group"
Hard Dependencies:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Soft Dependencies:
--Note: In the end, the information shown above forms a tree of dependencies. Try doing the same on an application that uses e.g. System.Data.DataSet.
NGEN Roots that depend on "C:\temp\test.exe":
C:\temp\test.exe
ScenarioDefault
C:\temp\test.exe
DisplayName = test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Native image = {CC9FE28A-004D-38EB-82F9-3D97AB21A051}
Hard Dependencies:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Soft Dependencies:
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
DisplayName = mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Native image = {DAAB7D0D-ABB0-394D-82EF-037B571B1032}
Hard Dependencies:
Soft Dependencies:
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
DisplayName = testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Native image = {346E10F6-8E71-3605-91A2-C732FC2D5866} --the location of testhelper can be derived from the GUID: F6106E34718EA29166582DFC32C7 by a bytewise revert of each "GUID group"
Hard Dependencies:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Soft Dependencies:
Native Images:
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Source MVID: {C456F353-332D-401F-B9FC-93495C519EB1}
Source HASH: f9149373069fb3e81111bb24db59018bc2d48d98
NGen GUID sign: {CC9FE28A-004D-38EB-82F9-3D97AB21A051}
OS: WinNT
Processor: x86(Pentium 4) (features: 00008001)
Runtime: 2.0.50215.44
mscorwks.dll: TimeStamp=42578752, CheckSum=0053D2C1
Flags:
Scenarios: <no debug info> <no debugger> <no profiler> <no instrumentation> --try to add other scenarios as explained earlier
Granted set: <PermissionSet class="System.Security.PermissionSet"
version="1"
Unrestricted="true"/>
File: C:\WINDOWS\assembly\NativeImages_v2.0.50215_32\test\8ae29fcc4d00eb3882f93d97ab21a051\test.ni.exe --the location of the native image
Dependencies:
mscorlib, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089:
Guid:{7125636A-C067-4930-9DA0-DCD6DC6A10A9}
Sign:66c33e7153140d9397fd66ecb5d9c4b19f00e8e3
Hardbound Guid:{DAAB7D0D-ABB0-394D-82EF-037B571B1032}
testhelper, Version=0.0.0.0, PublicKeyToken=null:
Guid:{58EDC827-7258-43EF-BD02-B694FA4C806C}
Sign:0cd07a972e90d8faf86ec768d0705a17211306d3
The NGen service
Time to move on to another piece of the renewed NGen technology, being the ".NET Runtime Optimization Service". What's in a name? It's a service and it's used to optimize the .NET Runtime. So, what about looking at the SCM MMC using services.msc? The first service in the list that you should see is the following:
- Service Name: clr_optimization_v2.0.50215_32
- Display Name: .NET Runtime Optimization Service v2.0.50215_X86
- Description: Provides support for optimizing managed assemblies using NGEN technology.
- Path to executable: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215\mscorsvw.exe
People who are somewhat familiar with services will notice that the recovery settings are rather "exceptional": on every failure, the service is restarted and there's a pretty agressive recovery policy. By default, the service will have a Manual startup type, but the service itself changes this when needed (see further). Now, what's this service all about?
Imagine an application you want to ngen when it's installed but you don't want to wait for the entire ngen compilation to complete at setup time. In other words, some asynchronous triggering of the ngen compilation mechanism for some application. This is the scenario for which this service was made: to perform IL-to-native code compilations in the background when the system is idle or when ngen compilation is enforced through ngen.exe.
Let's go through a end-to-end scenario using the NGen service:
- Make sure all test.exe, test2.exe and testhelper.dll native images are deleted from the system by running ngen uninstall on each of these assemblies. When doing so, make sure no other command prompt is active in the NGen cache folders for these assemblies' native images.
- First, query the service status. In my case this is the output:
C:\temp>sc queryex clr_optimization_v2.0.50215_32
SERVICE_NAME: clr_optimization_v2.0.50215_32
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 0
FLAGS :
If the service is running, it has work to do. In that case, execute the following command to "purge" the queue of outstanding work (note this can take a while and will cause high CPU usage):
C:\temp>ngen executeQueuedItems 3
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
(...)
If there was work to do and the service is still running, reboot the machine (just for sake of the demo). Next time the service should be stopped and have a startup type of Manual.
- Now we'll ngen the test.exe file, not directly but deferred. In order to do this, we need to execute the ngen install action but with the /queue flag:
C:\temp>ngen install /queue test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Installing assembly C:\temp\test.exe
Compare this with earlier executions of ngen install without the /queue flag. The assembly is not being compiled directly right now.
- Go to the C:\WINDOWS\assembly\NativeImages_v2.0.50215_32 folder in the another command prompt window. You should find no subfolder called "test" in there. Native image compilation has not been done yet...
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32
File Not Found
- Now run the ngen display action for the test.exe assembly:
C:\temp>ngen display test.exe
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
NGEN Roots:
C:\temp\test.exe (StatusPending) (Pri 3)
Native Images:
This output indicates that only the root of test.exe is known to the system and the status of its compilation is pending with priority 3 (see further).
- Query the service status again. It's now alive (and kicking?):
C:\temp>sc queryex clr_optimization_v2.0.50215_32
SERVICE_NAME: clr_optimization_v2.0.50215_32
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE,PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 3040
FLAGS :
- When you investigate the task list, you'll find one instance of mscorsvw.exe, as shown below:
C:\temp>tasklist /FI "IMAGENAME eq mscorsvw.exe"
Image Name PID Session Name Session# Mem Usage
========================= ====== ================ ======== ============
mscorsvw.exe 3040 Console 0 3,064 K
This is the service which is running. You can also check the state of the service as follows, using ngen.exe:
C:\temp>ngen queue status
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Service name is: clr_optimization_v2.0.50215_32
The .NET Runtime Optimization Service is running.
- In step 5, I've shown that the test.exe compilation is pending and has a priority of 3. This means the service is waiting till the computer is idle (which is measured based on the time of the last user input and the state of a screensaver, but this "idleness detection mechanism" is still to be finetuned towards RTM of .NET v2.0) in order to start working on priority 3 jobs that are in the queue. However, you can force this work to be done immediately, using the following command:
C:\temp>ngen executeQueuedItems 3
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Compiling 2 assemblies:
Compiling assembly C:\temp\test.exe ...
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Compiling assembly testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null ...
testhelper, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Note: While this command is running (you need to be quick to see), another instance of mscorsvw.exe will be created (watch your Task Manager task list, sorted by Image Name).
- When you inspect the NGen cache now, you should find the following entries:
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test*
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32
09/01/2005 01:24 AM <DIR> test
09/01/2005 01:24 AM <DIR> testhelper
0 File(s) 0 bytes
2 Dir(s) 119,775,739,904 bytes free
- In order to visualize the difference between priority 1, 2 and 3 perform now the following:
C:\temp>ngen install test2.exe /queue:1
Microsoft (R) CLR Native Image Generator - Version 2.0.50215.44
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Installing assembly C:\temp\test2.exe
- Go to the other command prompt window. Because the priority was set to 1, the service is performing the compilation immediately, as you can see by showing the test* contents of the NGen cache:
C:\WINDOWS\assembly\NativeImages_v2.0.50215_32>dir test*
Volume in drive C has no label.
Volume Serial Number is DC7C-7836
Directory of C:\WINDOWS\assembly\NativeImages_v2.0.50215_32
09/01/2005 01:24 AM <DIR> test
09/01/2005 01:29 AM <DIR> test2
09/01/2005 01:24 AM <DIR> testhelper
0 File(s) 0 bytes
3 Dir(s) 119,775,760,384 bytes free
I won't cover the other ngen.exe capabilities (such as the update action) over here for now. However, based on what I've shown above, you should have a good clue about the power the renewed ngen technollogy is offering in .NET v2.0. A classic scenario is queuing up precompilation work for a set of assemblies associated with your application at installation time. You'll queue compilation of the most critical files using priority 1 or 2 whileas you'll queue up compilation for the other executables (e.g. less used tools) using the default priority of 3 (compile during idle time). At installation time, you'll benefit from both queue-ups because the installer does not need to wait for the ngen tasks to complete (the service does the work in the background for you). The general skeleton looks like this:
ngen queue pause --keep the NGen image cache stable during setup (recommended)
ngen install <...> /queue --default priority = 3; recommended for less-used apps
ngen install <...> /queue:1 --enforce high priority compilation
ngen queue continue --okay, the NGen service can continue its mission
NGen: use it or leave it?
The official answer: it depends. The correct answer: it depends. You should measure the performance of both the JITted application and the NGen-ed application and compare the results in order to get a clue about the performance gains for your application. Purely theoritically, the following statements hold:
- Precompiled applications require less memory because the JIT compiler doesn't need to be loaded into memory.
- Precompiled applications can benefit from sharing memory pages for shared code across applications (i.e. DLLs). This also reduces memory consumption.
- (Warm) startups of precompiled applications are faster than their non-JITted equivalents.
Furthermore, in v2.0 NGen has support for sharing of native images across application domains and all of the reflection stuff on native images. For a discussion on "hardbinding", I want to refer to the MSDN Article mentioned below in the "Useful links" section.
Useful links
Conclusion
Visual Studio 2005 is great, but don't forget about the .NET Framework SDK tools in .NET v2.0. There are just so many improvements in there (in the end, these tools are the core of the .NET Framework), it would be a pitty for you to miss any of these improvements. I'll try to point out things like this on a regular basis on my blog.