Files
hakmem/docs/archive/BENCHMARKING_CHECKLIST.md
Moe Charm (CI) 52386401b3 Debug Counters Implementation - Clean History
Major Features:
- Debug counter infrastructure for Refill Stage tracking
- Free Pipeline counters (ss_local, ss_remote, tls_sll)
- Diagnostic counters for early return analysis
- Unified larson.sh benchmark runner with profiles
- Phase 6-3 regression analysis documentation

Bug Fixes:
- Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB)
- Fix profile variable naming consistency
- Add .gitignore patterns for large files

Performance:
- Phase 6-3: 4.79 M ops/s (has OOM risk)
- With SuperSlab: 3.13 M ops/s (+19% improvement)

This is a clean repository without large log files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 12:31:14 +09:00

7.0 KiB
Raw Blame History

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 だったと判明

根本原因

# 以前(ターゲットなし)
make bench_tiny

# Makefileの暗黙ルール
gcc bench_tiny.c -o bench_tiny  # hakmem とリンクせず!

bench_tiny.c は単に malloc/free を呼ぶだけなので、system allocator が使われた。


二度と起こらないための対策

1. 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: ビルド確認

# 必ず make clean してから
make clean && make bench_tiny

# ビルドメッセージを確認
# 期待: "✓ bench_tiny built with hakmem"

Step 2: リンク確認

# 方法 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 のみ)

正しい例:

$ 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 を使っている):

$ 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

# hakmem 初期化メッセージを確認HAKMEM_DEBUG_VERBOSE=1 の場合)
# または stats 出力で hakmem が動いているか確認
./bench_tiny 2>&1 | head -20

3. ベンチマークスクリプトの標準化

推奨: make bench_tiny を使うMakefile で正しく設定済み)

非推奨: 手動で gcc を叩く(リンク漏れのリスク)


4. ドキュメント化されたワークフロー

標準ベンチマーク手順

# 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(作成推奨)

#!/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"

使用例:

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

  • Makefile に明示的ターゲット追加
  • BENCHMARKING_CHECKLIST.md 作成
  • verify_bench.sh スクリプト作成(オプション)
  • BENCHMARK_PROTOCOL.md 作成(詳細手順)
  • Phase 0 (Baseline) の性能を測定し直す
  • Phase 1-4 の性能を正しく測定し直す

🚫 絶対にやってはいけないこと

  1. make bench_tiny なしで手動コンパイル
  2. リンク確認なしでベンチマーク実行
  3. 1回だけの測定で結論
  4. 性能変化の原因を確認せずにコミット
  5. ベースラインなしで「改善」を主張

今後は絶対に間違えない

このチェックリストに従えば、二度と同じ間違いは起きませんにゃ!🐱