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/

Reply via email to