A Discussion on Performance Optimizations

Dennis J. McWherter, Jr. bio photo By Dennis J. McWherter, Jr. Comment

Anyone who has ever taken a computer science course is familiar with the phrase, €œpremature optimization€ and its negative connotation. It is true that this is something which will often waste time, but how do people identify when they€™re prematurely optimizing? When do you know you should be optimizing? If you€™re not optimizing performance, should you be careless? If not, what should you focus on? These are only a few of the questions that arise from this phrase and we€™re going to tackle them together right here.

I thought highly optimized code was a good thing?

It is. That being said, due to Parkinson’s Law, you will always have more work to do. Consequently, if you focus on optimizing too early you risk optimizing trivial pieces of your product and using an exorbitant amount of time to do it. At the end, you could very well find that you highly optimized a piece of code that simply gets executed once at initialization– that is not likely a good use of your time.

Am I prematurely optimizing?

This question is one of the easier ones to answer. Simply put: have you noticed a problem yet? If not, chances are that the code you’re optimizing for performance is not actually a bottleneck in your system. Even if the code “looks slow,” your processing load or number of times this section is executed may negate this problem and it is likely “fast enough” for your purposes. Instead, this time would be much better spent optimizing for readability. As I mentioned before, writing code is like writing any piece of literature. That is, it should be edited heavily from the first draft for clarity and understanding. For non-trivial bits of code, it is nearly impossible to write it perfectly on the first attempt.

When should I be optimizing?

At the end. What I mean is, you should optimize after you have very high confidence that your code is correct, stable, and robust enough to handle the real world. This is not to say there won’t be bugs; there are almost always bugs that exist after we ship. Instead, this it to say that there is nothing obvious problems (after having done your due diligence to search for them) with your system. Even now, you shouldn’t think about optimizing just yet. Instead, run a few more tests and experiments under a production-like load through your full system and determine whether or not it is ready for production use. If what you have is working and is performant enough for your use case, optimizing would be wasteful of resources that could be spent improving your product’s features. On the other hand, you should always budget a little time at the end of the project for the case where you do need to optimize since this could take some time.

What should I focus on when not optimizing performance?

First and foremost, you should focus on correctness. You want to ensure that the algorithm you are using is correct and it matches your use case well. After that, unit tests and additional coverage is far more important than optimizing right away. Think about it this way: my code can be really fast but if it does not perform the operations it’s supposed to, then it’s useless. Also, as I’ve already stated above– with modern compilers in play– readability is likely the first thing you should focus on. Clear code is incredibly valuable and compilers have become great at optimizing away basic inefficiencies from our code; this provides us the luxury of writing intelligible– yet performant– statements. When the intent is clear, readable code is more likely to become bug-free code.

If I really need to optimize, how do I do it?

Great question. I don’t have an exact answer for everyone on this, but we can go through some basic ideas.

1. Know what your optimizing. You should first understand what it is you€™re trying to optimize. For instance, performance is typically inversely proportional to energy efficiency. If you need both, you will need to calculate an acceptable trade-off, etc.
2. Understand your system. To optimize effectively you need to understand your whole system down to the operating system or hardware on which it runs. If you’re using Java, you have to understand the evaluation semantics as well as what constitutes as “expensive” in the context of the JVM. Now, you may not always know all of this immediately, but after some of your own profiling work you should be able to determine these characteristics and then work on improving them.
3a. Know where your system is spending the most time. If you don’t know where your system is slow, where do you start looking to optimize?
3b. Have proper logging and tools. In support of 3a, you need a good toolset to determine where your system is spending its time. Moreover, the toolset should give you insight into what the system is doing at that point and where the time and resources are going.
4. Know what you€™re looking at. At the end of the day, when you€™re performing analysis on your system, you need to understand the data you€™re looking at. For instance, if your system is slow and CPU is far under-utilized, perhaps you have a slow blocking call in your code or you€™re simply not using a sufficient number of threads (assuming parallel code). Whatever the problem is, you need to be able to identify it to fix it.

So, should I optimize?

My instinct tells me, €œno.€ In general, you should not try to optimize until you know you have to optimize (in which case, you probably wouldn€™t be asking me). This is not to say you shouldn€™t strive to write performant code (read: you really should and, perhaps, you can save yourself some time later), but in my humble opinion, readability should be placed far above any clever performance hacks which muddle up the code.

Have any horror stories about optimizing the wrong bits of code or premature optimization of any sort? I€™d love to hear about them! Just post in the discussion section below.

comments powered by Disqus