5

We are taking a hit the first time some heavy UI screens are loaded. Our project is divided into one main executable and several DLL files. The DLL files can also contain UI screens which are slow the first time they are loaded.

Is there a way (in code) we can preload all the referenced assemblies so as to avoid the JIT compilation hit?

I know there is a tool called NGen. Is it possible to operate NGen in a development environment so we can see its effects instantly? Ideally though, we would like to preload the referenced assemblies from code.

Using C# .NET 3.5 along with DevExpress for our UI components.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Wozart
  • 125
  • 1
  • 7

5 Answers5

8

I personally found that putting the pre-jitter in 'Program' helped in a certain application, but that is a situation-specific question.

More importantly, the code in wal's answer will crash when it encounters an abstract method, so two lines of code have been added to skip abstract methods.

static Program()
{
    foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
    {
        foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly |
                            BindingFlags.NonPublic |
                            BindingFlags.Public | BindingFlags.Instance |
                            BindingFlags.Static))
        {
            if ((method.Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract|| method.ContainsGenericParameters)
            {
                continue;
            }
            System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
        }
    }
    Console.WriteLine("jitted!");
}
Cameron
  • 2,903
  • 1
  • 30
  • 31
7

Did you try/look at this?

That is, do the following for each assembly you want to pre JIT.

static void PreJIT()
{
    foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
    {
        foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly |
                            BindingFlags.NonPublic |
                            BindingFlags.Public | BindingFlags.Instance |
                            BindingFlags.Static))
        {
            System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
wal
  • 17,409
  • 8
  • 74
  • 109
  • My testing says that `PrepareMethod` isn't the same as calling the method as far as JITting and optimization is concerned. – NetMage Feb 26 '19 at 00:02
6

Take a look at NGen. Another option is to use ILMerge to merge all your assemblies into one. Whenever I use ILMerge, I add a post build command to so it happens automatically. The other alternative (untested) is, if you don't mind a longer start-up time, you could manually call Assembly.Load() at the beginning for each assembly.

Bala R
  • 107,317
  • 23
  • 199
  • 210
  • We have looked into ILMerge and when we release into production will be merging all the assemblies into one larger executable. I guess the real question is can we see the benefits of NGEN whilst still in the development environment? – Wozart Mar 03 '11 at 02:07
  • 2
    Loading assembly will not JIT most of the methods (if any). It will force disk access time/assembly loading itself to happen earlier. – Alexei Levenkov Mar 03 '11 at 02:07
  • 1
    Using `Assembly.Load()` won't help in any way. Take a look at [my question](http://stackoverflow.com/questions/1159192/howto-load-assemby-at-runtime-before-assemblyresolve-event). – Oliver Apr 18 '11 at 14:47
1

You can just create instances of the classes located in externall assemblies. Just call the constructor in a limited scope (I mean declare the variable inside a function. It should not be global var because it will delay GC to dispose that instance). This will load the assembly, compile it and cache it. You can even do this in a background thread so the main thread will keep responsiveness.

Davita
  • 8,928
  • 14
  • 67
  • 119
0

You can use NGen on any machine - there is no notion of "development enviroment" in CLR... When you use it make sure that NGen'ed images are actually used (see Native Image Generator (Ngen.exe) for instructions and look for FusLogVw note in the document).

You can also pre-JIT through invoking all the code you expect to run (as Davita suggested), but you'll need to invoke each and every method of all classes which in not exactly practical.

You should profile your application to see where time is actually spent - it could be reading of the assemblies from the disk, not JITing itself... You can roughly see it by starting the application, looking at the forms, closing the application and repeating steps. If the second run is much faster then the application spends most of the time reading from the disk, not JITing.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Alexei, thank you for your comments. If we close the application every time we load a form for the "first" time, it is slow. Every subsequent call to load the form happens very quickly. It's the same result every time we compile the application and run it. – Wozart Mar 03 '11 at 02:21
  • Than it is most likely JIT - NGEN should help. – Alexei Levenkov Mar 03 '11 at 02:57