Sunday, 20 April 2014

Low Hanging Fruits for Performance Optimization

If you are optimizing code, the biggest gains for you are likely going to come from optimizations in software design (i.e. your data structures and algorithms) and architecture (concerns like distribution, functionality, interface, multi core, etc). But usually when you run into a system which needs to be put on sterioids, this not the first thing you should be looking at. 

Let me begin break down the optimizatin problem into three stages:

First, I have seen many teams working hard to achieve some internal goal on performance of a software sub-system/module, when the software module has very little impact on the overall system performance. For eg., a protocol stack takes just 10% CPU usage in a product sub-system. If we improve the performance of this stack by 100% (in most cases by literally burning the midnight lamp), then the impact on the overall system is hardly 5%, something which is not significant. IMO optimizations like performance modeling have to be partitioned top-down, not bottom-up as software teams might be tempted to do. At times sub-system architected when challenged with a 50% improvment might be tempted to set every module in the critical path an improvment goal of 50% so that he can meet the goal. This is not the optimal way of working as the bottlnecks have to be identified quantitatively and then targets set. The benefits must be tangible for an optimization activity to be started on any peice (or whole) in the first place. 

Second, there is no end to the performance improvment that can be achieved on software. You identify & remove one bortleneck & something else gets significant. You remove that, a third might crop up and it goes one. At some stage you will not see one bottlneck but many equal contributors the conclusion being you need to deal with all of them to go to the next one. But their has to be an end to this practically. IMO, we must leran to accept that no design is final or perfect, but their is something in between that is "Just Good Enough" for that time. Optimization takes efforts. And as you optimize further it gets tougher each time. You have to consider the value (impact) of the optimization paarmeter (throughput, latency, resource usage, etc) on the whole (entire system). At some stage you are likely going to come to the conclusion that further optimization does not yield any *tangible* benefit to the end user or the product. That's when you need to stop.

Third, we assume that we have crossed both these stages, and you are convinced about the need to optimize one step, the question of how arises. As I have already said design & architecture chnages bring big benfits, but involve the maximum risk and efforts. Before you jump to this, you need to check the "hotspots"  in the present software design. Its likely that a few functions (or even routines) in the architecture are consuming a lot of CPU. For eg., an avoiadble socket open and close, an OS System call, a partcular hash lookup, etc. Many of them are low-level coding problems. You could consider if the usage of these hotspots can be reduced (avoidance), or the bottleneck itself can be improved.  A hotspot's contribution is  the product (multiplication) of both the number of times it invoked and the cost of each invocation. Optimize either (or both) and you will observe gains. These changes are localized  at times but the common trait is that they are very simple and less risky to make. That's why I call them the "Low Hanging Fruits".

A time will come when you can't do anything more with the the hotspots or their contribution to the overall system is not dominant. That's when you need to stop the hotspot based optimization and go to the  design or architecture changes (again). Data structure design & algorithm should be the first targets in this step and we can follow if required with architectural modifications.


No comments:

Post a Comment