 |
|
|
Hiya! What you are effectively presenting in your article is a code snippet with very little explanation of how to actually use it. And even then, it seems you haven't tested it enough to determine that, e.g., abstract methods cannot be jitted (somewhat obvious). You also don't take care of permissions, do not handle exceptions, and do not include cancellation of any sort. So if a developer on my project added this sort of code I'd be, well, not upset, but I would very much like an explanation of precisely why this type of method-wise prejitting was chosen as opposed to some other method. I'd also need proof that all potential errors are mitigated so that a customer doesn't get an ArgumentException when some late-bound assembly fails to pre-JIT.
Still, I don't want to appear more negative than I should - after all, this post gave me some food for thought, and for that I'm thankful. 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The intention was not to provide piece of production-ready code (well tested and all-possible-situations-and-exceptions-ready code). I just wanted to show an idea, an example how to do it. That's it. And that's the reason article is posted in HOW-TO section. If anyone would pay me for that - I'd provide code snippet you would be surprised by!
I don't mind some criticism . Thanks for feedback. Nothing personal.
Vitaliy Liptchinsky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
System.EntryPointNotFoundException
-----------------
Der Einstiegspunkt "TaskDialogIndirect" wurde nicht in der DLL "ComCtl32" gefunden.
-----------------
bei System.Runtime.CompilerServices.RuntimeHelpers._PrepareMethod(IntPtr method, RuntimeTypeHandle[] instantiation) bei ZetaTest.Main.Code.AppHost.Host.b__4() in C:\Users\ukeim\Documents\Visual Studio 2008\Projects\Zeta Test\Zeta Test Main\Source\Main\Code\AppHost\Host.cs:Zeile 780. bei System.Threading.ThreadHelper.ThreadStart_Context(Object state) bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) bei System.Threading.ThreadHelper.ThreadStart()
EntryPointNotFoundException { Message="Der Einstiegspunkt \\"TaskDialogIndirect\\" wurde nicht in der DLL \\"ComCtl32\\" gefunden.", TypeName="", Data=ListDictionaryInternal { Count=0, Keys=NodeKeyValueCollection { }, IsReadOnly=False, IsFixedSize=False, IsSynchronized=False, SyncRoot=Object { }, Values=NodeKeyValueCollection { } }, InnerException=null, TargetSite=RuntimeMethodInfo: _PrepareMethod, StackTrace=" bei System.Runtime.CompilerServices.RuntimeHelpers._PrepareMethod(IntPtr method, RuntimeTypeHandle[] instantiation)\\r\\n bei ZetaTest.Main.Code.AppHost.Host.b__4() in C:\\Users\\ukeim\\Documents\\Visual Studio 2008\\Projects\\Zeta Test\\Zeta Test Main\\Source\\Main\\Code\\AppHost\\Host.cs:Zeile 780.\\r\\n bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)\\r\\n bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\\r\\n bei System.Threading.ThreadHelper.ThreadStart()", HelpLink=null, Source="mscorlib" }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Uwe,
I'm only 5 months in Austria and Ich spreche Deutsch nicht so gut 
But from what I understand you are trying to pre-JIT method with external implementation (like marked with DLLImportAttribute). Am I correct? Generally I would avoid pre-JITing of such methods.
Vitaliy Liptchinsky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks, Vitaliy, I only tried it on a German Windows, so therefore the error messages in German only.
I do not know how this happend, I just called your code.
Maybe I must omit further methods?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
What did the trick:
... var attributes = method.GetCustomAttributes( typeof( DllImportAttribute ), false );
// Ignore DllImport attributes. if ( attributes == null || attributes.Length <= 0 ) { RuntimeHelpers.PrepareMethod( method.MethodHandle ); } ...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Chris Richner wrote: http://www.codeproject.com/script/Forums/View.aspx?fid=783605&msg=2831349[^]
Sorry, Chris. Not sure I understand this...
Vitaliy Liptchinsky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
No Problem, Vitaliy.. it's related to the System.EntryPointNotFoundException that was mentioned in the thread. I'm facing the same exception when I try to use Task Dialog API if no message loop is running.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I found this post to be very useful. I did find that when loading referenced assemblies it is useful to wrap the PrepareMethod in a try/catch block as the call may fail with an exception of some kind. Since I am using some 3rd party assemblies in my project, you never know how they may fail.
For example, I have a dependency on mscorlib where Win32Native/FindNLSString generates the following exception
System.EntryPointNotFoundException: Unable to find an entry point named 'FindNLSString' in DLL 'kernel32.dll'. at System.Runtime.CompilerServices.RuntimeHelpers._PrepareMethod(IntPtr method, RuntimeTypeHandle[] instantiation) at System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(RuntimeMethodHandle method)
Just a suggestion
Neil Lamka neil@meetingworks.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Nice article mate.
If you all havent caught up with PDC2008 then Anders gave a fantastic presentation on Future of C# and he showed that in C# 5.0 they are going to expose the compiler. ie. you can use Compiler as Service.
You can watch the video here.. I recommend it for every C# user. WMV-HQ[^] | WMV[^] | Zune[^]
------------------------------------------------------------------ Life would have been much easier if I had the source-code!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Nice solution, but I think the best soultion is creat a small loader, when the user start the app, the loader first loaded and then display a animation to indicate the user the app doing something in background.
The God created the world. The programer made the world easy.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
First of all: this is one of the coolest things I ever saw in here
I took it as is, and place it into my 80+ assemblies client, and I must say it looks like it does response better. I did a very non scientific measurements using my logs, and saw about ~20% improvement overall.
Some notes about the snippet:
1) As others has mentioned here earlier, it is important to protect from abstracts and generics at the method level. I avoided interfaces and generic definition at type level to make it a bit more efficient.
2) I found out that this PrepareMethod method actually initiate the type itself. This gave me trouble in places where I had code in a static constructor, so I ignored types with static constructors all together.
3) Last, but not least, I used it to prepare all the assemblies referred to by my bootstrap, skipping the ones from the Global-Cache (a decision that might not fit everyone).
For reference, this is my version:
Thread jitter = new Thread(delegate() { foreach (System.Reflection.AssemblyName an in System.Reflection.Assembly.GetEntryAssembly().GetReferencedAssemblies()) { System.Reflection.Assembly asmb = System.Reflection.Assembly.Load(an); if (!asmb.GlobalAssemblyCache) { foreach (Type type in asmb.GetTypes()) { if (!type.IsInterface && !type.IsGenericTypeDefinition) { //must initiate only classes without static constractors System.Reflection.ConstructorInfo ci = type.GetConstructor( System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (ci == null) { foreach (System.Reflection.MethodInfo method in type.GetMethods( System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Static)) { if (!method.IsAbstract && !method.IsGenericMethodDefinition && !method.ContainsGenericParameters) System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); } } } } } } }); jitter.Priority = ThreadPriority.Lowest; jitter.Start();
Ittay Ophir levi_rami@yahoo.com
modified on Wednesday, December 3, 2008 9:14 AM
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Hi Ittay.
Thanks for your feedback. I really appreciate it.
---->>> 2) I found out that this PrepareMethod method actually initiate the type itself. This gave me trouble in places where I had code in a static constructor, so I ignored types with static constructors all together.
PrepareMethod does not initiate class itself. Class is initiated when it is referenced first time. Here all classes are initiated in assembly.GetTypes() method. Which problems did you have with static constructors?
Vitaliy Liptchinsky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm sorry, but I think you are mistaken
The static constructor is not called on GetTypes(), but it is on PrepareMethod.
This super simple console test will prove it:
namespace PreCompile { class Program { static void Main(string[] args) { /* run it once with "true" and once with "false"... */ bool prepareMethod = false; /* when true: Starting... (with prepareMethod == True) ClassWithStaticConstructor lives!!! Started Ended when false: Starting... (with prepareMethod == False) Started ClassWithStaticConstructor lives!!! Ended */ Console.WriteLine("Starting... (with prepareMethod == {0})", prepareMethod); foreach (Type type in Assembly.GetEntryAssembly().GetTypes()) { if (!type.IsInterface && !type.IsGenericTypeDefinition) { foreach (MethodInfo method in type.GetMethods( BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if (!method.IsAbstract && !method.IsGenericMethodDefinition && !method.ContainsGenericParameters) { if (prepareMethod) RuntimeHelpers.PrepareMethod(method.MethodHandle); } } } } Console.WriteLine("Started"); ClassWithStaticConstructor.WakeUp(); Console.WriteLine("Ended"); Console.ReadKey(); } }
public class ClassWithStaticConstructor { static ClassWithStaticConstructor() { Console.WriteLine("ClassWithStaticConstructor lives!!!"); } public static void WakeUp() { } } }
Thanks
Ittay Ophir levi_rami@yahoo.com
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Yep, you are right. I think I missed it. Reflection does not instantiate the class, only reads metadata.
Thanks for sample!
Vitaliy Liptchinsky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
As for the problem I had, it have to do with bad code design on my classes, so it is not relevant.
It is true that usually there should be no problem with static-constructors, even when called from this preparation routine.
Ittay Ophir levi_rami@yahoo.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I like your approach best. But you miss prejitting the entry assembly itself. I had to change your first Iteration to include the entry assembly like this:
List assemblynames = new List(Assembly.GetEntryAssembly().GetReferencedAssemblies()); assemblynames.Add(Assembly.GetEntryAssembly().GetName()); foreach (AssemblyName an in assemblynames) { ... }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Getting errors on static methods and generic paramaterised methods. Fixed with the following alteration.
Thread jitter = new Thread(() => { foreach (var type in Assembly.GetEntryAssembly().GetTypes()) { foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance )) { if (!method.IsAbstract && !method.IsGenericMethodDefinition && !method.ContainsGenericParameters ) { System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); Console.WriteLine("{0} {1}", type.Name, method.Name); } } } }); jitter.Priority = ThreadPriority.Lowest; jitter.Start();
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
better....
foreach (Type type in Assembly.Load(asm.FullName).GetTypes()) { if (type.ContainsGenericParameters) continue;

|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Guys!
Thanks a lot for fixes!  Honestly, I haven't tested it with static and generic methods...
Vitaliy Liptchinsky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hello,
It would be nice to see some benchmarks to compare time needed to load an application with the method you described and without it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Just tried it and the time to load the application is nearly the same, but the performance of loaded Forms and TabPages is great during their first call. You can see it with your eye-brain-benchmark-timer 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |