I think this will be the last Mindchess update for a while, so I wanted to collect the current results in one place.
Mindchess was never intended to become a chess engine. I don't have a particularly strong interest in chess itself; I started this because perft looked like a good optimization target. The original goal was simply to see how far I could push raw move generation, with Chessbit as the obvious program to compare against.
I reached that goal, but then stayed around long enough to optimize the other two variants as well: depth-2 aggregate counting and transposition-table perft.
Raw single-threaded perft
This is still what I consider the primary result. There is no transposition table or subtree reuse here; every legal leaf is actually enumerated.
The results are medians of five runs on my Ryzen 9 9950X3D:
Code: Select all
Position Depth Mindchess MNPS Chessbit MNPS Lead
--------------------------------------------------------------
Start 7 3680.26 2560.29 +43.744%
Kiwipete 6 4662.31 3455.52 +34.924%
Position 3 8 3015.91 2068.48 +45.803%
Position 4 6 3821.15 2956.15 +29.261%
Position 5 6 3882.35 2912.85 +33.284%
Position 6 6 5241.79 4173.73 +25.590%
Geometric mean +35.241%
Raw multithreaded perft
The multithreaded version runs the same raw enumeration across workers, without a TT.
Start position, depth 9, 16 workers:
Code: Select all
Nodes: 2,439,530,234,167
Time: 43.758 s
Rate: 55,749.87 raw MNPS
Workers: 16
Split depth: 3
TT: none
Depth-2 aggregate counting
After finishing the raw version I also experimented with avoiding work at depth 2 by proving groups of replies without constructing every child position.
For this comparison both Mindchess and Chessbit were built with ICX 2026.0.0, without PGO, and Chessbit's transposition table was disabled. The values are medians of five alternating runs:
Code: Select all
Position Depth Mindchess MNPS Chessbit MNPS Lead
--------------------------------------------------------------
Start 7 8641.51 7912.69 +9.211%
Kiwipete 6 7016.32 6896.50 +1.737%
Position 3 8 3276.70 3115.89 +5.161%
Position 4 6 4793.57 4474.56 +7.129%
Position 5 6 6441.44 5959.36 +8.089%
Position 6 6 9119.73 8835.76 +3.214%
Geometric mean +5.724%
Hashed / transposition-table perft
The final experiment was a multithreaded transposition-table version. This is a different benchmark again: transposed subtrees are reused, so the reported rate is logical nodes divided by elapsed time rather than physically enumerated leaves.
Start position depth 10, 69,352,859,712,417 logical nodes, 32 workers and an 8 GiB TT:
Code: Select all
Engine Build Time Logical MNPS
----------------------------------------------------------
Chessbit / ICX non-PGO 12.020 s 5,769,788.66
Mindchess / Clang non-PGO 10.204 s 6,796,816.11
Mindchess / Clang PGO 9.579 s 7,240,438.70
Thomas deserves credit here. Chessbit provided the target that made this interesting in the first place, and he pointed me toward the depth-2 approach. Studying Chessbit also gave me useful ideas around recursive batching and cache-line bucket organization.
At this point I think I have done what I came for. I started out wanting to beat the raw implementation, achieved that, and then ended up staying around long enough to beat the aggregate and hashed versions as well.
There are certainly more things that could be optimized, but for now I feel done with the experiment.
I've cleaned up the repository so it now contains the three implementations separately, along with the build scripts, reproduction commands and transposition-table documentation:
https://github.com/vtlmks/mindchess
The two earlier threads contain the development history:
Raw perft:
https://talkchess.com/viewtopic.php?t=86611
Hashed perft:
https://talkchess.com/viewtopic.php?t=86623