sabato 3 aprile 2010

Efficient C Tip #11 - Avoid passing parameters by using more small functions

Efficient C Tip #11 - Avoid passing parameters by using more small functions: "This is the eleventh in a series of tips on writing efficient C for embedded systems. Today's topic will, I suspect, be slightly controversial. This post is based upon two basic observations:

  1. Passing parameters to functions is costly.

  2. Conditional branch instructions can be very costly on CPUs that have instruction caches (even with branch prediction).


I don't think that too many people will disagree with me on the above. Despite this I too often see a style of coding that incurs these costs unnecessarily. I think it's best illustrated by a (real world) example. The issue is one that will be familiar to most of you.  An embedded system contains a number of discrete LEDs (say 3), and the requirement is to write some code to allow higher level code to either turn on, turn off, or toggle a particular LED. The way I often see this coded is as follows:
typedef enum
{
LED1, LED2, LED3
} LED_NO;

typedef enum
{
LED_OFF, LED_ON, LED_TOGGLE
} LED_ACTION;

void led(LED_NO led_no, LED_ACTION led_action)
{
switch (led_no)
{
case LED1:
switch (led_action)
{
case LED_OFF:
PORTB_PORTB0 = 0;
break;

    case LED_ON:
PORTB_PORTB0 = 1;
break;

    case LED_TOGGLE:
PORTB_PORTB0 ^= 1;
break;

    default:
break;
}
break;

 case LED2:
...
}

So what's wrong with this you ask? Well in a nutshell the parameters passed to the function are used strictly to control the order of execution. There is no code common to any pair or group of parameters. When faced with a situation such as this, I instead implement the code as a large number of very small functions. For example:
void led1_Off(void)
{
PORTB_PORTB1 = 0;
}

void led1_On(void)
{
PORTB_PORTB1 = 1;
}

void led1_Toggle(void)
{
PORTB_PORTB1 ^= 1;
}
...

Let's compare the two approaches.

Efficiency


This blog posting is supposedly about efficiency, so let's start with the results. I coded these two approaches up together with a main() function that exercised all 9 possible combination's. I then turned full speed optimization on and looked at the results for an AVR processor.

Single function approach: 78 bytes for main(), 94 bytes for the LED code. Execution time 208 cycles.

Multiple function approach: 42 bytes for main(), 54 bytes for the LED code. Execution time 96 cycles.

Clearly my approach is significantly more efficient.

Usability


By usability I'm referring to the case where someone else needs to use your code. They know they need to say toggle LED2 so they hunt around and find the file led.h. The question is, once they have opened up led.h, how quickly can they determine what they have to do in order to toggle LED2? In the single function case they are presented with just one function (which is a plus), but then they have to locate the enumerations and work out the parameters that need to be passed to the function (which is a minus). In the multiple function case, they have to search through a list of functions looking for the correct one. However once they have found it, it's very clear what the function does.

For me, I think it is a toss up between the two approaches as to which is more usable.

Maintainability


In this case the multiple function approach is the big winner. To see how this is, consider what happens to the single function case when one adds an LED or adds an action. The single function case just explodes in size, whereas with the multi-function approach one simply adds more very simple functions.

Conclusions


If you buy my analysis then clearly the multi-function approach is superior in both efficiency and maintainability - two areas that are dear to my heart. Now granted this is a fairly extreme example. However in my experience if you look through a reasonable amount of code you will soon discover a function that essentially does one thing or another based upon a function parameter. When you locate such a function you might want to try breaking it into two functions in the manner described here - I think you'll be pleased with the results.  Previous Tip

****
As the readership of this blog has grown I must say I have been really impressed with the many insightful comments that have been posted. I know I learn a lot from them, and so I suspect, do a lot of the other readers. Thus for those of you that have commented in the past - thank you. For those of you yet to post a comment, I encourage you to take the plunge!

Home"

Nessun commento:

Posta un commento

Nota. Solo i membri di questo blog possono postare un commento.