When I learned Python I became enamored with the idiom of dispatching, which looks something like this:
name = "foo"
function = getattr(object, "prefix_" + name)
In this way we can call
object.prefix_foo() without big switch statements or
if/else if/else if constructs.
Of course, I usually program in C. While we can’t do exactly the same thing there, the closest analogy is the function pointer:
void (*func_ptr)(void) = foo;
If you know whether
func_ptr should be
bar ahead of time, the above code is far more elegant than this:
else if (condition_b)
I’ve always heard that branches are to be avoided at all costs, since on some processors even a correctly-predicted branch can still stall the pipeline. A switch statement can be implemented by the compiler as a series of compare and conditional branches, and that would compound the problem. On the other hand, an indirect function call could be more difficult for branch prediction, and of course still requires that branch even when predicted correctly. So I ran some completely artificial and unscientific tests to see what the performance break-even point is on a sampling of real hardware: how many conditional branches can you use before it would be faster (and prettier) to use a function pointer?
I wrapped a conditional function call (as shown above) in a 1-billion count loop, and averaged the runtime of that executable over a number of runs. I found some surprises.
One surprise: on an Intel Core2, there’s almost no performance difference between using a function pointer and even a single conditional.
Another surprise was how much variation there was in the numbers. In the code sequence above, I expected that a run where
condition_a were true would be faster than
condition_b. Not always true. I expected that runs with fewer conditions would always be faster than runs with more conditions. Again, not always true, due to differences in the instruction sequences generated by the compiler and cache effects.
I won’t post the full data here because it’s so informal and hasn’t been subjected to rigorous performance analysis. The summary though is this: talking only about performance, after only 3 or so conditions on a Freescale PowerPC e500v2 core, function pointers are worth it. They’re always worth it on a Core2. If you’re curious, try your own tests and let me know how your core behaves. I’d love to know if there’s a reason not to heavily adopt function pointers in all my code…
(Oh, and as for comparison between a non-conditional direct branch vs an indirect function pointer: on the e500v2, the function pointer added about 33% overhead. The difference was negligible on the Core2.)