Advertisement

.Net

Started by November 26, 2024 05:44 PM
6 comments, last by Calin 3 weeks ago

I'm trying to understand C# Just in time compilation. The internet explanations use complicated language that is difficult to break down.

The c# code is compiled on end user machine which means that the windows version will probably be different depending on who's running the executable but what else might differ from one machine to another? What is the point of compiling the code "just in time"?

The physical configuration (processor, memory etc) of my computer and your computer is different but isn't that a driver problem? How is a custom executable better?

My project`s facebook page is “DreamLand Page”

Calin said:
The c# code is compiled on end user machine which means that the windows version will probably be different depending on who's running the executable but what else might differ from one machine to another? What is the point of compiling the code "just in time"?

JIT-compilation has a variety of factors.

First, JIT-compilation makes the compiled intermediate code able to run on a variety of platforms. When you statically compile an exe in c++, this code can only run on a windows-machine, and only on certain supported architectures. If you instead compile a .NET-program, that program can run on any OS and architecture, as long as there is a matching .NET implementation. Windows, Linux, Mac. x86, x64, ARM… you name it. Of course there is still limiting factors, practically - mostly dealing with different hard-to-abstract OS specific system/library features, which means that pratically, you'd also need a framework that abstracts represeting pieces like the rendering-API; UI and so on… though it is still considerably less work than doing it yourself, which might require using silly stuff like NDK for compiling c++ on something like Android.

Second, this also usually recudes the time needed to compile such languages. Bytecode is way simpler then generation optimal machine-code, so the compiler has to spend less time during compilation to try to optimize sequences of code to their optimal forms. The JIT-compiler will still have to do those optimizations, but can delay or offload that. .NET is a bad example in this regard, as they do not have a native interpreted environment. Java for example runs on an interpreter, and only JIT-compiles code it considers benefical to do so. A one-time init function somewhere doesn't really need maximum speed. So it won't even bother to do that.
.NET on the other hand does need to compile all functions, but it can do so on-demand AFAIK. This still adds some overhead to executing the program on the users end (which can be seen famously in something like Unitys editor), but that'll even out over time.

Third, this does potentially allow additional optimizations, compared to a statically compiled program. When you compile your C++-program, the output is native code code that is run on a CPU. Thus, if you want to support ever CPU out there (which most compilers do), then you can only use those instruction-sets that are available everywhere. Newer or less common instructions are simply unavailable. Since the JIT is executed on the users PC, it can use exactly those instructions that the CPU has available, as long as the runtime accounted for them. One example is Intels new “APX” instructions for x86_64, which extends the instruction-set by a lot of useful stuff, like double the number of registers. It will take 10 years or more before C++-compilers can start support that (unless you only compile locally like with -march=native). But a JIT-compiler can implement it right away and make use of it. This has also been historically the case with things like AVE/SSE, which are now standard, but had to be introduces at a certain point before coming widespread supported.
On top of that, even the same instructions perform differently on different CPUs. Certain CPU (families) have specific sequences of instructions that perform better or worse, only on those specific CPUs. This is either due to errors on part of the manufacturers; missed optimizations, or simply new optimizations that have not been present before. Again, a statically compiled program that wants to support all CPUs needs to select a sequence of instructions that's likely to be best on average, or on most CPUs. A JIT can inspect exactly which CPU it is on, and apply it's knowledge about that CPUs flaws and strengths to optimize their output.
There's also a slew of other optimizations that are hard to achieve with static compilation. The JIT-compiler could determine branches or virtual calls on runtime, based on the loaded classes, or other global factors. Still, it seems most JIT compiled languages lack in performance compared to C++ from all what I've seen, so I'd personally label that as theoretical benefit in my book.

There's probably a lot more, like how bytecode can be smaller than native code when distributing; how it makes it easier to handle dependencies on external libraries (by not requiring a brittle binary interface like the one C++ (barely) uses)… But that's the gist of it.

Advertisement

I get the picture. Thank you

My project`s facebook page is “DreamLand Page”

Java does it as well.

Julian has it right. The optimizer might switch out instructions, maybe a SIMD instruction that does 8 at a time instead of 4 or 2 at a time, maybe pick a different library function to take advantage of the cache, whatever difference it knows about.

The changes are usually pretty small, but if they can shave off a few percent of runtime costs, it's still appreciated for many systems.

First, JIT-compilation makes the compiled intermediate code able to run on a variety of platforms

Which means it makes C# code run on Linux too (ASP.net is for linux servers I think, there was Mono too but that was a failed attempt to make WinForms run on Linux) and maybe Windows Server.

My project`s facebook page is “DreamLand Page”

Calin said:
Which means it makes C# code run on Linux too (ASP.net is for linux servers I think, there was Mono too but that was a failed attempt to make WinForms run on Linux) and maybe Windows Server.

Yeah, pretty much. I don't know the specifics, as I've never had to deal with cross-platform .NET. This MSDN-article seems to summarize it pretty well: https://learn.microsoft.com/en-us/dotnet/core/deploying/.

Advertisement

Thanks again Juliean that looks like an exhaustive description.

My project`s facebook page is “DreamLand Page”

Advertisement