Files
hakmem/docs/analysis/MID_LARGE_CPU_HOTPATH_ANALYSIS.md
Moe Charm (CI) 406a2f4d26 Incremental improvements: mid_desc cache, pool hotpath optimization, and doc updates
**Changes:**
- core/box/pool_api.inc.h: Code organization and micro-optimizations
- CURRENT_TASK.md: Updated Phase MD1 (mid_desc TLS cache: +3.2% for C6-heavy)
- docs/analysis files: Various analysis and documentation updates
- AGENTS.md: Agent role clarifications
- TINY_FRONT_V3_FLATTENING_GUIDE.md: Flattening strategy documentation

**Verification:**
- random_mixed_hakmem: 44.8M ops/s (1M iterations, 400 working set)
- No segfaults or assertions across all benchmark variants
- Stable performance across multiple runs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-10 14:00:57 +09:00

11 KiB
Raw Blame History

MID/Large CPU Hotpath (Phase54)

  • 条件: ./bench_mid_large_mt_hakmem 1 1000000 400 1 (Release)
    HAKMEM_TINY_HEAP_PROFILE=C7_SAFE, HAKMEM_TINY_C7_HOT=1, HAKMEM_TINY_HOTHEAP_V2=0, HAKMEM_TINY_LARSON_FIX=1
  • スループット: HAKMEM ≈28.1M ops/smimalloc 54.2M / system 15.3M は Phase53 より)
  • perf stat (cycles:u): IPC≈2.4、page-faults≈7.4kPhase53 と同等)

cycles:u ホットシンボルself%

  • hak_pool_try_alloc.part.0 … 14.7% pool alloc ホットパス)
  • worker_run … 9.2% (ドライバ側のループと malloc 呼び出しを含む)
  • free / hak_free_at.constprop.0 … ~910%glibc free 連携+自前 free
  • __memset_avx2_unaligned_erms … ~9%pool 初期化/clear と推定)
  • mid_desc_lookup … 3.8%
  • hak_super_lookup … 1.4%
  • hak_pool_free.part.0 … 0.7%

所感

  • pool 系hak_pool_try_alloc / hak_pool_freeと free/memset が支配的で、mid_desc_lookup と super_lookup も目立つ。
  • kernel 枠の大きな inclusive% は free/memset 配下にぶら下がっており、userland 側の pool/front の命令数削減が効果的そう。

Phase55 方針pool allocator ホットパス軽量化)

  • スコープ: core/hakmem_pool.c / core/hakmem_smallmid.c / core/box/pool_* の pool fast path。
  • hak_pool_try_alloc を直線化:
    • 「TLS/local freelist hitなら即 return」を先頭に寄せ、debug/統計/slow は unlikely 側へ。
    • mid_desc_lookup/クラス情報は入口で 1 回だけ計算し、TLS へのキャッシュを検討。
  • hak_pool_free / hak_free_at:
    • self-thread free は pool push を最優先にし、cross-thread/debug は unlikely に寄せる。
    • free 時の memset/初期化が不要なケースを洗い出し、スキップ余地をメモ。
  • mid_desc_lookup のキャッシュ:
    • size→class→desc を入口で 1 回だけ決める仕組み(既存キャッシュの再利用も含め)を検討。
  • 成功ラインbench_mid_large_mt_hakmem 1 1000000 400 1, Release):
    • ops/s を 2829M → 3032M+5〜10%)へ。
    • perf report で hak_pool_try_alloc + free 周辺 self% が数ポイント低下。

Phase56 結果pool fast path 初期実装)

  • 変更: PoolBlock→user 変換をヘルパに寄せ、TLS ring/lo pop と self-thread free push を直線化。owner 判定は mid_desc の 1 回 lookup で共有。
  • ベンチC6-heavy, ws=256, iters=20k, C7_SAFE, v2 OFF: 25.9M ops/s(目標 3032M に届かず、前回 2829M から回帰)。
  • perf stat同条件 1M/400: cycles=225,766,496、instructions=528,335,613、task-clock=57.88ms、ops/s≈25.7M。
  • 所感: fast-path整理だけでは効果薄く、むしろ低下。pool 内の memset/desc まわりやリング補充順序をより大胆に削らないと改善しない。次のステップとして追加の枝削減・キャッシュ導入を検討。

Phase MD1mid_desc_lookup TLS キャッシュ)

  • 目的: C6-heavy/mid で目立つ mid_desc_lookup を TLS 1 エントリでキャッシュし、サイズが同じリクエストが続くケースで self% を削る。
  • ENV ゲート: HAKMEM_MID_DESC_CACHE_ENABLED=1(デフォルト OFF。miss 時は従来の mid_desc_lookup にフォールバック。
  • baseline self%: mid_desc_lookup≈3.8%Phase54 perf, C7_SAFE
  • A/BC6_HEAVY_LEGACY_POOLV1, 1M/400, flatten OFF, zero=full:
    • cache OFF: 28.90M ops/s
    • cache ON : 29.83M ops/s+3.2%segv/assert なし。
  • Mixed 161024B (C7_SAFE front v3/LUT/fast classify ON): cache OFF 44.83M → ON 44.94M+0.3%。perf (cycles:u, release) では mid_desc_lookup は上位に出ず、self% 影響はごく小さい。

Phase57 回帰トリアージpool v2 をゲート化)

  • 変更: HAKMEM_POOL_V2_ENABLED を追加し、v1/v2 の pool 実装を env で切替。細分スイッチとして HAKMEM_POOL_V2_BLOCK_TO_USER / HAKMEM_POOL_V2_TLS_FAST_PATH を用意(デフォルト ON, v2 時のみ有効)。
  • ベンチC6-heavy, 1M/400, Release:
    • v1 (POOL_V2_ENABLED=0): 27.40M ops/s
    • v2 (POOL_V2_ENABLED=1): 24.73M ops/s
  • 所感: v2 の変更が回帰要因と判明。標準は v1 に戻し、スイッチ単位の A/B でどの改変が悪いかを切り分ける方針。

Phase80: Pool v1 flatten 初回 A/BC6-heavy

  • スコープ: pool v1 の自スレッドホットパスTLS ring/lo hitを別 Box として直線化し、mid/smallmidC6-heavyでの ops/s 向上を狙う。pool v2 は引き続き研究箱のまま触らない。
  • 実装: core/hakmem_pool.chak_pool_try_alloc_v1_flat / hak_pool_free_v1_flat を追加し、TLS ring/lo hit 時は最小限の分岐だけで pop/push する経路を用意。miss 時や cross-thread/slow は従来の _v1_impl にフォールバックする構造にし、ENV HAKMEM_POOL_V1_FLATTEN_ENABLEDデフォルト0HAKMEM_POOL_V1_FLATTEN_STATS で切替・統計を制御。
  • ベンチ条件: ./bench_mid_large_mt_hakmem 1 1000000 400 1ReleaseHAKMEM_BENCH_MIN_SIZE=257, MAX_SIZE=768, HAKMEM_TINY_HEAP_PROFILE=C7_SAFE, HAKMEM_TINY_C7_HOT=1, HAKMEM_TINY_HOTHEAP_V2=0, HAKMEM_SMALL_HEAP_V3_ENABLED=1, HAKMEM_SMALL_HEAP_V3_CLASSES=0x80, HAKMEM_POOL_V2_ENABLED=0, HAKMEM_POOL_V1_FLATTEN_STATS=1
  • A/B 結果:
    • flatten OFF (POOL_V1_FLATTEN_ENABLED=0): Throughput ≈ 23.12M ops/s[POOL_V1_FLAT] alloc_tls_hit=0 alloc_fb=0 free_tls_hit=0 free_fb=0
    • flatten ON (POOL_V1_FLATTEN_ENABLED=1): Throughput ≈ 25.50M ops/s(約 +10%)、alloc_tls_hit=499,870 alloc_fb=230 free_tls_hit=460,450 free_fb=39,649
  • 所感:
    • Pool v1 の TLS fast path を分離・直線化するだけで、狙っていた +5〜10% の上限付近まで改善が出た。まだ free_fb がそこそこ残っており、page_of / 自スレ判定の精度を上げて free_fb を減らす余地がある。
    • デフォルト運用は安全側を維持するため HAKMEM_POOL_V1_FLATTEN_ENABLED=0 のままとし、C6-heavy/mid ベンチや実験時にのみ flatten 経路を ON にする Box として扱う。

Phase81: Pool v1 flatten Phase2free_fb 理由分解)

  • 変更: flatten stats に free fallback の内訳を追加page_null / not_mine / other。free で mid_desc が取れない場合は page_null、owner 不一致や TLS 無効による fallback は not_mine、それ以外は other としてカウント。
  • ベンチ条件: ./bench_mid_large_mt_hakmem 1 1000000 400 1ReleaseHAKMEM_TINY_HEAP_PROFILE=LEGACY, HAKMEM_TINY_HOTHEAP_V2=0, HAKMEM_POOL_V2_ENABLED=0, HAKMEM_POOL_V1_FLATTEN_ENABLED=1, HAKMEM_POOL_V1_FLATTEN_STATS=1
  • A/B:
    • flatten OFF: 23.68M ops/s、stats すべて 0。
    • flatten ON : 25.90M ops/s(約 +9.4%)、alloc_tls_hit=499,870 alloc_fb=230 free_tls_hit=460,060 free_fb=40,039 page_null=40,039 not_mine=0 other=0
  • 所感: free fallback のほぼすべてが「mid_desc が取れず page=null」で発生している。owner mismatch はゼロ。今後は page_of/mid_desc 判定の精度を上げることで free_fb を減らす余地がある。

Phase82: mid_desc マスク整合による free_fb 削減

  • 変更: mid_desc_register/lookup/adopt が扱うページアドレスを POOL_PAGE_SIZE で正規化し、64KiB に未アラインな mmap でも mid_desc_lookup が一致するように修正。これにより false negative の page_null を減らす。
  • ベンチ同条件、flatten ON, Release, tiny/pool v2 OFF, LEGACY tiny:
    • flatten OFF: 23.68M ops/s(参考値・前フェーズと同じ)。
    • flatten ON : 26.70M ops/s(約 +13% vs OFFalloc_tls_hit=499,871 alloc_fb=229 free_tls_hit=489,147 free_fb=10,952 page_null=3,476 not_mine=7,476 other=0
  • 所感: page_null が大幅減≈40k→≈3.4k。not_mine が顕在化したため、次は owner 判定/自スレ判定の精度を軽く見直す余地がある。デフォルトは引き続き flatten OFF安全側で、bench/実験時のみ ON。

Phase 82 Final: mid_desc initialization race fix と包括的 A/B ベンチ

根本原因の修正

  • Phase 82 の full flatten が C7_SAFE モードでクラッシュしていた原因: mid_desc_adopt() が未初期化ミューテックスにアクセスする race condition
    • C7_SAFE では TinyHeap ルーティングが C7-only であり、Pool が通常より早期に呼ばれる
    • mid_desc_init_once()mid_desc_adopt() より前に保証されていなかった
  • 修正: hak_pool_init_impl() 冒頭で mid_desc_init_once() を強制実行 → 初期化順序を確定化
    • この修正は本線(常に有効、すべてのプロファイルで)

包括的ベンチマーク結果 (C6_HEAVY_LEGACY_POOLV1, Release)

フェーズ 10K ops/s 100K ops/s 1M ops/s 特記事項
Phase 1 (ベースライン) 3.03M 14.86M 26.67M 最適化なし、基準値
Phase 2 (Zero Mode Header) +5.0% -2.7% -0.2% ML1: 小規模ワークロード向け
Phase 3 (Full Flatten) +3.7% +6.1% -5.0% 中規模100Kで最適化効果
Phase 4 (Combined) -5.1% +8.8% +2.0% 最高パフォーマンス: 100K で +8.8%
Phase 5 (C7_SAFE Safety) NO CRASH NO CRASH NO CRASH クラッシュ完全回避

構成別デフォルト値(本線ポリシー)

C7_SAFE プロファイル:

  • HAKMEM_POOL_V1_FLATTEN_ENABLED=0 (デフォルト OFF
  • HAKMEM_POOL_ZERO_MODE=full (デフォルト: フル zero、安全側
  • mid_desc_init_once() 強制実行(クラッシュ防止、常に有効)
  • ベンチ時の opt-in: HAKMEM_POOL_V1_FLATTEN_ENABLED=1 / HAKMEM_POOL_ZERO_MODE=header で切り替え可能

LEGACY / 研究用プロファイル:

  • HAKMEM_POOL_V1_FLATTEN_ENABLED=0 (デフォルト OFF
  • HAKMEM_POOL_ZERO_MODE=full (デフォルト: フル zero
  • ベンチ時のみ HAKMEM_POOL_V1_FLATTEN_ENABLED=1 で opt-in

ワークロード特性別の最適化効果

ワークロードサイズ 最適な構成 改善率 備考
小規模 (10K) Phase 2 (Zero Mode) +5.0% オーバーヘッド増で複合モードは -5.1%
中規模 (100K) Phase 4 (Combined) +8.8% 最高効果を示す領域
大規模 (1M) Phase 4 (Combined) +2.0% キャッシュ圧力で効果減少

所感

mid_desc 初期化順序の修正(mid_desc_init_once() の強制実行)は本線として常に有効。これにより:

  • C7_SAFE モードでの未初期化ミューテックスクラッシュを完全排除
  • Flatten と Zero Mode は箱として組み込まれ、ENV で opt-in/out が可能
  • デフォルト構成では両機能とも OFF安全側維持

性能目標(+1325%)には未到達だが、安全性の確保と中規模ワークロードでの +8.8% 改善 が主要な成果。1M 反復での -5%〜-0.2% 回帰は、より大規模データセットでのキャッシュ効率悪化に起因する可能性があり、今後の最適化テーマ。