
Performance Improvements in .NET Core - matthewwarren
https://blogs.msdn.microsoft.com/dotnet/2017/06/07/performance-improvements-in-net-core/
======
old-gregg
Every time I try to get a quick feel of .NET on Linux, I allocate an hour to
it and that hour is always spent wandering around various guides on
microsoft.com and never getting anything done.

There are terms like .NET Core, .NET Platform, .NET Framework, .NET SDK all
mixed up on nearly every page, multiple versions of "Getting started" and
"Quick start" guides, massive navigation menus and options on every page so
you never know if you're looking at the latest and greatest or it's some kind
of abandoned dark corner of a web property, as it often happens with corporate
sites.

Yo! If you want .NET to be a massive hit on non-Windows platforms, move it off
Microsoft.com to a small site, have a single version of "getting started" (and
only one "guide"). Don't ever mention things that exist and don't work on
Linux.

Like this: [https://golang.org/doc/](https://golang.org/doc/)

Also, have a simple downloadable .tar.gz which expands into /bin + /lib +
/examples. I loved C# back in my Windows days and I moved to Linux to escape
Microsoft complexities and over-reliance on complex IDEs and tools, scattered
like shrapnel all over my c:/

I will not run apt-get against your repo without knowing ahead of time what
I'm getting and where will it all go, so let me play with the tarball first.

[EDIT] formatting

~~~
runfaster2000
Point taken. We have some improvements to make on this front.

~~~
jacques_chester
Speaking of names and versions -- while working on Cloud Foundry Buildpacks we
frequently turned our brains into pretzels trying to manage what components
were versioned how. We even had custom logic to parse a YAML file where we
maintained a mapping to keep things straight.

Especially since some components embedded different versions of other
components.

I don't know if the situation has improved since I rotated off, but a bog-
ordinary semver scheme would've saved a world of pain.

Failing that, a single page with components (SDK? Runtime?) and available
version numbers that gets updated.

Because we mostly wound up working what was what from forensic readings of
scattered blog posts, Github release and I think comments on Github issues.

In any case, I am sure the team would be glad to give you feedback on their
experiences since then -- my email is in my profile if want me to pass
anything along.

~~~
runfaster2000
See:
[https://github.com/dotnet/designs/issues/2](https://github.com/dotnet/designs/issues/2)

~~~
jacques_chester
Thankyou! I will ping my colleagues tomorrow.

~~~
runfaster2000
BTW: Your friends can also contact me -> rlander@ms

~~~
jacques_chester
The thankyous keep rolling. I also remembered I can point you at the Slack
instance where they live --
[https://slack.cloudfoundry.org/](https://slack.cloudfoundry.org/), in the
#buildpacks channel.

------
drej
Whenever I look at drastic improvements in performance, I remember that a
while ago I managed to speed up a custom parser at work, by about 30x. When I
emailed my colleagues, I just said "You may consider this to be work of a
genius. Or you may think I was stupid when writing the original
implementation. I'll let you pick the narrative that you fancy."

Interpretations are fun when there's a baseline :-)

~~~
jdmichal
Reminds me of when I replaced a read-write lock around generating a new object
instance with an atomic reference instead. I personally put that one into the
latter of your two cases... But the performance improvement certainly looked
heroic!

------
Analemma_
> This is another great example of a developer caring a lot about a particular
> area of .NET and helping to make it better for their own needs and for
> everyone else that might be using it.

This is a great, succinct, non-ideological explanation for why open-source
projects where anyone can contribute tend to be better. For a given
component/function, there might be only a single person in the entire world
who needs that optimized badly enough to actually do it themselves, but once
they do, everyone benefits. A closed-source team has to prioritize their
development efforts, which means niche improvements will probably never make
it in. Multiply this by a thousand different niches, and the product is going
to be slower.

~~~
bhauer
> _but once they do, everyone benefits_

This is such a good point.

We (TechEmpower) had this in mind when we created our framework benchmarks
project a few years back. Performance improvements in platforms and frameworks
have the potential of very broad impact. With our project, we wanted to
provide some inspiration for doing that kind of performance tuning. We had
found ourselves in many conversations about how many real-world CRUD web
applications take multiple seconds to render a page with a form. We realized
that if, just as an example, the JSON serializer or template engine were
substantially faster, many real-world applications that use those components
would see notable improvements to their user experience.

------
bitmapbrother
What's up with the memory consumption of C# .Net Core? It looks like it has
dethroned Java as the memory bloat champion.

[http://benchmarksgame.alioth.debian.org/u64q/csharp.html](http://benchmarksgame.alioth.debian.org/u64q/csharp.html)

~~~
runfaster2000
We haven't spent much time with those benchmarks. We looked at a couple of
them and believe that there are better ways to write them in C# and get better
results. That's not FUD but our findings.

This is a great community activity. Clearly, the community is more than
capable of performance enhancements, based on the improvements they have made
in the product.

If people start improving the C# benchmarks, please file an issue on
dotnet/core to get feedback and some cred. We may do another blog post on that
if there is some gravity around the activity.

~~~
voltagex_
Are any of those discussions around better way to write the benchmarks public?

From a very quick look, something like
[http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...](http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=csharpcore&id=2)
looks like a direct port from a C program, rather than idiomatic C#.

~~~
taspeotis
Some of them seem to have some rules [1] like:

> Please don't implement your own custom "arena" or "memory pool" or "free
> list" \- they will not be accepted.

> ...

> We ask that contributed programs not only give the correct result, but also
> use the same algorithm to calculate that result.

So there might not be too much room to improve. There could be some room to
improve for things like "custom ... memory pool" since .NET Core has ArrayPool
[2] built-in. But I can't tell if the spirit of that rule is "don't implement
pooling" vs. "you can only allocate memory in the standard ways provided by
the runtime."

[1] [http://benchmarksgame.alioth.debian.org/u64q/binarytrees-
des...](http://benchmarksgame.alioth.debian.org/u64q/binarytrees-
description.html#binarytrees)

[2]
[https://github.com/dotnet/corefx/blob/master/src/System.Buff...](https://github.com/dotnet/corefx/blob/master/src/System.Buffers/src/System/Buffers/ArrayPool.cs)

~~~
igouy
>> "you can only allocate memory in the standard ways provided by the
runtime." <<

This.

------
yodon
I was expecting maybe 10% improvements, but many of these are 30x perf
improvements on common collection operations

~~~
yread
The List. Add change is small but its hand optimized assembly, quite
impressive.

~~~
hacker_9
Worth noting it's not hand written assembly, but instead writing C# code in a
very specific way in order to encourage the compiler to implement more
aggressive optimizations (inlining, bounds check removals, etc).

------
alkonaut
I hope most or all these will find their way into the full framework. It's a
bit odd that this is so rarely mentioned. I still haven't quite grasped the
relation between core and the full framework when it comes to fixes like this
being merged into the full framework.

~~~
ksubedi
As .net core is a full rewrite, all these optimizations are .net core
specific, so porting them isn't going to be a easy thing.

~~~
paavohtl
.NET Core is not a rewrite in any way. It's the same runtime with the same GC
and JIT, same language compilers and mostly the same standard library. It has
just been stripped down by removing deprecated features (such as code
sandboxing / partial trust) and made support non-Windows platforms.

You might have confused it with ASP.NET Core, the web development framework,
which is a full rewrite.

~~~
T-hawk
If a developer confuses .NET Core and ASP.NET Core, is that a fault of the
developer, or of Microsoft's nomenclature?

------
koyote
This is great and a very detailed report as well!

Although if I understood this correctly, these performance improvements will
only take effect if you compile using .Net Core 2.0 and run using .Net Core
2.0 runtime? I did not realize .Net Core had diverged this much from .Net
Framework.

~~~
josteink
> I did not realize .Net Core had diverged this much from .Net Framework.

Yeah me too.

On the flip side I consider it a healthy sign for the project as a whole and
especially as an open-source undertaking.

------
martinald
The real problem for me is compatibility of NuGets with .NET core. I have so
many which are just not compatible and many which have a slightly different
Core variant with weird gotchas.

As such I've stuck with .NET 4.5 for now. On the positive side Mono seems to
have got a lot better and I have a bunch of stuff running on Linux with
surprisingly few problems "out of the box".

------
olegkikin

        for (int i = 0; i < 10_000_000; i++)
        {
            s_result = s.Min;
        }
    

Shouldn't your compiler completely fold this? There are no side effects, it's
single-threaded. This should take microseconds, not 86 milliseconds.

~~~
int_19h
It's pretty tricky for the runtime to figure out that there are no side-
effects, and that s.Min is not going to change, if the implementation behind
it actually walks some nodes. Among other things, it would require it to prove
that none of the walked nodes ever mutate anywhere else (don't forget that
this includes backdoors like reflection).

~~~
piaste
Are there any notable languages that flat-out forbid reflection, or treat it
as undefined behaviour?

------
arwhatever
Yay performance improvements to IEnumerable<T>/LINQ, to further take away
people's excuses for not writing code in a more declarative style.

------
polskibus
I wish they used benchmark.net for measuring performance. It can give much
more trustworthy measurements for such microoptomizations.

~~~
mellinoe
This is mentioned in the post, in case you missed it:

> _Further, normally such testing is best done with a tool like
> BenchmarkDotNet; I’ve not done so for this post simply to make it easy for
> you to copy-and-paste the samples out into a console app and try them._

We love BenchmarkDotNet and use it (and other perf tools) quite a lot
internally.

------
cspsolutions
Owning and managing software business we develop using multiple technologies

Mobile objective c, swift, Android java, xamarin.net, phone gap

Web asp.net Mvc , php, java

Etc...

Using Asp.net Mvc requires using 3rd party ui libraries and Depends on size of
team and experience in .net, usually we assign.net developers with at least 4
years experience in .net and front-end currently mvvm js libraries

If you starter in .net you have learning curve but this is reducing as
technologies improve

------
primeblue
A very understated company.

Microsoft keeps getting better. Open sourcing so many things.

C# and Visual Studio is a breath of fresh air compared to the bloated, aging
and vexing obfuscation called Java (work in both).

Since 1991 Microsoft Research keeps making contributions.

------
st0le
> For example, SortedSet<T>‘s ctor was originally written in a relatively
> simple way that didn’t scale well due to (I assume accidentally) employing
> an O(N^2) algorithm for handling duplicates.

Now that's a gross oversight.

~~~
Sammi
Dude. Be fair. You left out the part where he says:

 _> In other cases, operations have been made faster by changing the
algorithmic complexity of an operation. It’s often best when writing software
to first write a simple implementation, one that’s easily maintained and
easily proven correct. However, such implementations often don’t exhibit the
best possible performance, and it’s not until a specific scenario comes along
that drives a need to improve performance does that happen. For example,
SortedSet<T>‘s ctor was originally written in a relatively simple way that
didn’t scale well due to (I assume accidentally) employing an O(N^2) algorithm
for handling duplicates._

You'll never get anything done if you want to get it perfect the first time
round. Or as they say, first make it work, then make it right, then make it
fast.

------
pier25
Is there something like Heroku but for dotnet core apps?

I'd like to play a bit with it but it should be as easy as pushing to a repo
to deploy and run.

~~~
flukus
Why do you need to push to a repo to deploy/run? If you want to play just
create a project and run it locally.

~~~
pier25
I'd like to avoid any installation hassles.

What would be the easiest way to run on macOS?

------
SpikeDad
Always interesting timing by technology companies. Here's a post to developers
by Microsoft the day AFTER Apple's State of the Union presentation to
developers.

Microsoft touting performance improvements the day after Apple amps up
performance on pretty much every aspect of the Apple developers infrastructure
(Xcode, Swift, APIs, processor and GPU utilization, etc).

Must be a coincidence...

~~~
runfaster2000
I was personally involved in the publishing of this post. The timing of this
post and the Apple event didn't even register with us as interesting. We're an
engineering team and have zero interest in cross-company tactics like that.
Now, if there is an LLVM release you want to tell me about ... ;)

