8 ms·
A Look at the Internals of 'Tiered JIT Compilation' in .NET Core
- polskibus 9y agoI heard so many times that JVM is much better than CLR, especially in the JIT area (Hotspot?). If it's true, do the new .NET Core internals, allow .NET Core to beat JVM? If not, are there any additional steps planned to beat JVM at last? .NET ecosystem is much smaller than Java's (for instance all the Apache projects) and Linux + .NET Core happened too late to make up for it in my opinion. Hopefully, at least performance can be the point that can turn other people attention back towards C#/.NET.
- chrisseaton 9y ago> I heard so many times that JVM is much better than CLR, especially in the JIT area (Hotspot?). I wouldn't disagree with this (I work at Oracle on VM research), but I've been told by other people that Microsoft or at least the .NET just generally prefer a simpler approach, without profiling, dynamic compilation, deoptimisation, and other complexity the approach used by the JVM brings. It's much more what-you-see-is-what-you-get from their JIT, rather than the mind-binding things the JVM manages to do with some code, and maybe that makes life easier for their use cases. I'm not sure they want to add the same kind of complexity that the JVM has, even if it did bring them some better performance. But as I say that's second hand conversations.
- sreque 9y agoI definitely agree with this stance, and would say that languages like C# and golang have a weaker runtime but try to make up for it in other ways, often surpassing Java in certain areas. For instance, both languages have stack-allocated types to help stress the GC less. C# also has a much better native interop story than Java, as well as the unsafe keyword. At the end of the day, if you want amazing performance in Java, you have to write C-like code in Java, and that often involves things like managing your own offheap memory, sticking with arrays of numbers, etc. Java's biggest areas for improvement in the performance arena are going to come allowing for stack-allocated types, fully-continugous arrays, less overhead when calling native code, and providing official APIs for the other things you can currently do with sun.misc.Unsafe.
- naasking 9y agoThe .NET runtime is weaker on the JIT side, but the lack of type erasure on generics is very complicated all on it's own. Java doesn't have to deal with this. In fact, .NET is the only VM I know of with this feature. Fortunately, it permits a lot of interesting manual optimizations you can't easily express when runtime types aren't available.
- seanmcdirmid 9y agoThe lack of erasure is a huge usability win (types don’t disappear at run time), as well as a performance win (I’ve been able to do great things with C# generics + value types). I also like the way it naturally deals with static fields (useful for factory routines).
- throwaway010317 9y agoI use C# in my day job and try to learn as much as I can about cool ways to use its type system. Genuinely curious to see some examples if you're able to point me in the right direction? > I’ve been able to do great things with C# generics + value types
- naasking 9y agoYou can see a few tricks in my project here: https://github.com/naasking/Dynamics.NET https://github.com/naasking/Dynamics.NET You can use static classes to cache information about types. That project caches delegates to perform deep copies, to invoke constructors, to check for deep immutability, and whether a type can contain any cycles. This is all done structurally via reflection, but the results are executed only once and cached in static fields by exploiting runtime types. The cached delegate trick can be used whenever you need to some efficient dynamic dispatching. I use it here [1] in another project to cache the Dapper methods that would be invoked so I can easily compose smaller queries into larger ones that return very complicated objects. A more complicated example would be the fastest immutable dictionary available for .NET in my Sasa library [2]. Generic methods and types defined on structs are JITted separately, so the dispatching overhead is low. I exploit this to create a very efficient hash array mapped trie. [1] https://github.com/naasking/Dapper.Compose/blob/master/Dapper.Compose/Query.cs#L90 https://github.com/naasking/Dapper.Compose/blob/master/Dappe... [2] https://sourceforge.net/p/sasa/code/ci/default/tree/Sasa.Collections/Trie.cs https://sourceforge.net/p/sasa/code/ci/default/tree/Sasa.Col...
- matthewwarren 9y ago> but I've been told by other people that Microsoft or at least the .NET just generally prefer a simpler approach, without profiling, dynamic compilation, deoptimisation, and other complexity the approach used by the JVM brings. It's much more what-you-see-is-what-you-get from their JIT, rather than the mind-binding things the JVM manages to do with some code, and maybe that makes life easier for their use cases. Interesting, it's clear after a bit of research that this is the case (i.e. .NET JIT simpler that Hotspot), but it had never occurred to me that it was a conscious decision I'd always thought that the .NET was just playing catch-up and/or didn't need to do all the things that Hotspot does. (for instance .NET has value types or 'stucts' so some optimisations are not needed because the programmer can just use them instead of classes, if they need the perf boost)
- sillypuddy 9y agoIt has been a deliberate decision. The Book of the Runtime documentation states "The goal of the CLR is to make programming easy" and acknowledges there are faster alternatives out there. When I have asked insiders why there isn't a bigger focus on performance, the response is essentially that if performance is really important you should use C++.
- matthewwarren 9y ago> The Book of the Runtime documentation states "The goal of the CLR is to make programming easy" In case anyone else is interested, that quote comes from https://github.com/dotnet/coreclr/blob/master/Documentation/botr/intro-to-clr.md#the-primary-goal-of-the-clr https://github.com/dotnet/coreclr/blob/master/Documentation/...
- benaadams 9y agoAlso says > The .NET runtime supports a wide variety of high performance applications. As such, performance is a key design element for every change. https://github.com/dotnet/coreclr/blob/master/Documentation/project-docs/performance-guidelines.md https://github.com/dotnet/coreclr/blob/master/Documentation/...
- 9y ago
- mehrdadn 9y ago>> I heard so many times that JVM is much better than CLR, especially in the JIT area (Hotspot?). > I wouldn't disagree with this I would wholeheartedly disagree with this though. There's not even any way to write, say, a generic class (even one as simple as ArrayList<T>) and then let the user instantiate it with a primitive type like <int> in Java. To use generics in Java is to pay the speed penalty of an indirection for every single primitive type on top of the extra per-object bytes of space overhead. There's just no way Java is going to fix these problems without massive breaking changes in the type system or an extremely in-depth & expensive form of static analysis unlike anything I've seen in any real-world compiler.
- chrisseaton 9y agoYou're not disagreeing with me, because we're talking about different things! You're talking about Java, the language, I'm talking about the JVM, really HotSpot, really C2 actually, the implementation and the techniques it uses, whatever the language is, compared to the techniques that the .NET CLR uses. The points you bring up are interesting though, because some of these complexities (which HotSpot isn't responsible for or in a position to change!) are as someone else has said, probably partly what has motivated the extra work in C2 compared to the .NET CLR JIT. > To use generics in Java is to pay the speed penalty of an indirection for every single element on top of the extra per-object bytes of space overhead. And this is just false - the extra indirection only applies for elements that are boxed primitives, not 'every single element'. There is no extra indirection for things that are references anyway.
- mehrdadn 9y ago> You're not disagreeing with me, because we're talking about different things! You're talking about Java, the language, I'm talking about the JVM, really HotSpot, really C2 actually, the implementation and the techniques it uses, whatever the language is, compared to the techniques that the .NET CLR uses. No, we are disagreeing. I'm talking about how repercussions of decisions in the language affect the implementation. My comment was not at all limited to just the language itself. If you read my comment, you notice I mentioned fixing these issues would require changes in either the type system or an "expensive form of static analysis unlike anything I've seen in any real-world compiler". Because when the language dictates that there must be an indirection, the implementation can only remove it when it can prove that doing so would be transparent to the code, which is impossible to do in general and extremely difficult in practice. This is neither just about the language nor just about the implementation; it's about the consequences of language decisions in the implementation. > the extra indirection only applies for elements that are boxed primitives Yes, I just assumed since I had already mentioned primitives it was clear that I'm talking about the use of primitives in generics. But I'll edit it in to repeat myself.
- kittiepryde 9y agoAre there standard benchmarks used to measure and compare the two approaches (jvm vs .net)?
- chrisseaton 9y agoIt's crazy but I'm not really aware of any good benchmarks, at least in the research community. But you can show the differences qualitatively, in that the .NET simply doesn't have large swathes of optimisations which I think are considered pretty fundamental in the JVM such as escape analysis.
- benaadams 9y agoPinch of salt with all benchmarks, but "The Computer Language Benchmarks Game"? http://benchmarksgame.alioth.debian.org/u64q/csharp.html http://benchmarksgame.alioth.debian.org/u64q/csharp.html .NET does better in most of them, but falls down vs Java on Regex and k-nucleotide
- deleted 9y ago[deleted]
- jackmott 9y agoIt seems to be pretty close now, but it is hard to compare due to different philosophy. For instance Java gives you no control re Heap vs Stack, but their runtime is very clever with escape analysis and can clean some of that up for you. .NET is not as clever with the escape analysis (the new .NET core stuff is better) but the programmer is given some control of it, and you get net better performance if you do that well, than you do with clever escape analysis. benchmarkgame results are very close between the two languages with the latest updates to C# implementations and running on the latest .net core 2.0
- benaadams 9y agoThe JVM jit _has_ to do a lot more for performance. Lack of value types means greater allocation by default - so it needs escape analysis to avoid it. Type erasure for generic types means speculative optimisation and deoptimisation steps for types. etc Doesn't mean the .NET Jit can't improve in these areas (e.g. now its doing devirtualization for .NET Core 2.1, and escape analysis would be great) - but it does start in a better place.
- bunderbunder 9y agoI think that the "lack of value types" is probably an overrated difference these days. Empirically, I've found that value types generally only offer a tangible perf benefit when they're the size of a pointer or smaller. There aren't a whole lot of spots where that comes into play. Primitives, sure, but Java also has those. Beyond that, maybe you'd see some difference in code that does a lot of date calculations, maybe. I've done some slightly obscene and shameful optimizations around packing data into 64-bit structures in the past, but those are pretty special cases.
- comex 9y agoHow about vectors or coordinates? This post from a few years ago comes to mind: http://www.minecraftforum.net/forums/mapping-and-modding-java-edition/minecraft-mods/1272953-optifine-hd-c7-fps-boost-dynamic-lights-shaders?page=2100#c43757 http://www.minecraftforum.net/forums/mapping-and-modding-jav... (Allegedly, a Minecraft update added significant strain on the garbage collector by switching the codebase from using separate variables/parameters for x, y, and z coordinates to using a single “BlockPos” object.)
- bunderbunder 9y agoIf you're just using local values, or storing them in an array, then, yeah, value types might help. That's a likely scenario for something like storing arrays of vectors. The spot where you take a hit is when you've got a scattering of individual objects that are being passed into and out of functions. There, the extra data copying has a tendency to outweigh the other benefits. And that's a more likely scenario for most kind of the kinds of business apps that .NET and Java are typically used for.
- matthewwarren 9y ago> If it's true, do the new .NET Core internals, allow .NET Core to beat JVM? I'm hoping that 'Tiered Compilation' will help, but it's early days. We will have to wait until it is 'officially' in .NET Core before it can be properly tested
- forgotpassagan 9y agoThe JVM has simply has a lot more resources poured into it. C# and the CLR is a more modern clone of Java and it shines in the great usability of C# and to some extent the more sane op-codes of the CLR. Transforming between the two is actually easy enough that several projects offer 100% interop between C# and pure Java libraries. I expect performance of the JVM to beat C# for a long time, but since the designs are so similar the difference isn't important in most cases. Having spent time in both ecosystems, I'll admit that C# is easily a superior language to Java, honestly the best designed language I've ever used. Not surprising since it has the same designer as Delphi and Typescript. It's all syntactic sugar, but so much so that programming C# is significantly faster and easier. What really hurts the .NET ecosystem right now is an insanely large gap in open source support. Something MS is fostering now but spent more than a decade trying to kill. This will not be easy to fix, as it's more a people problem than technical. MS actively tried to hurt the open source community for over a decade and to get support they will need to change the mind of countless people. It remains to be seen if this is viable. If I was Microsoft I would remedy this by adding first-class support for Java libraries in C# by throwing their support behind existing projects to do so. This might close a gap that could otherwise take decades to fill
- pjmlp 9y ago> If I was Microsoft I would remedy this by adding first-class support for Java libraries in C# by throwing their support behind existing projects to do so. This might close a gap that could otherwise take decades to fill Apparently you never heard of J#. https://en.wikipedia.org/wiki/J_Sharp https://en.wikipedia.org/wiki/J_Sharp
- forgotpassagan 9y agoI hadn't, but the primary problem is the inverse case. Java programmers have no problem switching to C# and vice versa. The languages are really similar. The problem is that many millions of lines of open source software have already been written in Java and developers are not going to spend thousands of man-years converting them. Especially because they know the languages are so similar. Developers are well aware that it would take minimal effort to make the languages compatible so they make little effort to port from one to the other. And Microsoft's problem is that the vast majority of these projects already target Java. If the languages were vastly different ports would be more interesting and fun to do, but since they're not porting is basically a boring and vastly annoying syntax conversion. Something annoying that nobody wants to do for free. If Microsoft officially supported interop with native Java libraries I believe C# would take off like a rocket. Unfortunately, so far, Microsoft hasn't really sent out an olive branch to the massive open source Java community
- tatersolid 9y agoMy experience having managed a medium scale SaaS app’s slow transition from Java to C#: 1) the CLR has very few “nerd knobs” compared with the JVM. It mostly auto-tunes itself and just works 2) despite this “lack of features” we’ve never experienced long pauses, GC storms, or our other JVM pains despite the same high user load and cloud instances 3) performance as measured by median and 99.9% response times is better in the C# bits on the same hardware, but there are also fewer DB round trips due to eliminating Hibernate in favor of Dapper and EF 4) tuning the JVM for high load is still poorly documented whack-a-mole of switches and profiling. G1 didn’t help the “auto-tuning” aspects of the JVM much in our experience, we still had STW pauses of 10+ seconds under load occasionally 5) this comparison is likely totally unfair as the C# code is clearly “better-written” having been actually designed and drags in far fewer bloated dependencies than the Java code did
- polskibus 9y agoCan you say whether you moved to .net Core or .net framework?
- tatersolid 9y agoFramework for now, Core was too young when this started. But we’ve been careful to make sure it’s a switch-flip and not a major effort to move to Core