Computing in the real world
SEARCH FOR: IN:
Guest  Level 00    Register Log in

Real World Computing

.NET performance

24th April 2006 [PC Pro]

The class libraries that make up the .NET CLR provide pre-written code modules to do lots of the useful things you want when building an application, which means that by invoking these functions through a few lines of your code you don't have to develop them (and debug them!) yourself. Both in theory and in my own experience, the .NET class libraries are better designed, higher performing and contain fewer bugs than the average programmer might be able to produce for themselves. So at the level of designed-in performance, .NET provides some clear wins.

As an IT pro, once your development team has decided on a particular design and chosen those features of .NET to be incorporated into the application, you're somewhat stuck with their design decisions. Suppose, for example, that those designers choose a three-tier application architecture, with each tier implemented on a different system. This imposes an immediate absolute performance hit of at least 20 per cent compared to performing all the functions on the same machine, but on the other hand such an architecture facilitates scaling in the future. These are the sort of trade-offs your designers have made and you have to live with. At the same time, it's easier to understand such design trade-offs if you first understand the impact they're likely to have on your network. On my website, you'll find some pointers to background articles on these various .NET design issues.

However, there are certain areas where .NET behaves very differently from what you may be used to, and such differences can provide both new types of performance problems you need to investigate and some new performance-tuning options. There are three areas in particular that I want to look at in this article. First, I want to show you how .NET applications start up and what you can do to hasten this process. Second, I'm going to talk about caching in .NET and how you can use it to improve performance. Lastly, I'm going to take a look at the extra performance counters that .NET provides, which can equip you with greater insight into how your .NET applications are performing and help you tune your system correctly.

Native Code and NGEN

In traditional Win32 (and earlier) programming, the compiler creates a EXE or DLL file that contains native CPU instructions, and different compilers or different compiler switches are needed to create different native code for, say, an i386 or an x64 processor. A .NET executable or DLL also contains code that gets executed when you run the application: this isn't native CPU code but rather IL (Intermediate Language) code. IL consists of instruction codes for a virtual processor, which the .NET CLR converts into native instructions for the real CPU at run-time. Whenever .NET needs to execute a class, it runs the JIT (Just In Time) compiler to translate IL into native code - x86 code if you're running on a 32-bit Intel/AMD processor, or 64-bit code for AMD x64 processors and so on. Note that this conversion is performed on a class-by-class basis, so if a particular DLL contains ten defined classes but your code only calls one of them .NET will only JIT compile that single class. Once the JIT process has been completed, the CLR keeps the JITed native code in its cache.

This JIT process consumes some CPU time during application start-up, and the delay can be quite noticeable, depending on the application. For example, the Beta 2 release of the Monad command shell wasn't JITed by default and took several seconds to perform its JIT compilation when you first ran it. Another occasion when this JIT delay can hit you is when you release update code for your ASP.NET website. You may recall from my previous column about ASP.NET that the CLR compiles code as needed, but once compiled any ASP.NET code remains in a .NET cache. This means that whenever you drop a new version of a page or its underlying code into your web folder, .NET will automatically recompile that module the next time the page is requested. For just the odd page on a moderate-volume website, this might be barely noticeable, but given significant site changes spread across a large server farm the performance hit may be quite severe.

Continued....