views:

930

answers:

11

I just inherited a C# project that runs way to slow and will have to start optimizing it. What I wanted to do first is learn a little more about profiling/optimizing since I didnt have to do it before. So the question is where do I start, what books/blogs/articels can i read?

I do know OF the .net profilers like ANTS profiler and so on, but i have no idea how to use them efficently. I have not really used it, just let it run on a few sample apps to play around with the output.

Thanks for any help you can give me

+3  A: 

If you are familiar with and have already purchased ANTS (a very fine profiler) then go here for a quick tutorial to get you up and running.

Andrew Hare
+4  A: 

I'm taking an undergraduate course (one topic is Performance Analysis) and the recommended text is The Art of Computer Systems Performance Analysis: Techniques for Experimental Design, Measurement, Simulation, and Modeling. It's something of a bible on the subject and might be a bit overkill.

vinc456
overkill is nice for those sleepless nights where you just have to read some dry text on performance analysis to put you out for good:) thx
LDomagala
@LDomagala Amen!
Lucas McCoy
+1  A: 

these two articels is all i found till now:

Find Application Bottlenecks with Visual Studio Profiler

Measuring .NET Application Performance

LDomagala
+2  A: 

If you have Visual Studio Team System I suggest using the Profiler it contains.
It is under "Analyze->Profiler"
Using this profiler is really simple. You can just dive in and see what you make of it. Hands on practice is better than any article or book you're going to read about it.

Finding your first couple of bottlenecks is easy as just a few clicks. Solving them might be abit more tricky but again, Optimizing code is just a matter or practice and experience.

shoosh
+11  A: 

There are two steps to optimizing code.

First, you need to find out what's slow. That's where a profiler is handy. They're generally straightforward to use. You run your application through a profiler, and when it terminates, the profiler will show you how much time was spent in each function, exclusive (this function without counting time spent in function called from that) as well as inclusive (time spent in this function, including child function calls).

In other words, you get a big call tree, and you just have to hunt down the big numbers. Usually, you have very few functions consuming more than 10% of the execution time. So locate these and you know what to optimize.

Then comes the trickier part, how to optimize the code. Of course, the most effective approach is often the high-level one. Does the problem have to be solved in this way? Does it have to be solved at all? Could it have been solved in advance and the result cached so it could be delivered instantly when the rest of the app needed it? Are there more efficient algorithms for solving the problem?

If you can apply such high-level optimizations, do that, see if that improved performance sufficiently, and if not, profile again.

Sooner or later, you may have to dive into more low-level optimizations. This is tricky territory though. Today's computers are pretty complex, and the performance you get from them is not straightforward. The cost of a branch or a function call can vary widely depending on the context. Adding two numbers together may take anywhere from 1 to 100 clock cycles depending on whether both values were already in the CPU's registers, and so on. So the more low-level knowledge of how the CPU works, the better. However, there are a few trends that are often worth following:

I/O is expensive. CPU instructions are measured in fractions of a nanosecond. RAM access is in the order of tens to hundreds of nanoseconds. A harddrive access may take tens of milliseconds. So often, I/O will be what's slowing down your application. Does your application perform few large I/O reads (read a 20MB file in one big chunk), or countless small ones (read bytes 2,052 to 2073 from one file, then read a couple of bytes from another file)? Fewer large reads can speed your I/O up by a factor of several thousand.

Pagefaults involve harddrive accesses too. In-memory pages have to be pushed to the pagefile, and paged-out ones have to be read back into memory. If this happens a lot, it's going to be slow. can you improve the locality of your data so fewer pages will be needed at the same time? Can you simply buy more RAM for the host computer to avoid having to page data out? (As a general rule, hardware is cheap. Upgrading the computer is a perfectly valid optimization - but make sure the upgrade will make a difference. Disk reads won't be a lot faster by buying a faster computer. And if everything fits into RAM on your old system, there's no point in buying one with 8 times as much RAM)

Your database relies on harddrive accesses too. So can you get away with caching more data in RAM, and only occasionally writing it out to the database? (Of course there's a risk there. What happens if the application crashes?

And then there's everyone favorite, threading. A modern CPU has anywhere from 2 to 16 CPU cores available. Are you using them all? Would you benefit from using them? Are there long-running operations that can be executed asynchronously? The application starts the operation in a separate thread, and is then able to resume normal operation instantly, rather than blocking until the operation is complete.

So basically, use the profiler to understand your application. How does it spend its execution time, where is it being spent? Is memory consumption a problem? What are the I/O patterns (both harddrive and network accesses, as well as any other kind of I/O)? Is the CPU just churning away all the time, or is it idle waiting for some external events, such as I/O or timers?

And then understand as much as possible about the computer it's running on. Understand what resources it has available (CPU cache, multiple cores), and what each of them means for performance.

This is all pretty vague, because the tricks to optimizing a big database server are going to be very different from what you'd do to optimize some big number-crunching algorithm.

jalf
@jalf: this is a good summary of performance-analysis-as-a-big-subject. I like to think of it as a small subject. Sampling the call stack (I do it manually) tells where the waste is, quickly and precisely.
Mike Dunlavey
+1  A: 

Read Rico Mariani's blog. Before he was promoted, he was a major performance tuning guy for .Net. The older entries in his blog have a ton of good advice. I'd start close to the beginning and work your way forward.

That, plus the articles you've already found (especially the first one) should get you started.

Sean Reilly
A: 

This won't help you much on C#, but the OS X Shark tools (comes with the developer tools from Apple) are the Best profiling tools I've come accross. Almost fun to use!

As to profiling, there's two ways of approach. First, you should understand the software. The data structures especially. Don't start optimizing unless you understand it first.

Second, you shall measure (which seems you're about to do). I've been mislead by my gut instinct almost always; places I would regard as secondary are the time takers. This also means when you're optimizing you're always optimizing for a certain set of test cases you run. The selection of such cases is important.

akauppi
+1  A: 

There are profilers and performance analysis tools, but while you're trying to find / buy / install / learn one, just try an old-timer's trick...

Run the app under the IDE, and while it's being sluggish, hit the "Pause" button, and ask it what it is doing, and why. The best way to answer this is by reading the call stack.

If it is several times slower than it should be, like 10 times, that means it is spending 90% of its time doing something unnecessary, and that is the probability you will catch it doing it. If you repeat this several times, you can confirm your suspicions with as much accuracy as you want.

So you don't need an expensive / popular but fuzzy magnifying glass.

So finding the reason for the slowness is not the hard part, and there are usually several.

The hard part is, after you've fixed a few "low-hanging-fruits", you will probably have to face the fact that the main reason for the slowness is over-design.

Good luck.

Mike Dunlavey
+1  A: 

I've used profilers before, they can be helpful, but you can get a lot of help just from creating a singleton stopwatch type class and "Click" it (have it print out the time since the last click and what was just done that took that time) before and after methods you think might be problematic.

If speed is a problem throughout the app, you're probably not going to be able to do too much about it, but you might be able to make a few changes...

Look for inner loops. These are performance death. An inner loop can be caused by something as simple as indexing into a linked list, or doing an insertion sort into an array-based list. (Once I had a list box that was taking 10-20 minutes to fill with tens of thousands of entries, although that's too many entries, the worst part was that it was sorting it by inserting each entry into an array list).

Look for cases where you are doing long operations based on keypresses. These should almost always be done outside the main thread.

Don't even THINK of optimizing things like numbers of classes or how often they are instantiated, string concatenation (outside of loops), nulling out variables or any of the other silly strategies that seem like they should help. I've tried a few and always ended up feeling silly when I actually slowed things down because I wasn't as smart as the runtime is at most things.

Bill K
+1  A: 

I would download a few of the profiling tools available (free trials) and start using them.

I used jetbrains , and there are others. (ants for example, devpartner and a MS one?, atomatedqa, etc) You should not have too much problems running them. They have reports that give you lots of information and you can learn pretty quickly just using the applications.

Any one of them will probably help you and it is nice to use the trials. You can then either just shelve the decision to buy the tool, or buy the one(s) that was the most helpful/easiest to use. In general they are great time savers and worth the money, though some can be expensive. (I have a hard time with the ones on the upper end when there are very good tools for a lot less money)

You might find some serious/major performance issues the first day you install and run them. I know I did.

good luck.

just download some tools and start running your app.

EDIT:

As for books and learning - basically the best way to learn about problems with code is to find bad code. Many times doing inspections with experienced developers will be helpful.

as an example: I think Joel wrote an article way back about he did something like

for (int i = 0; i < strlen(some string); i++)

that is pretty obvious that you are going to call strlen (expensive) every iteration of the loop.

You'll have to look at some of the code after the profiler tells you where time is being spent and see if the code can be fixed easily with simple things like that, or changes have to be made in the design of the algorithms.

Tim
A: 

You have already hit the nail on the head with the Profiler. All of them, at least all that I have used, follow the same basic methodology. You select the executable and then run the application.

What you do with the output is find the methods that take the most time.l This is not all, but you asked for a good way to learn how to optimize code, so the long running routines are a good place to start. ANTS, which you mentioned, will default to showing long running routines, as will most, if not all, others.

You can exclude the container methods, like Main(), unless you have a lot of code in there (unlikely).

In general, I find most waste in three areas:

  1. Loops
  2. Recursion
  3. Network latency

Area #3, for the database, is generally easy to spot if you will also profile your database, as you will see the number of hits. The best way to reduce network latency, whether database or not (service calls, for example), is to communicate in messages rather than CRUD. Don't query each table, one at a time. Unfortunately, the solution often requires canning parts of many common data layers.

Recursion and loops are very similar problems. If you want bang for the buck, hit the inner loop first.

In .NET, you can also learn a lot about optimization by learning basic IL and examining the IL of your applications through tools like Reflector. A bit of a waste of time, if this is not the major portion of your job description, or something you are likely to want to spend your future career doing. Being a fireman pays well, but being a maintenance only coder can be very boring.

There are only a couple of books on optimizing and profiling .NET applications. The one that has optimzing in the title. The debugging book for .NET has some info on Profiling, but it is not very deep. It is a great book to read for optimization, however, as many issues that cause bugs will also show up in your optimization trips.

Gregory A Beamer