Computer Chess Club Archives




Subject: Re: C and C++ --- NPS

Author: Matt Taylor

Date: 19:13:35 12/24/02

Go up one level in this thread

On December 24, 2002 at 20:33:34, Gerd Isenberg wrote:

>On December 23, 2002 at 21:33:50, Matt Taylor wrote:
>>On December 23, 2002 at 21:29:08, Arshad F. Syed wrote:
>>>Is there anyone here who has actually converted their C code to C++ while
>>>keeping the NPS the same or even managed to improve upon it? Sune did mention
>>>that he did so only at the cost of 15% degradation in speed. Why do people even
>>>bother wasting their time with C++ for a chess program when it inevitably leads
>>>to taking a hit in NPS? Regardless, of all the advice to simply inline the
>>>functions, I have yet to see a living example of chess program code which
>>>performed faster in C++.
>>The biggest hit you take in C++ is virtual functions, and inevitably people use
>>them. The virtual functions are very damaging due to the fact that they're
>>implemented with a function pointer, and at the machine level it translates into
>>an indirect call. The indirect calls branch mispredict because the CPU can't
>>figure out ahead-of-time where you're calling to, and branch mispredicts are
>Hi Matt,
>really? The vtable index of a virtual function is a compile time constant.
>Is an indirect call via register a mispredicted branch per se, even if the
>register was loaded with this->vptr->someVfunctionPointer an appropriate time
>before the indirect call occurs? What branch could be executed, other than the
>determined indirect call?

I spent a while perusing the Athlon optimization manual, and I don't see
anything about that. Even in the Xeon optimization manual, it says little about
this. I do recall reading it somewhere, but I have no idea where now.

The one thing that the Xeon manual mentions is that, in static prediction,
indirect branches are predicted as not taken. From my understanding of how
dynamic branch prediction works, you would take the penalty once for each time
you made the call. E.g. the following will eat 2 penalties:

; Note esi is preserved across the call. I'm going to assume that ecx is, too.
mov    esi, [ecx->SomeFunction]
call   esi
call   esi

The dynamic prediction mechanism stores the -address- that you branch to, so if
this were the body of a loop, you would eat the penalty twice, and every other
prediction (assuming it didn't get wiped from the BTB) would pick correctly
assuming you were calling to the same place. If you were to, say, cycle through
an unsorted list of pieces and call a function for move generation, you would be
eating major penalties because it would mispredict almost every time.

The major problem with indirect branches is easily seen in the code sample
there. Static prediction -can't- guess where it's going to go because it needs
to know about the contents of esi at the front of the pipeline. It won't know
where to continue executing until the u-op that assigns to esi retires.

The alternative of switch/case will at -least- prefetch the correct code if it's
small, and it has a chance of getting the prediction right.

>>Unfortunately, not using virtual functions (mostly) defeats the benefits you
>>would get from OO here.
>>If you convert to C++ without using virtual functions, you probably won't take
>>much of a hit at all. Personally, I've never seen a -need- to convert to C++. I
>>can implement my OO in C, and it simplifies linking because C doesn't have name
>But polymorphism is nice to have, even without virtual functions.
>I don't believe that name mangling affects the linker a lot ;-)

It's not a problem until you want to mix in some assembly or link to someone's C
code or use code written in some other language. Then the
"?#@#$%@$@#2#@@#$FunctionXYZ" names become very obnoxious.


This page took 0.22 seconds to execute

Last modified: Thu, 07 Jul 11 08:48:38 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.