Prophet @ CCT10


Last modified: 6/22/08

Prophet participated in CCT10 on January 26-27, 2008. Prophet was seeded 22nd out of 36 entrants. Its hardware for the tournament was a Core 2 Duo at 1.8 GHz, with 2gb ram, running 32 bit Gentoo Linux (even though the Core 2 is a 64 bit processor). Prophet was running with two search threads. As usual the tournament took place at the Internet Chess Club (ICC).

Unfortunately Prophet suffered from a compiler bug in this tournament, so I'm not going to analyze any of the games. Instead, I will summarize the bug and its effect on Prophet. It's actually a pretty cool little bug to find - I just wish I didn't discover it in a tournament!

First, some code:

#include <stdio.h>

enum SQUARES {
    A8,B8,C8,D8,E8,F8,G8,H8,
    A7,B7,C7,D7,E7,F7,G7,H7,
    A6,B6,C6,D6,E6,F6,G6,H6,
    A5,B5,C5,D5,E5,F5,G5,H5,
    A4,B4,C4,D4,E4,F4,G4,H4,
    A3,B3,C3,D3,E3,F3,G3,H3,
    A2,B2,C2,D2,E2,F2,G2,H2,
    A1,B1,C1,D1,E1,F1,G1,H1,
    NO_SQUARE };

typedef unsigned long long Bitmap;
Bitmap bm_mask[64];
Bitmap to_boundary[64];


void DrawBitmap(Bitmap bmap) {
    for (int c=0;c<64;c++) {
       if (bmap&bm_mask[c]) printf("1"); else printf("0");
       if ((c%8)==7) printf("\n");
    }
    printf("\n");
}

void Initialize() {

    Bitmap b=1;
    for (int c=0;c<64;c++)
       bm_mask[c]=(b<

    for (int c=0;c<64;c++) {
       to_boundary[c]=0;
       for (int t=1;t<8;t++) {
         // if (c==E4) printf("considering: %d\n",t);
          if (c-(t*8)<0) break;
          to_boundary[c]|=bm_mask[c-(t*8)];
       }
    }

    DrawBitmap(to_boundary[E4]);

}

int main(int argc,char *argv[]) {
    Initialize();
    return 0;
}

With the printf statement in, the output was:

considering: 1
considering: 2
considering: 3
considering: 4
considering: 5
00001000
00001000
00001000
00001000
00000000
00000000
00000000
00000000

.... and with it commented out, the output was:

00000000
00000000
00000000
00001000
00000000
00000000
00000000
00000000

Which makes absolutely no sense of course - a compiler bug! If you look closely, the break statement in the inner loop (which I've highlighted in red) is redundant. The code is still technically correct, but the break statement is indeed redundant, which triggered a bug in the compiler's optimizer. The bug was confirmed by a former Intel compiler engineer. That's right - it was the Intel C++ Compiler, version 10.2. Here is what the engineer, Aart Bik, wrote in a discussion of the topic on talkchess:

Even though I no longer work as compiler engineer at Intel, I still have some primitive means of debugging the Intel compiler.... This indeed seems a bug (in induction variable optimization to be precise). I have emailed my old buddies at Intel to confirm and fix this. And, yes, people claiming that one should not have to rewrite their code to avoid compiler bugs are absolutely right.
Hope this helps.

Aart Bik
http://www.aartbik.com/

and later...

As a quick follow-up on my own posting, the bug reported by James (thanks for that) now also has been confirmed by my former team mates for 10.x and a fix is in the making....

The effect of this was that some of Prophet's bitboards were not properly populated, which wreaked total havoc on the evaluation function. Prophet would show +1 or so for white right out of book, no matter which side it was playing. It was a total disaster. How it managed to win even 1.5 points is beyond me.

For my part ... if I had been paying better attention I would've caught the problem earlier and perhaps salvaged a point or so. And the biggest lesson I learned: test EVERYTHING, even the COMPILER before entering a tournament. I normally run with gcc, but compiled with the Intel stuff thinking it'd give a slight speed boost. (And on top of everything it really wasn't any faster than gcc4!)


Back to the main page