Writing High-Performance .NET Code by Ben Watson
A really good book from someone who has clearly worked hard in the past to maximize the performance of .NET applications. The book has a strong emphasis on using Event-tracing for windows, ETW, for getting information about the behaviour of various components of the CLR (such as jitting or garbage collection behavior), and also makes a lot of good observations on measurement, opining that averages often not the best measurement and one should instead aim at a particular percentile (which is something that Gil Tene discusses in his talk on understanding latency)
Chapter one covers performance measurement and tools. Here the author describes ETW (by way of example), perfmon and performance counters, Windbg and its associated SOS extension for CLR debugging, decompilation using ILSpy/Reflector, the sysinternals tools such as VMMap, and also mentions profilers such as the one that comes with Visual Studio. The author seems to shy away from using profilers because of their invasiveness, and he is often more concerned with measuring the performance on systems that don’t need the applications to be restarted in order to get measurements. Certainly it would be hard work to profile a production system using rewriting .NET profilers, and ETW seems to be positioned as a low overhead logging framework while still offering great detail on the application being logged.
Chapter two covers garbage collection and it’s a very good overview. It has clear explanations on the various modes for the garbage collection, server/workstation with and without background garbage collection (for generation two) and explains how the mode maps down to the number of threads that the system is going to be using. When to force full garbage collections (hardly ever), when to compact the large object heap, when to handle the garbage collection pending event and how to track down fragmentation (using Windbg) are covered, as well as how to monitor the performance of the memory system.
Chapter three covers the JIT. When to NGEN and when to use the 4.5 background compilation mode are covered. The author also discusses the C# language constructs that generate masses of code – LINQ and dynamic code in particular, and again covers the way to monitor what the JIT is doing.
Chapter four covers asynchronous programming and is a collection of items that the author has considered when writing his own systems. There is an emphasis on using Tasks as the abstraction for chunks of work, given that these support cancellation and various combinators for combining them in interesting ways. PLINQ, timers, and await are also covered in some of the observations.
Chapter five on general coding and design looks at various things. Class versus struct and the massive savings in memory usage that structs can offer, sealing and virtual dispatch contrasted with interface dispatch at a polymorphic call site, avoiding boxing and casting, and using exceptions as a general control flow operation. There’s also an interesting note on dynamic code generation.
Chapter six looks at parts of the .NET Framework, and points out that you should understand the cost of every API call you make – particularly as the framework often provides many different ways to do the same thing (for example parsing XML). This chapters looks at some miscellaneous items that are commonly misused.
The next two chapters look at performance counters in more detail, and then look at writing your own trace events into the ETW logs.
The final two chapters discuss how you can make your team more performance focused and how to avoid the various performance traps.
I liked this book because of its practical application. The explanations of the various technologies are really good, and the text is peppered with stories of where the observations actually helped in practice. ETW is being pushed hard as the technology to use for logging and it is really good to find a book that focusses on the use of this.