I highly disagree that the point of function objects is to allow runtime polymorphism. Certainly that is useful, and I have no objection to it. I like templates because they allows the compiler to optimize anything that is optimizable and doesn't make the programmer worry about it at all. This is the goal of a well designed language. A template that uses the functors will be written once and work for ALL cases and always be optimized as best as is possible byt the compiler because it is independently compiled for each case. This is a pretty impressive accomplishment and in my mind it is one of the major features of C++ that sets it way ahead of simpler languages such as Java. Not that Java doesn't have its place, but for for advanced and highly flexible designs, templates are pretty close to the perfect tool imho.
Just look at the STL. Its sort is faster than ones that most people hand code and it works with any datatype and can be passed functors... Pretty impressive, highly flexible (any datatypes and any way of sorting) and it is generally optimized to be as fast or faster than anything that ever really good programmers create for their one specific case. That is the power of templates. And the best part is that if a better algorithm comes along in 2 years, only one function needs to be changed instead of 200 different sorting functions. That is indicative of a good design. But this has nothing to do with Effective Go Library anymore. With regard to what you wrote about the branch always being predicted correctly ... you are correct assuming there are not too many branches in the code. The processor has a table that stores these branches but that table is only of a certain size. Anyway, it doesn't really matter much because future processors are likely to change how they function anyway. Templated code is an ideal solution though because it abstracts a concept from the specifics of how it is implemented which gives maximum flexibility and close to perfect optimization. And my number of 50... I didn't even think about it, but I got it from some calculations I did a long time ago. Yeah, really kind of a meaningless number now that I think about it. On 2/16/07, Luke Gustafson <[EMAIL PROTECTED]> wrote:
Lukasz, any chance you can access the assembly to see how the compiler optimized it differently? That is a strange result. All that I could think of is, if you have several places where the function is called, and the compiler used to be inlining it, it may be faster (for cache reasons) to make it a function call instead of inlining. Inlining is not always fastest! Regarding function pointers--from Agner Fog's guide: "3.7 Indirect jumps (all processors except PM and Core2) Indirect jumps, indirect calls, and returns may go to a different address each time. The prediction method for an indirect jump or indirect call is, in all processors except PM and Core2, simply to predict that it will go to the same target as last time it was executed. The first time an indirect jump or indirect call is seen, it is predicted to go to the immediately following instruction." (The Pentium M & Core2 have more sophisticated indirect jump prediction) So, if a function pointer always points to the same function, all processors will predict the branch correctly! I am doubtful function objects would be much faster, except that they may be more likely to be inline-able. Also I disagree that well-designed code should cause function objects to be predicted at compile time--it seems to me that their purpose is for run-time polymorphism! >I will just tell You about my experiences: > > - allmost all code of benchmark in Ego library is inlined (remove_stone is > not) > - function pointer are usually inefficient, because jump prediction works > poorly > - when I introduced a parameter to simple_playout::run: function > pointer that replaced play_one and always put address of play_one > there, then the code was slightly faster. > I have *no idea* why it was so. > > - and most important: KISS > > Lukasz > > > On 2/16/07, Darren Cook <[EMAIL PROTECTED]> wrote: >> >> trouble. Also, the alternative is usually function pointers which >> >> have >> >> atleast 50 times the overhead of a function object. Correct me if I'm >> >> wrong. >> >> >> > function objects really cannot be 50 times more efficient as function >> > pointer are rather efficient with very little overhead. >> >> With well-designed code, function objects ("functors") should be >> compiled inline, and have zero overhead. Function pointers are never >> inlined (unless modern compilers are getting *really* clever), so they >> always have some overhead. Functors are therefore divide-by-zero-times >> more efficient (I don't know where Nick got the 50 times figure from :-). >> >> (If the functor is large enough to not be inlined then it is execution >> time that dominates and function call overhead is not important.) >> >> Using functors might cause more code, so less code fits in cache. I >> don't know how that affects overall performance. >> >> Darren >> >> _______________________________________________ >> computer-go mailing list >> computer-go@computer-go.org >> http://www.computer-go.org/mailman/listinfo/computer-go/ >> > _______________________________________________ > computer-go mailing list > computer-go@computer-go.org > http://www.computer-go.org/mailman/listinfo/computer-go/ _______________________________________________ computer-go mailing list computer-go@computer-go.org http://www.computer-go.org/mailman/listinfo/computer-go/
_______________________________________________ computer-go mailing list computer-go@computer-go.org http://www.computer-go.org/mailman/listinfo/computer-go/