Wednesday, October 28, 2015

The Monkey mastering .Net!?

For readers of the blog, they may notice that I am kinda big fan of Java's optimizer and environment but on my day to day tasks I'm still using .Net. Also, to do something interesting, I look into loading big data sets and a good way to work with this data is to look into the Heroes 2 data and the FHeroes 2 algorithms of processing them.

The previous post was how it is possible to read the game data of few compressed MB in few seconds. But the original algorithm extracting all data data from Heroes2.Agg (kind of a "global file system" for graphics) and compression them into a zip, and this zip full extraction was later benchmarked.

But how much does it take to run it from command line?
Time: 18349 ms
So it takes 9 times to extract the graphics of the original game using .Net than to extract them from a plain zip from Java. As the algorithm is very slow, I was suspecting something went wrong. Obviously I checked to be sure that I set "Optimize code" into the assembly's properties. Checked...

After digging, I found a smoking gun: by default Visual Studio 2015 sets the: "prefer 32 bit code".

Chosing 64 bit code, the answer changed drastically:
Time: 13396 ms.
I tried to switch also from 4.5.2 to 4.6.0 (maybe is related with RyuJit) but the times were fairly consistent.

The last surprise? I tried Mono even knowing that is a 32 bit only environment on Windows.

The result? In part a bit shocking: time: 8554 ms, so more than 2 times faster compared with .Net. I measured twice, the results are consistent. Also, Mono comes with many options which is in fact amazing if you ask me, but they did not impact almost at all the performance:
- mono --llvm: Time: 8297 ms
- mono -O=unsafe: Time: 8325 ms

Disclaimers: these tests can show a pathological case of .Net. To try to reproduce the test, you have to get Heroes 2 Demo, take heroes2.agg and copy it inside "data" folder, and run the revision of NHeroes2 on GitHub comitted just around the blog entry was written.

But some rules to keep in mind when you run your application in .Net environment: 
- make sure you have "Optimize code" and "Any CPU" (without Prefer 32 bit) or x64 binary checked on Release. Otherwise you can lose 25% in a bitmap processing code.
- if your code runs in Mono, try it, it may run faster than 2x times and maybe this is what you need
- try Mono even for other reasons: this will make your code more future-proof, as you can migrate at least some sections of your code to your server with Linux or with your OS X. Even more, if you can afford, you can buy tools to build .Net applications with Xamarin. To me they look a bit overpriced, but if you need to support starting from a C# code an iPhone application, why not to pay to Xamarin
- at last: I found some functionality I was using, was not working optimal with the latest Mono distribution, but there are many workarounds for it: the .Net default Zip compressing library is not supported and it crashed on my machine in Mono. But this was not an issue, as there is ICSharpCode.SharpZipLib which runs on Mono just fine. Xamarin are fairly good on catching up, so I will not hold my breath if Xamarin would have maybe in few months some Zip file support compatible with .Net Compression frameworks

Ah, and I forgot to say, I don't know fully why the performance was so bad, I would expect to be a bit related with GC behavior, and is possible that the GC of Mono to have a bit higher troughput but a worse "worst case scenario" than .Net. This may explain maybe the difference from 13.4 seconds to 8.5 seconds. Or maybe a weird bounds check that the .Net optimizer may not optimize it nicely and Mono would do it... I really don't know. If there is someone wanting to investigate and make the code much faster than 8 seconds with .Net using a custom profiler, so be it, but just don't use this as either a "definitive proof that Mono is faster than .Net". Similarly, don't forget that most of the time, a well optimized code can run faster just if it has better organized data. .Net would likely extract all data (estimated, not absolute numbers, as I never wrote the .Net code to extract from zip) compared with Java previous post in around 6 seconds, and it would be faster than Mono with the actual 8.3 seconds. And Mono would not be able to run faster because it crashes with the zip format for now.

No comments:

Post a Comment