diff options
Diffstat (limited to 'src/testbitboard.c')
| -rw-r--r-- | src/testbitboard.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/src/testbitboard.c b/src/testbitboard.c index 7d2bfeb..c91f87c 100644 --- a/src/testbitboard.c +++ b/src/testbitboard.c @@ -42,6 +42,22 @@ Return value: COOR c; ULONG b; BITBOARD bb; + // volatile, separate from bb (which is reused below for unrelated + // correctness checks and gets passed by address -- making it + // volatile there breaks those calls): without a volatile sink, the + // SLOWCOOR_TO_BB/COOR_TO_BB benchmark loops just below compute a + // value and never use it again, so the optimizer proves they have + // no effect and deletes them entirely -- this used to silently + // report "0 cycles/op" for both, an obviously impossible number + // that was never actually measuring anything (same class of bug + // documented in eval.c's RunEvalRookAB comment: "the first time + // this was written it produced 0.000s / inf calls/sec"). Other + // loops below (CountBits/LastBit/FirstBit etc.) happened to + // survive because those are real out-of-line/opaque calls the + // optimizer can't prove are side-effect-free; the COOR_TO_BB + // macros expand to plain visible expressions with nothing + // stopping them from being optimized away. + volatile BITBOARD bbSink; BITBOARD bbSpeed[1000]; ULONG u, v, w, z; UINT64 u64; @@ -74,20 +90,27 @@ Return value: for (u = 0; u < 1000000; u++) { b = u % 64; - bb = SLOWCOOR_TO_BB(b); + bbSink = SLOWCOOR_TO_BB(b); } - printf(" SLOWCOOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT + printf(" SLOWCOOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/op\n", (SystemReadTimeStampCounter() - u64) / 1000000); u64 = SystemReadTimeStampCounter(); for (u = 0; u < 1000000; u++) { b = u % 64; - bb = COOR_TO_BB(b); + bbSink = COOR_TO_BB(b); } - printf(" COOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT + printf(" COOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/op\n", (SystemReadTimeStampCounter() - u64) / 1000000); + // bbSink's individual writes are never dead-code-eliminated + // (that's what volatile guarantees) regardless of whether anything + // reads it afterward, but nothing did until this line -- report it + // so the compiler doesn't flag it as unused, same pattern the + // evalcycles command uses for its own timing-loop sink. + printf(" (bbSink final value, just to use it: %#llx)\n", + (unsigned long long)bbSink); u64 = SystemReadTimeStampCounter(); for (v = 1; v < 1000; v++) |
