Java Specialists' Java Training Europehome of the java specialists' newsletter

The Java Specialists' Newsletter
Issue 0662003-03-21 Category: Book Review Java version:

GitHub Subscribe Free RSS Feed

Book Review: Java Performance Tuning by Jack Shirazi

by Dr. Heinz M. Kabutz
Abstract:
In this book, Jack outlines the process used to make Java systems run faster. He gives lots of tips on how to find your bottlenecks and then also gives specific tricks to make your code just that bit faster. A must-have for Java programmers who care about the speed of their programs.

Welcome to the 66th edition of The Java(tm) Specialists' Newsletter, sent to 6138 Java Experts in 94 countries. The newslist server is going to start throwing out dead email addresses, so the side effect is that the number of subscribers will likely decrease. If you did not receive this email, please respond by replying to this email and telling me that you did not receive it.

Last week I had great fun with some programmers in Frankfurt. We did the Design Patterns Course and good laughs together and of course we all learned new things. Thanks especially to my friend Carl Smotricz (who used to host our newsletter archive) for organising this event. One of the highlights of my trip was meeting with some of our newsletter subscribers for a good German beer.

Meeting Jack Shirazi

During my recent travels, I had the opportunity to meet with Jack Shirazi, famous as the author of the landmark book Java Performance Tuning. Besides consulting on performance related issues, Jack also maintains an excellent website, which is the #1 resource for expert Java programmers who want to keep up to date with Java performance. I particularly like his website because true to the topic, it is fast to navigate. The website does not look particularly pretty, but you can easily get to the information you want. There are no frames, no pictures, no special fonts, but gosh, does it render quickly! When I chatted to Jack about this, he told me that according to the principles in his book, the fastest content that you could possibly serve is static content, i.e. content that is not dynamically generated. Jack therefore generates his entire website and uploads the differences. This works because the content does not change all the time, it would be a bit difficult to build an entire internet banking site like this. However, even the internet banking site should be serving static content whenever this is possible.

Jack and I spent a good few hours chatting about all sorts of topics, from the state of consulting to business ideas, to how many kids we have (at this point I knew that Jack was hopelessly superior at a 3:1 ratio and we agreed to decide on greatness by means of an arm-wrestle). The waitress was quite amused since neither of us really had any idea of what we were doing. There are two types of people in this world: those that can program, and those that can arm-wrestle. Our inability to achieve neither victory nor defeat has placed us firmly into the camp of programmers :-)

Ah, here is a good job interview question: "Hi, so you want to work for the XYZ company where we build important software. What did you think of the {rugby|cricket|soccer|football|basketball|baseball} game on Saturday?" An answer like "Was there a match? Who played?" will get you the job as programmer without any further questions, but saying "Yeah, Ted performed well - he has recovered well since his knee operation that he had in high school - he went to Osborne High from 1984-1989 where he was Valedictorian, did you know?" will only get you a position in the sales department. Mind you, the sales department is not a bad place to be - at least you can watch sport on the weekend and tell your boss and spouse that you are doing important work.

Let us not get sidetracked...

NEW: Please see our new "Extreme Java" course, combining concurrency, a little bit of performance and Java 8. Extreme Java - Concurrency & Performance for Java 8.

Java Performance Tuning 2nd Edition

Naturally I did not just travel 10000km to speak to Jack about kids and lucrative consulting jobs. [To those of you who do not have kids, once you have them, you will realise that they are far more important than anything else in life, even Java.]

The real reason I met with Jack was to speak about the 2nd Edition of his book Java Performance Tuning. When Jack wrote the first edition of his book, there was not much else available. The one book that I have mentioned in this newsletter is Java 2 Performance and Idiom Guide, and that was available before Jack's. However, Jack's book focuses far more on performance than the other book. In addition, Jack adds value to the reader with his informative website that is worthwhile to explore.

The book contains chapters on the following performance topics:

  • Chapter 1 gives general guidelines on how to tune. It will help you to formulate a good tuning strategy following a methodical process.
  • Chapter 2 covers the tools you need to use while tuning.
  • Chapter 3 looks at the SDK, including Virtual Machines (VMs) and compilers. Jack does not cover JDK 1.4.1, only up to JDK 1.4.0. This is understandable, because at the time of writing, JDK 1.4.1 had not been released.
  • Chapters 4 - 12 cover various techniques you can apply to Java code.
  • Chapter 12 looks at tuning techniques specific to distributed applications.
  • Chapter 13 steps back from the low-level code-tuning techniques examined throughout most of the book and considers tuning at all other stages of the development process.
  • Chapter 14 is a quick look at some operating system-level tuning techniques.
  • Chapters 15 - 18 are new in this edition, providing the information you need to tune J2EE applications. Chapter 15 describes tuning considerations that are common to all J2EE applications. Chapter 16 looks at specifics for tuning JDBC, including optimizing transactions and SQL, while Chapter 17 provides important information for speeding up servlets and JSPs. Chapter 18 describes performance considerations for Enterprise JavaBeans (EJBs).
  • Finally, Chapter 19 covers a wide range of additional resources where you can learn more about Java performance tuning.

Chapter 1: Introduction

The book starts with a chapter outlining a performance tuning strategy that you should follow when attempting to tune an application. Follow it, and you will be successful. Ignore it, and you will forever be tuning and never get any acknowledgements for your achievements. At the end of each chapter is a performance checklist of the major points of that chapter. For example:

  • Specify the required performance.
  • Make your benchmarks long enough: over five seconds is a good target.
  • Break down distributed application measurements into components, transfer layers, and network transfer times.
  • Tune systematically: understand what affects the performance; define targets; tune; monitor and redefine targets when necessary.
  • Work with user expectations to provide the appearance of better performance.
  • Quality-test the application after any optimizations have been made.
  • Document optimizations fully in the code. Retain old code in comments.

Chapter 6: Exceptions, Assertions, Casts, and Variables

Many moons ago, when Java had just been invented, programmers invented strange ways to write optimal code. One of the weirdest abominations was the logic that a try/catch was for free when no exception was thrown and that it was cheaper than if and instanceof statements. For example:

public class TryCatch {
  public static boolean test1(Object o) {
    try {
      Integer i = (Integer)o;
      return false;
    } catch(Exception e) {
      return true;
    }
  }

  public static boolean test2(Object o) {
    if (o instanceof Integer) {
      Integer i = (Integer)o;
      return false;
    } else {
      return true;
    }
  }
}

The thinking was that a try block was free, so therefore if you almost always have Integer objects, it will be faster to just cast and hope for the best, than to first test if it really is an Integer. test1() should therefore be faster than test2() most of the time, unless we passed in an object that was not an Integer.

But is it really faster? Let us have a look:

public class TryCatchCostTest extends TryCatch {
  public static void main(String[] args) {
    Integer i = new Integer(3);
    Boolean b = new Boolean(true);
    long TEST_DURATION = 2 * 1000;
    boolean res;
    long stop;

    stop = TEST_DURATION + System.currentTimeMillis();
    int test1_i = 0;
    // we do not want to test with every increment, otherwise the
    // call to System.currentTimeMillis() will dwarf the rest of
    // our calls.
    while(((test1_i % 1000) != 0) 
        || (System.currentTimeMillis() < stop)) {
      test1_i++;
      res = test1(i);
    }
    System.out.println("test1(i) executed " + test1_i + " times");

    stop = TEST_DURATION + System.currentTimeMillis();
    int test1_b = 0;
    while(((test1_b % 1000) != 0)
        || (System.currentTimeMillis() < stop)) {
      test1_b++;
      res = test1(b);
    }
    System.out.println("test1(b) executed " + test1_b + " times");
    System.out.println("test1(i) was " + (test1_i / test1_b)
                       + " times faster");

    stop = TEST_DURATION + System.currentTimeMillis();
    int test2_i = 0;
    while(((test2_i % 1000) != 0)
        || (System.currentTimeMillis() < stop)) {
      test2_i++;
      res = test2(i);
    }
    System.out.println("test2(i) executed " + test2_i + " times");

    stop = TEST_DURATION + System.currentTimeMillis();
    int test2_b = 0;
    while(((test2_b % 1000) != 0)
        || (System.currentTimeMillis() < stop)) {
      test2_b++;
      res = test2(b);
    }
    System.out.println("test2(b) executed " + test2_b + " times");
  }
}

When I run this test on JDK 1.4.1_01 with my Pentium 4m 1.7GHz, I get the following values under client hotspot:

test1(i) executed 22700000 times
test1(b) executed 126000 times
test1(i) was 180 times faster
test2(i) executed 52420000 times
test2(b) executed 53015000 times

Oops, it appears that logic was incorrect! test2() is about twice as fast as the best test1()! How does this look with the server hotspot compiler?

java -server TryCatchCostTest
test1(i) executed 50310000 times
test1(b) executed 43000 times
test1(i) was 1170 times faster
test2(i) executed 51915000 times
test2(b) executed 51952000 times

The difference between test1() and test2() is not as pronounced as with the client hotspot, but test2() is still marginally faster. However, the version of test1() that causes the exception has become three times slower!

Under what circumstances did this idea proliferate? My suspicion is that it used to be true for the interpreted version of Java, probably around JDK 1.0. Have a look at what happens when we run this test with the -Xint switch. It appears that test1(i) is indeed faster!

java -Xint TryCatchCostTest
test1(i) executed 19153000 times
test1(b) executed 180000 times
test1(i) was 106 times faster
test2(i) executed 14522000 times
test2(b) executed 18719000 times

The book is great in that for all important statistics, it compares performance results for Sun JDK 1.1.8, 1.2.2, 1.3.1, 1.3.1 -server, 1.4.0, 1.4.0 -server and 1.4.0 -Xint. This is probably the most useful part of the book, and also lends credibility to the statements that Jack makes. If Jack makes a statement without proof, you cannot assume that it is true. However, when the statement is backed up with values, you can be assured that it is probably correct.

Can you paint yourself into a corner?

Kent Beck is famous for his phrase: "Make it run, make it right, make it fast."

Unless we can compile it, we do not need to try tune the performance. Once we get it to compile, we have to make sure that it is correct. What is the point of having a blazingly fast algorithm that is incorrect? I can sort any collection of elements in O(1) if it does not have to be correct.

In my doctoral thesis, I examined how one could analytically evaluate the performance of a distributed system written in the Specification and Discription Language (SDL). Since there were few analytical techniques for performance evaluation of SDL systems, I converted SDL to a new form of Petri net based on the Queuing Petri Net invented by the University of Dortmund. There are many correctness and performance testing techniques for Petri nets, so the first step was to determine whether the net contained deadlocks, was unbounded or had livelocks. Once the correctness had been determined, I could apply the numerous performance techniques to the net and then convert the results back to the original SDL system.

Due to the complexity of the Markov Chain that was generated from the Petri net, we could only analyse small systems, but then, it was a doctoral thesis, not a commercial product. You are allowed to dream a bit in theory when you do a PhD, infact, a PhD is where you investigate everything about nothing.

In the real world, we usually stop after the first test: "does it compile?" Most software in the world has not been tested before being delivered. Why? Because testing that it works correctly is a tedious job that takes time and programmers do not make mistakes anyway. I am yet to walk into a company and ask whether they have unit tests, without getting a nervous reaction. When I then ask what they are doing about performance I get an even more nervous reaction.

When the system then performs badly, they have to call in trouble-shooters like Jack and myself to tune their applications. Performance involves both CPU times and memory sizes. A few newsletter ago, I casually asked whether you wanted to know how to detect OutOfMemoryErrors ahead of time. More than 100 readers responded that they were in desperate need of such a tool. Jack and I do not mind this state of affairs at all - that is a good way to earn our keep. However, you will have a problem when you need Jack and me but you cannot afford our rates. Then you will kick yourself for putting performance last.

I asked Jack about the philosophy of "Make it run, make it right, make it fast" and Jack mentioned to me that there are situations where this does not work. There are ways in which you can paint yourself in a corner so that the only alternative is to throw away the application and start again. This piqued my curiosity, and I asked Jack for an example.

"An example of painting yourself in the corner is when you do not use the Page-by-Page Iterator Design Pattern from the beginning"

As I thought about the troubled projects I had consulted for, I realised that Jack was correct. You can get a better optimising compiler, you can reduce the number of Strings that get created, you can change the collection you use, but if you do not have the Page-by-Page Iterator Design Pattern in your design from the beginning, you will be p*ssing against the wind. This applies for 3-tier and for 2-tier applications. The P-b-P Iterator can be added to your system after-the-fact, but it will require plenty of work and cause errors.

Conclusion

Should you purchase the Java Performance Tuning Book? There is no easy answer to that question. If you do not have the US$ 44.95 to pay for the book, it will be unlikely that you will be able to afford to pay for Jack or me to help you tune your system. Basically, you would be on your own. You can also browse Jack's website or look at our newsletter archive. Otherwise, if you are serious about writing good Java code that is well-tuned, you would do well to purchase a copy of Jack's book, and read through it over a period of a few months.

That is all I have to say on this topic. The book could be converted into about 30 newsletters, that is how much information is contained therein.

Kind regards

Heinz

Book Review Articles Related Java Course

Extreme Java - Concurrency and Performance for Java 8
Extreme Java - Advanced Topics for Java 8
Design Patterns
In-House Courses

© 2010-2016 Heinz Kabutz - All Rights Reserved Sitemap
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. JavaSpecialists.eu is not connected to Oracle, Inc. and is not sponsored by Oracle, Inc.