# Benchmarking Checklist - 二度と間違えないために ## ❌ **何が起きたか(2025-10-26 事件)** ### 問題 Phase 1-4.1 の全てのベンチマークで **glibc malloc** を測定していた。 hakmem の性能を測定していると思い込んでいたが、実際は system allocator だった。 ### 発覚の経緯 1. Phase 3: 391 M ops/sec と報告 2. Phase 4: 373 M ops/sec に退行 3. Phase 4.1: 381 M ops/sec に改善 4. Phase 4.2 で Makefile を修正して hakmem を正しくリンク 5. **103 M ops/sec** という衝撃の結果 6. → 全ての測定が glibc malloc だったと判明 ### 根本原因 ```makefile # 以前(ターゲットなし) make bench_tiny ↓ # Makefileの暗黙ルール gcc bench_tiny.c -o bench_tiny # hakmem とリンクせず! ``` bench_tiny.c は単に `malloc/free` を呼ぶだけなので、system allocator が使われた。 --- ## ✅ **二度と起こらないための対策** ### 1. Makefile の明示的なターゲット(完了) ```makefile # Phase 4: Tiny Pool benchmarks (properly linked with hakmem) TINY_BENCH_OBJS = hakmem.o hakmem_config.o ... (全ての hakmem オブジェクト) bench_tiny: bench_tiny.o $(TINY_BENCH_OBJS) $(CC) -o $@ $^ $(LDFLAGS) @echo "✓ bench_tiny built with hakmem" # 明確なメッセージ bench_tiny_mt: bench_tiny_mt.o $(TINY_BENCH_OBJS) $(CC) -o $@ $^ $(LDFLAGS) @echo "✓ bench_tiny_mt built with hakmem" test_mf2: test_mf2.o $(TINY_BENCH_OBJS) $(CC) -o $@ $^ $(LDFLAGS) @echo "✓ test_mf2 built with hakmem" ``` ### 2. ベンチマーク実行前のチェックリスト #### **Step 1: ビルド確認** ```bash # 必ず make clean してから make clean && make bench_tiny # ビルドメッセージを確認 # 期待: "✓ bench_tiny built with hakmem" ``` #### **Step 2: リンク確認** ```bash # 方法 A: シンボル確認(推奨) nm ./bench_tiny | grep hak_tiny_alloc # 期待: hak_tiny_alloc のシンボルが見つかる # NG: "no symbols" または何も出ない # 方法 B: ldd 確認(共有ライブラリの場合) ldd ./bench_tiny # hakmem が静的リンクされているので libhakmem.so は出ないが、 # libc.so, libpthread.so, libm.so が出ることを確認 # 方法 C: size 確認 size ./bench_tiny # 期待: text サイズが大きい(hakmem コードが含まれる) # NG: text サイズが数KB程度(bench_tiny.c のみ) ``` **正しい例**: ```bash $ nm ./bench_tiny | grep hak_tiny_alloc 000000000000b2a0 T hak_tiny_alloc 000000000000cd10 T hak_tiny_alloc_superslab $ size ./bench_tiny text data bss dec hex filename 89234 3456 12800 105490 19c12 bench_tiny ``` **間違いの例(glibc malloc を使っている)**: ```bash $ nm ./bench_tiny | grep hak_tiny_alloc # 何も出ない! $ size ./bench_tiny text data bss dec hex filename 2345 128 64 2537 9e9 bench_tiny ``` #### **Step 3: 実行前の sanity check** ```bash # hakmem 初期化メッセージを確認(HAKMEM_DEBUG_VERBOSE=1 の場合) # または stats 出力で hakmem が動いているか確認 ./bench_tiny 2>&1 | head -20 ``` --- ### 3. ベンチマークスクリプトの標準化 **推奨**: `make bench_tiny` を使う(Makefile で正しく設定済み) **非推奨**: 手動で gcc を叩く(リンク漏れのリスク) --- ### 4. ドキュメント化されたワークフロー #### **標準ベンチマーク手順** ```bash # 1. Clean build make clean # 2. Build with verification make bench_tiny 2>&1 | tee build.log grep "✓ bench_tiny built with hakmem" build.log || echo "ERROR: hakmem not linked!" # 3. Verify linkage nm ./bench_tiny | grep hak_tiny_alloc || echo "ERROR: hakmem symbols not found!" # 4. Run benchmark (3 times for stability) for i in {1..3}; do echo "=== Run $i/3 ===" ./bench_tiny 2>&1 | tail -6 echo "" done # 5. Compare with baseline # (save results and compare) ``` --- ### 5. 自動化された検証 #### **verify_bench.sh**(作成推奨) ```bash #!/bin/bash # verify_bench.sh - Verify benchmark binary is correctly linked BINARY="$1" if [ ! -f "$BINARY" ]; then echo "❌ Binary not found: $BINARY" exit 1 fi # Check for hakmem symbols if nm "$BINARY" | grep -q "hak_tiny_alloc"; then echo "✅ hakmem symbols found" else echo "❌ hakmem symbols NOT found - using system allocator!" exit 1 fi # Check binary size (heuristic) TEXT_SIZE=$(size "$BINARY" | awk 'NR==2 {print $1}') if [ "$TEXT_SIZE" -gt 50000 ]; then echo "✅ Binary size OK ($TEXT_SIZE bytes)" else echo "⚠️ Binary size suspiciously small ($TEXT_SIZE bytes)" exit 1 fi echo "✅ Verification passed: $BINARY" ``` **使用例**: ```bash chmod +x verify_bench.sh ./verify_bench.sh ./bench_tiny ``` --- ## 📊 **真の性能データ(Phase 4.2 で初めて正しく測定)** ### System malloc (glibc) - **Throughput**: ~370 M ops/sec - **Latency**: 2.7 ns/op ### hakmem (Phase 4.2) - **Throughput**: **103 M ops/sec** - **Latency**: **9.6 ns/op** - **Gap**: glibc が **3.6倍速い** ### mimalloc (推定) - **Latency**: 14 ns/op (ANALYSIS_SUMMARY.md) - **Throughput**: ~71 M ops/sec - **Note**: hakmem の方が速い可能性がある --- ## 🔄 **今後のベンチマーク protocol** ### Before every benchmark: 1. ✅ `make clean` 2. ✅ `make bench_tiny` (ビルドメッセージ確認) 3. ✅ `nm ./bench_tiny | grep hak_tiny_alloc` (シンボル確認) 4. ✅ Run benchmark 3 times 5. ✅ Compare with baseline ### After benchmark: 1. ✅ Record exact commit hash 2. ✅ Record build command 3. ✅ Record verification result 4. ✅ Save raw data ### Before claiming performance change: 1. ✅ Verify > 5% difference 2. ✅ Run 5+ times for statistical significance 3. ✅ Check for system noise (other processes) 4. ✅ Document what changed --- ## 📝 **Lessons Learned** 1. **Make の暗黙ルールは危険** - 明示的なターゲットを常に定義 2. **"動く" ≠ "正しい"** - malloc/free は常に動く(system allocator がある) 3. **測定前の検証が必須** - nm/ldd/size でリンク確認 4. **性能変化には根拠が必要** - コード変更と性能の因果関係を確認 5. **ドキュメント化** - チェックリストがないと同じ間違いを繰り返す --- ## 🎯 **Action Items** - [x] Makefile に明示的ターゲット追加 - [x] BENCHMARKING_CHECKLIST.md 作成 - [ ] verify_bench.sh スクリプト作成(オプション) - [ ] BENCHMARK_PROTOCOL.md 作成(詳細手順) - [ ] Phase 0 (Baseline) の性能を測定し直す - [ ] Phase 1-4 の性能を正しく測定し直す --- ## 🚫 **絶対にやってはいけないこと** 1. ❌ `make bench_tiny` なしで手動コンパイル 2. ❌ リンク確認なしでベンチマーク実行 3. ❌ 1回だけの測定で結論 4. ❌ 性能変化の原因を確認せずにコミット 5. ❌ ベースラインなしで「改善」を主張 --- ## ✅ **今後は絶対に間違えない** このチェックリストに従えば、二度と同じ間違いは起きませんにゃ!🐱✨