Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ngen vs RyuJIT - fastest x64 running code when (pre-)startup does not matter

Are Ngen and RyuJIT two completely unrelated things under .NET 4.6 (especially with different optimization techniques and algorithms)?

What produces fastest (better optimized) x64 native code if we do not care about the cost of jitting itself and/or cold/warm startup time?

We are running a long running server app. The continuous running phase is very important performance-wise. The (pre-)startup phase is unimportant for us. Until now we have been on .NET 4.5 and always generated native images by Ngen. We are now in process of upgrading to .NET 4.6 and we want to be sure that this doesn't downgrade the performance of our continuous running phase. I have read some info that RyuJIT is great choice for improving the JITing time, but that the jited code can be less optimized compared to Ngen - see e.g. this github comment on one of the RyuJIT bugs.

like image 253
Jan Avatar asked Nov 11 '15 09:11

Jan


1 Answers

There is not enough difference between NGen and RyuJIT to make you happy. They do very different jobs, NGen jits ahead-of-time and RyuJIT jits in-time while the process is running. But NGen does not have its own jitter, it asks RyuJIT to get the job done. The generated machine code is not fundamentally different. There are a few optimizations that cannot be done up front, NGen-ed code is slightly slower.

Technically NGen could do a better job since the optimizer could spend more time analyzing the code and trying to find the best possible optimization. But Microsoft does not take advantage of this. It is not completely crystal why they don't but surely has something to do with their 1-800 support phone number. Code optimization is always the riskiest part of a code generator and the bugs in the existing jitters have always been optimization bugs. That this might change some day is not unthinkable.

You'd be ahead when you could take advantage of .NET Native. It generates code ahead-of-time with the back-end of the C++ compiler. But currently, and surely for quite a while to come, it is only supported for packaged apps. The kind that are delivered through the Windows Store, you'll have to target Store, Phone or Universal and use the Store as the deployment vehicle. The package is very important to make .NET Native work, only decent way that it can see what code needs to be translated. And it often still needs help to get it right, Reflection is a difficult problem to solve, the reason that you have it on your machine. Note that the same problem doesn't exist for NGen, it still relies on the jitter to get some code jitted in-time. Like Reflection target code and generics. That this might change some day is not unthinkable.

As noted, NGen code is slight slower. So if you don't care about warm-start delays then you don't want to use NGen.

Last but not least, RyuJIT does not generate faster code than its predecessor. Which already did a very decent job of optimizing. Too decent. The RyuJIT project was started to fix problems in the legacy x64 jitter, the kind that were pretty fundamental in the code base and could only be solved with a drastic rewrite. Optimization was one of them, it had no upper-bound on the amount of time it spent on it. Giving it very unreasonable jitting times on large methods. So if you want to squeeze the last ounce then intentionally disabling RyuJIT so it falls back to the legacy x64 jitter is something you ought to try.

like image 146
Hans Passant Avatar answered Nov 14 '22 22:11

Hans Passant