A comprehensive multi-language benchmark suite for chess game analysis, comparing Python, Node.js, Rust, and Go implementations.
Fetches games from Chess.com public API and analyzes them using Stockfish engine to calculate move accuracy based on WDL (Win-Draw-Loss) probabilities.
Features:
- Fetches games from Chess.com API for any username
- Parses PGN (Portable Game Notation) files
- Analyzes each position with Stockfish at configurable depth
- Calculates accuracy scores using WDL probabilities
- Supports parallel processing with configurable workers/threads
- Benchmarks both Stockfish analysis and pure PGN parsing
Test Configuration:
- Player: hikaru (1000 games)
- Stockfish: depth 4, WDL enabled
- Parallelization: 4 workers Γ 1 thread each
- Hardware: Apple Silicon (M-series)
| Rank | Language | Library | Games/sec | Moves/sec | Time |
|---|---|---|---|---|---|
| π₯ | Rust | shakmaty | 18.73 | 1,643 | 51.5s |
| π₯ | Python | python-chess | 18.67 | 1,624 | 53.6s |
| π₯ | Node.js | chess.js | 17.73 | 1,503 | 56.4s |
| 4 | Go | notnil/chess | 14.65 | 1,279 | 66.8s |
| Rank | Language | Library | Games/sec | Moves/sec | Time | vs Rust |
|---|---|---|---|---|---|---|
| π₯ | Rust | shakmaty | 35,121 | 3,001,431 | 0.03s | 1x |
| π₯ | Python | python-chess | 251 | 21,817 | 3.98s | 140x slower |
| π₯ | Node.js | chess.js | 214 | 18,271 | 4.64s | 164x slower |
| 4 | Go | notnil/chess | 40 | 3,483 | 24.5s | 878x slower |
| Strategy | Games/sec | Result |
|---|---|---|
| 4 workers Γ 1 SF thread | 20.03 | β Best for depth 4 |
| 2 workers Γ 2 SF threads | 11.73 | 41% slower |
| 1 worker Γ 4 SF threads | 5.98 | 70% slower |
At shallow depths, game-level parallelism beats Stockfish multi-threading.
After optimizing I/O buffering (256 bytes vs 8KB default) and eliminating unnecessary allocations, Rust achieves:
- Fastest Stockfish analysis (18.73 games/sec)
- 878x faster PGN parsing than Go
Despite being interpreted, Python nearly matches Rust for Stockfish analysis due to:
- Mature
subprocessmodule with optimized IPC - Excellent
python-chesslibrary - GIL irrelevant (each worker has its own Stockfish process)
The notnil/chess library is critically slow:
- 4x slower than Python for PGN parsing
- 878x slower than Rust
- This is a library problem, not a Go problem
Time breakdown per game:
βββ Stockfish analysis: ~95%
βββ PGN parsing: ~3%
βββ IPC overhead: ~1.5%
βββ FEN generation: ~0.5%
When Stockfish dominates, language speed matters lessβbut library quality still matters!
- Stockfish - Install and note the path (default:
/opt/homebrew/bin/stockfish) - Python 3.8+ with pip
- Node.js 18+ with npm
- Rust 1.70+ with cargo
- Go 1.21+
git clone https://github.com/Bot-Rakshit/chess-bench.git
cd chess-bench
# Python
cd python && pip install -r requirements.txt && cd ..
# Node.js
cd node && npm install && cd ..
# Rust
cd rust && cargo build --release && cd ..
# Go
cd go && go build -o benchmark benchmark.go && go build -o pgn_benchmark pgn_benchmark.go && cd ..Analyze games with full Stockfish evaluation:
# Python
python python/benchmark.py <username> <games> --workers 4 --threads 1 --depth 4
# Node.js
node node/benchmark.js <username> <games> --workers 4 --threads 1 --depth 4
# Rust
./rust/target/release/benchmark <username> <games> --workers 4 --threads 1 --depth 4
# Go
./go/benchmark <username> <games> -workers 4 -threads 1 -depth 4Example:
python python/benchmark.py hikaru 100 --workers 4 --threads 1 --depth 4Test library parsing speed without Stockfish:
# Rust (fastest)
./rust/target/release/pgn_benchmark hikaru 1000
# Python
python python/pgn_benchmark.py hikaru 1000
# Node.js
node node/pgn_benchmark.js hikaru 1000
# Go
./go/pgn_benchmark hikaru 1000chess-bench/
βββ README.md
βββ .gitignore
βββ python/
β βββ benchmark.py # Stockfish analysis
β βββ pgn_benchmark.py # Pure PGN parsing
β βββ requirements.txt
βββ node/
β βββ benchmark.js # Stockfish analysis
β βββ pgn_benchmark.js # Pure PGN parsing
β βββ package.json
βββ rust/
β βββ Cargo.toml
β βββ src/
β βββ main.rs # Stockfish analysis
β βββ bin/
β βββ pgn_benchmark.rs
βββ go/
βββ go.mod
βββ benchmark.go # Stockfish analysis
βββ pgn_benchmark.go # Pure PGN parsing
The benchmark fetches games using Chess.com's public API:
- Archives endpoint:
https://api.chess.com/pub/player/{username}/games/archives - Games endpoint:
https://api.chess.com/pub/player/{username}/games/{YYYY}/{MM}
- Get WDL (Win/Draw/Loss) probabilities from Stockfish for each position
- Convert to win probability:
P = (W + DΓ0.5) / 1000 - Calculate accuracy per move:
- If position improved:
accuracy = 100% - If position worsened:
accuracy = max(0, 100 Γ (1 - loss Γ 2))
- If position improved:
- Average all move accuracies for the target player
| Language | Library | Version | Notes |
|---|---|---|---|
| Python | python-chess | 1.10+ | Mature, excellent Stockfish integration |
| Node.js | chess.js | 1.0.0-beta | Easy to use, TypeScript support |
| Rust | shakmaty | 0.28 | Zero-copy, SIMD optimized, blazingly fast |
| Go | notnil/chess | 1.9.0 | Simple API, but very slow PGN parsing |
Default path is /opt/homebrew/bin/stockfish. To change:
- Python: Edit
STOCKFISH_PATHinbenchmark.py - Node.js: Edit
STOCKFISH_PATHinbenchmark.js - Rust: Edit
STOCKFISH_PATHinsrc/main.rs - Go: Edit
StockfishPathinbenchmark.go
| Parameter | Description | Default |
|---|---|---|
username |
Chess.com username | hikaru |
games |
Number of games to analyze | 1000 |
--workers |
Parallel workers | 4 |
--threads |
Stockfish threads per worker | 1 |
--depth |
Stockfish search depth | 4 |
PRs welcome! Especially interested in:
- Alternative Go chess libraries (to replace slow
notnil/chess) - Performance optimizations
- Additional language implementations (C++, Zig, Java, etc.)
- Higher depth analysis comparisons
MIT