[.NETWorld] C# PERFORMANCE TIPS & TRICKS


At Mindscape, we’re a pretty polyglot group of developers. Various parts of Raygun are written in different languages and frameworks – whatever is best for the job. At present we have:

Given the vast amount of C# and the explosive growth in data we’re dealing with, some optimisation work has been needed at various times. Most of the big gains come from really re-thinking a problem and approaching it from a whole new angle. Today however, I wanted to share some C# performance tips that have helped in my recent work. Some of these are fairly micro so don’t just charge out and employ everything here. With that, tip 1 is…

Every developer should use a Profiler

There are some great .NET profilers out there. I personally use the dotTrace profiler from the Jet Brains team. I know Jason on our team gets a lot of value from the Red Gate profiler also.

Every developer should have a profiler installed, and use it.

I can’t count the number of times that I’ve assumed the slow part of an application was in one area when in fact it was somewhere else completely. Profilers help with that. Furthermore, sometimes, it’s helped me find bugs – a part that was slow was only slow because it was doing something incorrectly (that wasn’t being picked up properly by a unit test).

This the first, and effectively mandatory, step of any optimisation work you’re going to be doing.

The higher the level, the slower the speed (usually)

This is just a smell that I’ve picked up on. The higher level abstraction you’re using, the slower it will often be. A common example here that I’ve found is using LINQ when you’re inside a busy part of code (perhaps inside a loop being called millions of times). LINQ is great for expressing something quickly that might otherwise take a bunch of lines of code, but you’re often leaving performance on the table.

Don’t get me wrong – LINQ is great for allowing you to crank out a working app. But in performance focused parts of your code base you can be giving away too much. Especially since it’s so easy to chain together so many operations.

The specific example I had, was where I was using a .SelectMany().Distinct().Count(). Given this was being called tens of millions of times (critical hot point found by my profiler) it was stacking up to a huge amount of the running time. I took another approach and reduced the execution time by several orders of magnitude.

Don’t under estimate Release builds vs. Debug builds

I’d been hacking away and was pretty happy with the performance I was getting. Then I realised I’d been doing all my tests inside Visual Studio (I often write my performance tests to run as unit tests also, so I can more easily run just the part I care about). We all know that release builds have optimisations enabled.

So I did a release build, called the methods I was testing from a console app.

I got a great turn around with this. My code had been optimised like crazy by me, so it really was time for some of the micro-optimisations that the .NET JIT compiler to shine. I gained about about an extra 30% performance with the optimisations enabled!

This reminds me of a story I read online a while back. An old game programming tale from the 90′s – back when memory limitations were super tight. Late the development cycle the team would ultimately run out of memory and start thinking about what had to be removed or downgraded to fit inside the tiny memory foot print available. The senior developer had expected this, based on his experience, and had allocated 1MB of memory with junk data at the very start of the project. He then saved the day and solved the problem by removing the 1MB of memory he’d allocated right at the start of the project! Knowing the team always ran out of space, by having the memory there to free gave the team what they needed and they shipped on time.

Why do I share this? It’s similar in performance land – get something running well enough in debug mode and you’re about to get some “free” performance in a release build. Good times.

Look at the bigger picture

There are some fantastic algorithms out there. Most you don’t need on a day to day, or even month to month basis. It is however worth knowing they exist. All too often I discover a much better approach to solving a problem once I do some research. A developer doing research before coding is about as likely as a developer doing proper analysis before writing code. We LOVE code and always want to dive right into the IDE.

Furthermore, often when looking at performance problems we focus too heavily on a single line or method. This can be a mistake – looking at the big picture can help you improve performance far more significantly by reducing the work that needs to be done.

I recommend reading resources like Clever Algorithms: http://www.cleveralgorithms.com/ It was certainly an eye opener to me on some of the more advanced algorithms out there.

Memory locality matters

Lets assume we have an array of arrays. Effectively it’s a table, 3000×3000 in size. We want to count how slots have a value greater than zero in them.

Question – which of these two is faster?


for (int i = 0; i < _map.Length; i++)
{
	for (int n = 0; n < _map.Length; n++)
	{
  		if (_map[i][n] > 0)
  		{
    		    result++;
  		}
	}
}



for (int i = 0; i < _map.Length; i++)
{
	for (int n = 0; n < _map.Length; n++)
	{
  		if (_map[n][i] > 0)
  		{
    		    result++;
  		}
	}
}

Answer? The first one. How much so? In my tests I got about an 8x performance improvement on this loop!

Notice the difference? It’s the order that we’re walking this array of arrays ([i][n] vs. [n][i]). Memory locality does indeed matter in .NET even though we’re well abstracted from managing memory ourselves.

In my case, this method was being called millions of times (hundreds of millions of times to be exact) and therefore any performance I could squeeze out of this resulted in a sizeable win. Again, thanks to my ever handy profiler for making sure I was focused on the right place!

In Summary

This has been a collection of just a few things I’ve found useful for picking up the performance of my .NET code. There’s obviously a lot of other optimisation tips and tricks and many I haven’t written about here. I welcome you sharing any you have in the comments :-)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s