Sunday, March 15, 2009

Jitting at runtime (Jit methods on the fly)

What is Jit



Jit stands for Just in time complication. You can read more about JIT here. However, the idea is that the
code is not fully complied, it is pre-complied. The first time your method is executed, the .NET runtime checks if the method has been complied for the target machine, if it did not then it compiles it on the fly. This is called JIT. This behaviour also causes a delay when executing methods for the first time. The bigger the method, the bigger the delay. I have noticed this delay the most when doing UI applications, the generated code would take a long time to JIT. You can also add performance counters to see how much time your application is jitting. In fact most classes that use generated code, can be good candidate for jitting (typed dataset, UI screens, EDMX...)



NGen


NGen is the alternative solution to runtime Jitting. Everything is complied by the NGen tool and a compiled image is placed within the GAC. At runtime when loading the assembly, the runtime will check for a compiled image based on the assembly name and version, if it finds one it will load it without Jitting. Still, NGen needs to run on the target machine before running the application. NGen is also not as efficient as Jit, that's because Jit executes at runtime and has much more information about the method and how to optimize it. You can read more about NGen here.


Is it possible to control the Jitting



I always wanted to have something to control the jitting at runtime. Similar to the GC class, I can control at runtime when the GC is executed, there is not built in class called Jit that will allow me to Jit certain methods. However, it is possible. The method that allows for this type of functionality is RuntimeHelpers.PrepareMethod Method (RuntimeMethodHandle). However, here is a little warning for you all, in the MSDN article it indicates: The classes in System.Runtime.CompilerServices are for compiler writers' use only.. Still, I decided to use it, there are times that I would like to control when Jitting happens.



JitHelper and the PreJit attribute



The idea is very simple. I want to have a helper class that will jit any method that is marked with an attribute of PreJit. Normally the coder knows which are the heavy methods, this way the coder has the control of marking methods that can take long to jit. For example:


[PreJit]
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "Form1";
}


Notice the PreJit attribute on the method.

PreJit is just a marker attribute. Here is the code for it.


[AttributeUsage(AttributeTargets.Method)]
public class PreJitAttribute : Attribute
{
public PreJitAttribute()
{

}
}



Now, all that is left to do is Jit the methods that are marked with the [PreJit] attribute. Lets take a look at one method that handle jitting based on the type of a CLR class.




private static void PreJitMarkedMethods(Type type)
{
// get the type of all the methods within this instance
var methods = type.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static);

// for each time, jit methods marked with prejit attribute
foreach (var method in methods)
{
// checks if the [PreJit] Attribute is present
if (ContainsPreJitAttribute(method))
{
// jitting of the method happends here.
RuntimeHelpers.PrepareMethod(method.MethodHandle);
}
}
}

// (helper method) checks if the [PreJit] attribute is present on a method
private static bool ContainsPreJitAttribute(MethodInfo methodInfo)
{
var attributes = methodInfo.GetCustomAttributes(typeof(PreJitAttribute), false);
if (attributes != null)
if (attributes.Length > 0)
{
// attribute found return true
return true;
}

return false;
}


Lets note the important stuff. This method is able to jit all marked methods with the PreJit attribute based on a CLR type




  • Getting all methods, private, public and even static

  • Only Jit methods that have an attribute of [PreJit]
  • On each method we get the MethodInfo object

  • Passing MethodInfo.MethodHandle to PrepareMethod allows us to jit a method



The Jitter



Now that it is possible for me to jit every method within a type, all I have to do is create high level
methods that will allow me to do the following:




  • Jit only methods that are marked with PreJit attribute

  • Jit on a different thread

  • Jit based on an instance (Jit methods within the instance)

  • Jit based on a Type (Jit methods for a given class type)

  • Jit based on an assembly (Jit methods within all the classes in an assembly



Lets see the full class code for the Jitter

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Runtime.CompilerServices;

namespace JitHelper
{
public class Jitter
{
public static void PreJit(object instance)
{
PreJitMarkedMethods(instance.GetType());
}


public static void PreJitAll(object instance)
{
PreJitAllMethods(instance.GetType());
}

public static void BeginPreJitAll(object instance)
{
Thread preJitThread = new Thread(() =>
{
PreJitAllMethods(instance.GetType());
});

preJitThread.Name = "PreJittingThread";
preJitThread.Priority = ThreadPriority.Lowest;
preJitThread.Start();

}

public static void PreJit() where T : class
{
PreJitMarkedMethods(typeof(T));
}


public static void PreJitAll() where T : class
{
PreJitAllMethods(typeof(T));
}

public static void BeginPreJitAll() where T : class
{
Thread preJitThread = new Thread(() =>
{
PreJitAllMethods(typeof(T));
});

preJitThread.Name = "PreJittingThread";
preJitThread.Priority = ThreadPriority.Lowest;
preJitThread.Start();
}

public static void PreJitAll(Assembly assembly)
{
var classes = assembly.GetTypes();
foreach (var classType in classes)
{
PreJitAllMethods(classType);
}
}

public static void BeginPreJitAll(Assembly assembly)
{
Thread preJitThread = new Thread(() =>
{
PreJitAll(assembly);
});

preJitThread.Name = "PreJittingThread";
preJitThread.Priority = ThreadPriority.Lowest;
preJitThread.Start();
}


public static void PreJit(Assembly assembly)
{
var classes = assembly.GetTypes();
foreach (var classType in classes)
{
PreJitMarkedMethods(classType);
}
}


public static void BeginPreJit(Assembly assembly)
{
Thread preJitThread = new Thread(() =>
{
PreJit(assembly);
});

preJitThread.Name = "PreJittingThread";
preJitThread.Priority = ThreadPriority.Lowest;
preJitThread.Start();
}

public static void BeginPreJit(object instance)
{
Thread preJitThread = new Thread(() =>
{
PreJit(instance);
});

preJitThread.Name = "PreJittingThread";
preJitThread.Priority = ThreadPriority.Lowest;
preJitThread.Start();
}

private static void PreJitMarkedMethods(Type type)
{
// get the type of all the methods within this instance
var methods = type.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static);

// for each time, jit methods marked with prejit attribute
foreach (var method in methods)
{
if (ContainsPreJitAttribute(method))
{
// jitting of the method happends here.
RuntimeHelpers.PrepareMethod(method.MethodHandle);
}
}
}


private static void PreJitAllMethods(Type type)
{
// get the type of all the methods within this instance
var methods = type.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static);

// Jit all methods
foreach (var method in methods)
{
// jitting of the method happends here.
RuntimeHelpers.PrepareMethod(method.MethodHandle);
}
}


private static bool ContainsPreJitAttribute(MethodInfo methodInfo)
{
var attributes = methodInfo.GetCustomAttributes(typeof(PreJitAttribute), false);
if (attributes != null)
if (attributes.Length > 0)
{
return true;
}

return false;
}
}
}


A few notes about the code:


  • Methods beginning with "Begin" are executed on a low priority thread. This allows for background jitting. I have not done a callback feature to know when jitting ends, I don't think it is required, but you are free to modify the class and add it.

  • Method ending with "All", will Jit all methods and not just the one marked as PreJit attribute

  • Not all methods can be PreJit, for example methods marked as DllExport are not .NET methods, so be careful with the All feature. For performance reasons I have not checked for DllExport attribute, but you can add it if needed.

  • Notice that one method uses generics, this is simply so the caller can pass the type via generic without doing typeof operator.



Using the Jitter



I will simply show you an exmaple, the following example everything within Form1 is pre-Jitted.


[STAThread]
static void Main()
{
// Jitting all the methods within Form1 class.
Jitter.PreJitAll();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}


if you want to pre-jit within a thread, then simply use:


[STAThread]
static void Main()
{
Jitter.BeginPreJitAll();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}


Benchmarking


It is not that simple to benchmark this type of code because it really depends how your application works. However, the Jit operation happends the first time a method is executed. So the first time of any method will cause a delay. I have created a windows form full of text boxes controls, and I used the Jitter to Jit everything within the form class. On the form show event I display the time it took to show the form:

Without using the jitter: ~0.12 milliseconds
With the Jitter: ~0.12 milliseconds
Timing after Jitting: ~0.09 milliseconds


  • With the Jitter or without it, it took about the same amount of time to show the form.

  • Without timing the Jitter, just the load operation after the Jit, it took 0.09 miliseconds to show

  • Overall it means that the Jitter class can have a significate performance improvment at runtime, if a class is jitted before it is being used.


Conclusion




Let me first say that I coded this class mostly because I wanted to have the control over Jitting. But overall .NET runtime does a very good job Jitting when needed. The same way we should not call GC.Collect() we should not call Jitting functions. Having said that, there are times it would be nice to control Jitting and have an alternative to NGen. Use this tool only if you have a performance issue, or a startup timing issue. If you do not have a performance issue - do not use this. This class also uses reflection to find out the methods to Jit. Reflection is slow, which is another reason to avoid using this class unless required. You should consider trying pre-jitting your classes when you are using generated code classes, such as typed dataset, LINQ to entities, or winform UI classes.

Even if you are not planning to use the Jitter class, it is better to have the Jitter class and not need it, then need it and not have it.

Thank you for reading. Have a nice day, and happy .Netting.



2 comments:

RRave said...

Dear Friends,



I hope you are doing well. I got this email address from one of your contribution web site. I have launched a web site www.codegain.com and it is basically aimed C#,JAVA,VB.NET,ASP.NET,AJAX,Sql Server,Oracle,WPF,WCF and etc resources, programming help, articles, code snippet, video demonstrations and problems solving support. I would like to invite you as an author and a supporter.
Looking forward to hearing from you and hope you will join with us soon.


Thanks & Best Regards,
RRaveen,
Founder CodeGain.com,
http://www.codegain.com.

Anonymous said...

Thanks a lot for this post!!

I am working with VB.NET, not with C#, so I'll have to do some translating, but this will help a lot!!

I'm writing a code to do dynamic simulations. It is written in 1 .dll-file that contains a few classes. Each class contains a set of functions that repeatedly call eachother (also from one class to the other) within every timestep of the simulation. One single simulation-run will often count a few 10.000 or even 100.000 of those timesteps. Therefore, I suspect that pre-JITting the whole .dll (all functions of all classes of it), at the initial launch of the simulation, might considerably improve performance, rather than letting the JIT-compiler do it's work every time it encounters a certain function of a certain class within one simulation-run. (I'd rather not use ngen.exe, for portability reasons and so.)

Is this correct, or is the JIT-compiler able to 'memorise' all the JITting it did during the first time-step, meaning that only the first of the 100.000 timesteps will be slower?

Thanks a lot for the whole bunch of info and the codes on your post!