.NET Release is very slow when starting a method for the first time. How to fix this with NGEN?

I deployed the application in release mode (x64), which I expected would be fast, and I noticed that there is a serious slowdown whenever a new method or set of methods is executed for the first time. When I say β€œharsh”, I mean 100-200 ms to execute for the first time, and after that it takes less than 1 ms.

From what I found, it seems to be related to the JIT compiler, which should compile the methods on first run. I expected some delay from this, but 100ms is a catastrophic delay in the middle of execution.

I know about NGen, but NGen needs to be done during installation on a machine. Machines for all have limited user rights and cannot install anything. The application is deployed as an executable and reference DLL. I think that’s why I was never able to get NGen to work.

Is there a way to get JIT to compile each method at startup?

Although I create dummy variables, I add a start-up procedure that would do nothing but run each method once, so it might be that when you start the run. It would be enough to force compile or each method code path needs to be executed separately.

+2
source share
3 answers

Wow. Such delays are unusual for JIT. Profile your application to make sure the bottleneck is JIT.

Now, if it's really JIT, here is a much better method than adding a dummy argument everywhere:

Use RuntimeHelpers.PrepareMethod for each non-generic method. This function will force JIT to process it.

You can also use the RunClassConstructor method for each class ... well, run your static constructors.

Here is some (completely untested) code:

 foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { if (type.IsGenericTypeDefinition || type.IsInterface) continue; RuntimeHelpers.RunClassConstructor(type.TypeHandle); foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) RuntimeHelpers.PrepareMethod(method.MethodHandle); } 
+3
source

NGen should be run on each machine during installation. Make it part of the installation process. This will be compiled for the appropriate architecture.

If your delay is really related to JITting, this should solve it. Profile your application to be sure.

0
source

My first solution was to manually create dummy instances of classes, and then call methods with the optional dooly bool variable, which would be false by default. It worked, but it was required to add this dummy for each method, which is crude and time consuming.

Lucas Trzesniewski's answer is much wider, since it prepares all classes and all methods in the code, and it does not require any changes in any of my code, so it is much easier to implement. The only cost is that, being so thorough, it takes more time for a period of 0.5 to 1.5 seconds, or maybe 0.5 seconds longer than my selective launch. Moreover, in my case, it is worth it to guarantee that there are no delays in the code.

There was no noticeable burst of memory or CPU usage other than the initial start-up, and memory usage actually decreased slightly, perhaps because now all the codes are executed and optimized.

0
source

Source: https://habr.com/ru/post/1201256/


All Articles