The Tuning Game System Limitations and What to Tune

- 9 - when it is too difficult to determine method calls at compile time, as is the case for many Java methods. Of course, the same Java language features that cause these overheads may be the features that persuaded you to use Java in the first place. The important thing is that none of these overheads slows the system down too much. Naturally, too much is different depending on the application, and the users of the application usually make this choice. But the key point with Java is that a good round of performance tuning normally makes your application run as fast as you need it to run. There are already plenty of nontrivial Java applications, applets, and servlets that run fast enough to show that Java itself is not too slow. So if your application is not running fast enough, chances are that it just needs tuning.

1.2 The Tuning Game

Performance tuning is similar to playing a strategy game but happily, you are usually paid to do it. Your target is to get a better score lower time than the last score after each attempt. You are playing with, not against, the computer, the programmer, the design and architecture, the compiler, and the flow of control. Your opponents are time, competing applications, budgetary restrictions, etc. You can complete this list better than I can for your particular situation. I once attended a customer who wanted to know if there was a go faster switch somewhere that he could just turn on and make the whole application go faster. Of course, he was not really expecting one, but checked just in case he had missed a basic option somewhere. There isnt such a switch, but very simple techniques sometimes provide the equivalent. Techniques include switching compilers , turning on optimizations, using a different runtime VM, finding two or three bottlenecks in the code or architecture that have simple fixes, and so on. I have seen all of these give huge improvements to applications, sometimes a 20-fold speedup. Order-of-magnitude speedups are typical for the first round of performance tuning.

1.3 System Limitations and What to Tune

Three resource s limit all applications: • CPU speed and availability • System memory • Disk and network inputoutput IO When tuning an application, the first step is to determine which of these is causing your application to run too slowly. If your application is CPU -bound, you need to concentrate your efforts on the code, looking for bottlenecks, inefficient algorithms, too many short-lived objects object creation and garbage collection are CPU-intensive operations, and other problems, which I will cover in this book. If your application is hitting system-memory limits, it may be paging sections in and out of main memory. In this case, the problem may be caused by too many objects, or even just a few large objects, being erroneously held in memory; by too many large arrays being allocated frequently used in buffered applications; or by the design of the application, which may need to be reexamined to reduce its running memory footprint. - 10 - On the other hand, external data access or writing to the disk can be slowing your application. In this case, you need to look at exactly what you are doing to the disks that is slowing the application: first identify the operations, then determine the problems, and finally eliminate or change these to improve the situation. For example, one program I know of went through web server logs and did reverse lookups on the IP addresses. The first version of this program was very slow. A simple analysis of the activity being performed determined that the major time component of the reverse lookup operation was a network query. These network queries do not have to be done sequentially. Consequently, the second version of the program simply multithreaded the lookups to work in parallel, making multiple network queries simultaneously, and was much, much faster. In this book we look at the causes of bad performance. Identifying the causes of your performance problems is an essential first step to solving those problems. There is no point in extensively tuning the disk-accessing component of an application because we all know that disk access is much slower than memory access when, in fact, the application is CPU-bound. Once you have tuned the applications first bottleneck, there may be and typically is another problem, causing another bottleneck. This process often continues over several tuning iterations. It is not uncommon for an application to have its initial memory hog problems solved, only to become disk-bound, and then in turn CPU-bound when the disk-access problem is fixed. After all, the application has to be limited by something, or it would take no time at all to run. Because this bottleneck-switching sequence is normal—once youve solved the existing bottleneck, a previously hidden or less important one appears—you should attempt to solve only the main bottlenecks in an application at any one time. This may seem obvious, but I frequently encounter teams that tackle the main identified problem, and then instead of finding the next real problem, start applying the same fix everywhere they can in the application. One application I know of had a severe disk IO problem caused by using unbuffered streams all disk IO was done byte by byte, which led to awful performance. After fixing this, some members of the programming team decided to start applying buffering everywhere they could, instead of establishing where the next bottleneck was. In fact, the next bottleneck was in a data-conversion section of the application that was using inefficient conversion methods, causing too many temporary objects and hogging the CPU. Rather than addressing and solving this bottleneck, they instead created a large memory allocation problem by throwing an excessive number of buffers into the application.

1.4 A Tuning Strategy