Please consider the branch prediction too before answering this question.
I have some scenarios where i can replace a conditional statement with a call to a function with the help of function pointer.Some thing like this. (you can think of component based programming over inheritance for a similar type of senario)
class Shape
{
float Area()
{
if(type == SQUARE)
{
return length*length;
开发者_Python百科 }
else if(type == RECTANGLE)
{
return length*breadth;
}
}
}
The same class can be written like this.
class Shape
{
void SetAreaFunction(void *funcptr)//this function is used to set the current AreaFunc
{
CurrentAreaFunc = funcptr ;//this holds the pointer to current area func
}
float SqauareArea();//this will return square area
float RectangleArea();//this will return rectangle area
float Area()
{
currentAreaFunc();
}
}
IF you consider the above cases, both achieves same results.But, I'm thinking about the performance overhead.In the second case I'm avoiding having branch prediction problem by having a function call.
Now let me know which is the better practice and 'better optimized code' in this kind of senarios.(btw, I don't like the statement "Pre-mature optimization is root of all evil" as, optimization has its benefits so i do consider optimizing my code!)
P.S: I don't mind if any one give a detailed overview about 'how bad branch prediction can be" even in assembly code.
Update: After profiling (similar kind of above code),
If Condition succeeded in this kind of senario.Can any one give a reason for this? Functional call code can be prefetched as there is no Branching code right? But here its looks the other way..branching code wins! :O Profiled on Intel Mac Osx,GCC O3/Os optimisation.You replaced an if statement with an indirection.
Both your if statement, and the indirection requires memory access.
However, the if will result in a short jump - which will probably won't invalidate the pipeline, while the indirection may invalidate the pipeline.
On the other hand, the indirection is a jump, while the if statement is a conditional jump. The branch predictor may miss.
It is hard to tell which is faster without testing it. I predict that the if statement will win.
Please share your results!
You need to profile such code to be able to make a certain statement for a specific environment (compiler, compiler version, OS, hardware) and you need to measure in a specific application to be able to know whether this even matters for that application. Unless you are writing library code, do not bother except for when profiling has shown this to be a hot spot in your application.
Just write the most readable code, that is easiest to maintain. It's always easier to optimize clean, bug-free, and easily readable code than to fix bugs optimized code.
That said, I remember Lippman in his The C++ Object Model citing research that has found virtual functions (basically function pointers) to be at least as fast as switching over types in real-world applications. I don't know the details, but it's somewhere in the book.
It is more likely that the optimizer can apply his magic on the if statement, then on a dynamically changing function pointer. Just a guess, theoretically the compiler is allowed to do anything that he can prove does not change the semantics.
But in the case you do not call a function but only implement a branch (using an if
in your case) the CPU is more likely to apply its magic, i.e. reorder instructions, prefetching things and the like. If there is an function call in between most CPUs will very likely "flush" their pipelines and CPU-optimization will not be possible.
That said, if you put everything inside a header, caller and callees, the compiler may do away with functions calls, will reorder stuff itself and so on.
Try to measure it yourself. Call it 1M times. With C++11 use <chrono>
, monothonic_clock::now()
.
Update: My experience is: Don't over-optimize your code my hand -- it is very likely that you make it worse. Let the compiler do the work, and for that make as much code visible to it as you can. If you do, you definitely need a profiler, try out alternatives, use the hints some of them offer you. But don't forget: This must be fine-tuned very carefully. Only one measurement of performance is speed. There is also readability, testability and reusebility and many more. And to quote Donald Knuth: "Premature optimization is the root of all evil."
精彩评论