Prizes & Awards
My Profile
Active Members
TodayLast 7 Days
more...
|
New Feature: Community Sites:
Create your own .NET community website and start earning from Google AdSense !
It's Free !
|
ASP.NET Performance Tips and Best Practices
|
Getting the numbers Throughput and Response Time In any performance work, it is vital to be able to gather good data on a sites performance. This includes things like maximum throughput (req/sec), response time (msec), performance counter data and profile data. Since performance work is iterative, one must be prepared to gather data, analyze the data, implement some changes and retest (repeat as needed). And before doing any performance tuning, always gather some data to back it up. Nothing is more frustrating that doing some performance work based upon some intuition or because it seemed logical, only to find out later that it wasnt the bottleneck or it had only minimal impact due to other problems. A common number used to measure performance is the maximum throughput of the web server while it has an acceptable response time. Response time is often measured by 2 numbers: Time to First Byte (TTFB), Time to Last Byte (TTLB). As the names imply, they refer to when the client has begun receiving data and when all the data has been delivered. The TTLB tends to be used as the response time from the server (since it includes the transmission time as well). The TTFB, when page buffering is turned on (the default), tends to be when ASP.NET has completed processing the page, hands off the data to the web server for transmission back to the client and the first byte reached the client. Usually the next ASP.NET request has already begun processing by the TTFB time (unless the app manually sends data back during processing). Also, it is important to keep in mind that the response time can be almost arbitrarily increased by simply increasing the concurrent load on the web server, meaning if the web servers CPU or back end resource has been maxed out, putting more load on it will only increase the average response time. For throughput tests, it is recommended that one use a dedicated web server, a set of dedicated client machines, a fast isolated network and a load generating tool (i.e. Application Center Test). It is also important to remember that when gathering throughput numbers, there must be some warm up time before the actual throughput numbers are gathered to allow the server to finish its one-time initialization costs and other web server and OS related paths to settle down for their maximum throughput. For tools that dont have this option, try to take into account that initial throughput may not be the peak or optimal throughput of the server. It is also up to individual application and web server configurations to determine the appropriate warm up and sampling period. Also, dont forget that its important to gather enough data points to determine ones margin of error. Performance Counters ASP.NET provides a rich set of performance counters to help in diagnosing and monitoring the health and performance of your web applications. They are split into two major categories: ASP.NET and ASP.NET Applications. One will also notice on any ASP.NET installation that there are also 2 other categories with similar names, but with version information attached. This is to support the side-by-side features of the CLR and ASP.NET, where two releases of them can run side-by-side on the same server for compatibility purposes. The ASP.NET and ASP.NET Applications categories will always report the data for the highest version installed and are provided as a simpler way to always access the data from the latest version. Here are some guidelines when monitoring the performance counters: These are typically the counters that should always be monitored (items listed in Category, Counter order): Processor, % CPU Utilization Gives machine level CPU utilization. Low CPU utilization or inability to make it near max regardless of client load often signifies contention for a lock or a resource in the app. ASP.NET, Requests Queued Gives the number of requests waiting to be processed. When this number starts to increment linearly with respect to client load, one has then reached the limit of concurrent requests processed on the machine. There is a set default maximum for requests queued, which is 5,000. It is configurable via the machine.config file, though. ASP.NET Applications, Requests/Sec The current throughput of the application. Under constant load, this number should remain within a certain range, barring other server work (i.e. garbage collection, cache cleanup thread, external server tools, etc). ASP.NET Applications, Errors Total A well functioning web server should not be generating errors. Errors in ones application may skew any throughput results because of very different code paths for error recovery. Investigate and fix any bugs in ones application before performance testing. ASP.NET, Application Restarts, ASP.NET, Worker Process Restarts These two are useful because it tells how often ones application is getting reset on the server. An application restart can occur because of changes in configuration, bin assemblies and too many page changes. The worker process can be restarted due to fatal crash of it or due to controlled recycling. In either case, unexpected increases in these counters may point to unforeseen problems in the applications and should be investigated These counters are also interesting for investigating possible problems: System, Context Switches/sec This counter indicates the rate at which thread context are switched by all CPUs in the machine. A high number often indicates either high contention in locks or many switches between user and kernel mode by the thread. Further investigation with sampling profilers and other tools may be warranted. ASP.NET Applications, Pipeline Instance Count This counter gives the number of request pipeline instances that exist for that application. Since only one thread of execution can be running within a pipeline instance, this number gives the maximum number of concurrent requests that are being processed for a given application. It is often better to have this number be low when under load, which signifies that the CPU is being well utilized. .NET CLR Exceptions, # of Exceps Thrown This is a CLR counter that tells the number of exceptions thrown within an application. Any exceptions thrown in an application can have performance implications, so it may be good to monitor this. Note, though that some code paths rely on exceptions for their proper functioning, so dont be alarmed in those situations. A good example is the Response.Redirect method, which does its work by throwing an uncatchable exception, ThreadAbortException. As such, it may be more useful to track this value with the Errors Total counter to see if the exception indeed generated into an error on the application. Tracing ASP.NET has a built in tracing facility that allows one to obtain trace information on a page or application level. This is a good way to include debug type statements without having to resort to messy Response.Write methods or custom mechanisms. It provides details like the structure of the pages web form control tree; server variables, headers and cookies; the form or query string parameters; size of the viewstate generated for a control; and timing information in processing each subtree of the control tree. It is often a good and quick way to get rough ideas of the performance of a page. The ASP.NET documentation covers how to activate it and retrieve the data, so please refer to it. Profiling Since ASP.NET is running on top of the CLR, it is now possible to profile a web page completely, from its entry point, through any middle tier objects and to its end. This is something that was not possible in ASP and provides a great tool for performance work in ASP.NET. All CLR profiles are able to profile ASP.NET pages it is strongly urged that anyone doing performance work pick a profiler, learn to use it well and leverage this when doing ones analysis. There are 2 major types of profilers: call attributed and sampling. Call attributed instruments all calls and can give specific timings for each method and their children. This is the most useful type of profiling when analyzing code paths and trying to trim them. Their biggest pitfall is that if execution runs through any code path that hasnt been instrumented (i.e. often when calling COM or native methods from ASP.NET), the profiler cant keep track of the times and attributes them to the last method that was instrumented. One thing to note is that given the profiling services of the CLR, there is no need to instrument ones code beforehand it is done at runtime. A sampling profiler is different in that no instrumentation needs to be done beforehand it works by sampling the CPU at specified intervals or due to CPU interrupts and keeping track of what code is executing. It can then provide to the user a view of what code was most often executing during that period of time. This type of profiling is most useful for troubleshooting lock/resource contentions and hot spots in the code. A final thing to keep in mind is that it is often good to skip the first request and/or any one time initialization costs when doing steady-state running analysis. Specific tips and tricks Language independence All languages in the CLR get compiled down to Intermediate Language (IL), which basically means that any given language subset will have similar performance characteristics. Of course what makes a language interesting and useful is more than a simple syntax, but the other features it has. Using some of these could have performance impacts. A couple of guidelines: Use the type-specific, early bound features in the language. Some languages, like VB and Jscript .NET allow for late-bound code to be easily written. Try to avoid using that feature and turn on the more strict, early bound checks, since using late-binding will entail more work for the CLR during execution of the page. Enumerating into collections sometimes is more expensive than index access in a loop. This is because the CLR can sometimes optimize array indexes and bounds checks away in loops, but cant detect them in foreach type of code. JScript .NET allows methods within methods to implement these in the CLR required a more expensive mechanism which can be much slower, so avoid them by moving inner methods to be just regular methods of the page. In any case, its important to understand that while any given language is equal in the eyes of the CLR, specific features that they expose may have grave performance impacts. Interop Running code in both managed and unmanaged worlds can be expensive. It is preferable to migrate legacy components to managed components to avoid these problems, but this is sometimes not possible (especially in initial migration of applications). As such, there may be ways to minimize the performance impact. One of the biggest reasons for the performance hit is the cost of marshalling data between the two worlds. Because of that, when doing interop, try to make the calls be chunky (i.e. do more work on either side of the fence and try to avoid lots of calls). The cost of marshalling the data ranges from relatively cheap (i.e. int, bool) to more expensive (i.e. strings). Strings, a common type of data exchanged for web applications, can be expensive because all strings in the CLR are in Unicode, but COM or native methods may require other types of encoding (i.e. ASCII). Also, try to avoid STA (Single Threaded Apartment) COM components. They need to be run in ASP.NET in a different mode (ASPCompat=true) with a different thread pool. This particular topic is covered in more detail next. Finally, do release any COM objects or native resources as soon as youre done with them. This allows other requests to utilize them, as well as minimizing performance issues, such as having the GC release them at a later point. ASPCompat ASP.NET by default doesnt allow any STA (Single Threaded Apartment) COM components to be run within a page. To do so, one must enable the ASPCompat=true mode on the page. What this does is switch the thread pool used for the execution to an STA thread pool, while also allowing the context and other objects to be available to the COM object. The former is also a performance optimization, because it avoids any marshalling of calls from MTA (Multiple Threaded Apartment) to STA threads. Using an STA COM component can be a significant performance hit and should be avoided if possible. If this cant be done, like in any interop scenario, avoid making lots of calls during an execution and try to make them as chunky as possible. Also, be careful to not to construct any STA COM components during the construction of the page. See the following code snippet: <%@ Page Language="VB" ASPCompat="true" %>
|
Responses
|
| Author: Sincere Seeker 16 Mar 2006 | Member Level: Bronze Points : 0 | Please provide the original source..
|
|