O p t i m i z i n g
February 22nd, 2008
I spent the last few days profiling and optimizing one of our app’s primary GUI screens. Here are some observations:
- Our app includes a built-in diagnostic tool that logs every server call. We can bring up a dialog and watch the calls as they occur. For our first optimization, we moved one of these calls off the EDT to a SwingWorker. Although the call itself only took 10-30ms, it was called often enough to introduce noticeable sluggishness. Having built-in diagnostic tools is priceless, because you can monitor what is happening behind the scenes.
- NetBeans includes a decent profiler, and the price is right: $0. Despite using IDEA for most coding, I always turn to NetBeans for profiling. IDEA could really use an integrated profiler.
- Having a super fast PC is helpful, because profiling is extremely taxing on your system. I don’t have a super fast PC, which makes the profiling experience painful and tedious.
- Despite the pain of a slow PC, profiling is very rewarding when you find a problem and fix it.
- We found several hot spots — NetBeans does a great job making these obvious. Each time we’d fix one issue, we’d run our scenarios again and find the next most critical issue.
- When optimizing, start with the worst hot spot and work your way down the list. A “hot spot” might mean a method is called once and consumes 13 seconds, or perhaps a method only takes 3 milliseconds but is called 800,000 times.
- Profiling is always surprising. One bottleneck was caused by an obvious programming error, and that error has been in our code since 2005. Ouch.
- You will hit dead ends. For example, one hot spot involves a small helper class that is executed tens of thousands of times. Unfortunately, the code is mutable with a wide open public API, making optimization quite hard. If this class was immutable and had fewer methods, I’m sure I could optimize it further.
- I try to fire up the profiler and spend time looking for problems before customers complain about bugs. I tend to focus on either runtime performance or else memory leaks, but generally not both in the same session. I may spend a few days each month focusing on one or the other.
- Optimizing always involves risk. Fixing one thing may introduce a new bug, so proceed with caution. Mitigate this risk by focusing on the most critical bottlenecks first. Optimize enough to make these bottlenecks go away, but don’t go so far that your code becomes unmaintainable.
- I found that after optimizing, the code is often cleaner than before. This might seem counter intuitive, but spending time meticulously analyzing a particular method line-by-line often gives you insight into better implementations. It think it is wrong to blindly assume that all time spent on optimization and efficiency necessarily leads to cryptic code.