Files
hakmem/CURRENT_TASK.md

201 lines
22 KiB
Markdown
Raw Normal View History

## HAKMEM 状況メモ (2025-12-05 更新 / C7 Warm/TLS Bind 反映)
### 現在の状態Tiny / Superslab / Warm Pool
- Tiny Front / Superslab / Shared Pool は Box Theory 準拠で 3 層構造に整理済みHOT/WARM/COLD
- Tiny Gatekeeper Boxalloc/freeと Tiny Route Box により、USER→BASE 変換と Tiny vs Pool のルーティングを入口 1 箇所に集約。
- Superslab Tier BoxHOT/DRAINING/FREE Release Guard Box により、SuperSlab ライフサイクルと eager FREE の安全な境界を定義。
- Warm Pool 層:
- `tiny_warm_pool.h`: per-thread の HOT SuperSlab プール。
- `warm_pool_stats_box.h`: hits/misses/prefilled の統計箱。
- `warm_pool_prefill_box.h`: registry スキャン時に Warm Pool を事前充填する cold-path helper。
- Prefault Box`ss_prefault_box.h`は追加済みだが、4MB MAP_POPULATE 問題を避けるためデフォルト OFF`HAKMEM_SS_PREFAULT=0`)に設定。
### 直近の成果
- Gatekeeper inliningPhase A-1完了`malloc`/`free` ラッパの関数呼び出しを削減しつつ、Box 境界は維持。
- Unified Cache Refill の debug 検証を 1 箇所に集約し、リリースビルドの HOT パスを軽量化:
- `bench_random_mixed_hakmem 1000000 256 42` が約 4.3M → 5.0M ops/s~+17%)に改善。
- Tiny-only/Tiny Mixed / Non-Tiny の条件差分をドキュメント化・分離:
- `bench_random_mixed_hakmem``HAKMEM_BENCH_MIN_SIZE` / `HAKMEM_BENCH_MAX_SIZE` を追加し、
- 8128BTiny-only
- 1291024BTiny C5C7 専用)
を個別に測定可能にした。
- `docs/PERF_ANALYSIS_TINY_MIXED.md` ほかに、8128B/200K/ws=400旧 Tiny 専用)と現在の 161024B/1M/ws=256Tiny+Non-Tiny 混在)の違いを明記。
- Unified Cache Refill 安全化Step 1 完了):
- `core/front/tiny_unified_cache.c``unified_cache_refill()``max_batch <= 256` を保証し、`out[256]` と常に整合するよう修正。
- C5〜C7 の Unified Cache 容量・バッチサイズを増やす実験を行ってもスタック破壊が起きない状態にした。
- Tiny Page BoxC7 Tiny-Plus 層の導入Step 2 第1段階完了:
- `core/box/tiny_page_box.h` / `core/box/tiny_page_box.c` を追加し、`HAKMEM_TINY_PAGE_BOX_CLASSES` で有効クラスを制御できる Page Box を実装。
- `tiny_tls_bind_slab()` から `tiny_page_box_on_new_slab()` を呼び出し、TLS が bind した C7 slab を per-thread の page pool に登録。
- `unified_cache_refill()` の先頭に Page Box 経路を追加し、C7 では「TLS が掴んでいるページ内 freelist/carve」からバッチ供給を試みてから Warm Pool / Shared Pool に落ちるようにしたBox 境界は `Tiny Page Box → Warm Pool → Shared Pool` の順序を維持)。
- TinyClassPolicy/Stats/Learner Box を追加し、Hot path は `tiny_policy_get(class_idx)` で Page/Warm ポリシーを読むだけに統一。
- FROZEN デフォルトlegacy プロファイルPage Box は C5〜C7 のみ ON、Warm は C0〜C7 すべて ONC0〜C4 cap=4、C5〜C7 cap=8
- ENV `HAKMEM_TINY_POLICY_PROFILE=legacy|c5_7_only|tinyplus_all` で切替可能(未指定は legacy
- Stats は OBSERVE 用に積むだけ、Learner は空実装のまま。
- mimalloc/system との最新ベンチ (Release, prefault デフォルト, policy=legacy, mode=2) を README_PERF に追記。C7-only 48.8M vs mimalloc 95.3M / system 73.9M、1291024B 50.0M vs 128.4M / 97.7M、full 50.9M vs 123.6M / 83.5M、Tiny-only 8128B 93.2M vs 123.7M / 66.3M。
- TLS Bind Box の導入:
- `core/box/ss_tls_bind_box.h``ss_tls_bind_one()` を追加し、「Superslab + slab_idx → TLS」のバインド処理`superslab_init_slab` / `meta->class_idx` 設定 / `tiny_tls_bind_slab`)を 1 箇所に集約。
- `superslab_refill()`Shared Pool 経路)および Warm Pool 実験経路から、この Box を経由して TLS に接続するよう統一。
- C7 Warm/TLS Bind 経路の実装と検証:
- `core/front/tiny_unified_cache.c` に C7 専用の Warm/TLS Bind モード0/1/2を追加し、Debug では `HAKMEM_WARM_TLS_BIND_C7` で切替可能にした。
- mode 0: Legacy Warmレガシー/デバッグ用、C7 では carve 0 が多く非推奨)
- mode 1: Bind-onlyWarm から取得した Superslab を TLS Bind Box 経由でバインドする本番経路)
- mode 2: Bind+TLS carveTLS から直接 carve する実験経路)
- Release ビルドでは常に mode=1 固定。Debug では `HAKMEM_WARM_TLS_BIND_C7=0/1/2` で切替。
- Warm Pool / Unified Cache の詳細計測:
- `warm_pool_dbg_box.h` と Unified Cache の計測フックを拡張し、C7 向けに
- Warm pop 試行/ヒット/実 carve 回数
- TLS carve 試行/成功/失敗
- UC ミスを Warm/TLS/Shared 別に分類
を Debug ビルドで観測可能にした。
- `bench_random_mixed.c``HAKMEM_BENCH_C7_ONLY=1` を追加し、C7 サイズ専用の micro-bench を追加。
- TinyClassPolicy / Stats / Learner Box の導入(初期フェーズ):
- `core/box/tiny_class_policy_box.{h,c}` にクラス別ポリシー構造体 `TinyClassPolicy``tiny_policy_get(class_idx)` を追加。
- FROZEN デフォルト: Page Box = C5C7, Warm = 全クラスC0C4 cap=4 / C5C7 cap=8
- `HAKMEM_TINY_POLICY_PROFILE=legacy|c5_7_only|tinyplus_all` でプロファイル切替可能(未知値は legacy にフォールバック)。
- `core/box/tiny_class_stats_box.{h,c}` に OBSERVE 用の軽量カウンタUC miss / Warm hit / Shared Pool lock など)を追加。
- `core/box/tiny_policy_learner_box.{h,c}` に Learner の骨組みを追加(現状は FROZEN/OBSERVE モード向けの雛形)。
- `core/front/tiny_unified_cache.c` / Page Box / Warm Pool 経路を `tiny_policy_get(class_idx)` ベースでゲートし、Hot path からは Policy Box を読む形に統一。
- `bench_random_mixed` に RSS ダンプ(`getrusage(RUSAGE_SELF).ru_maxrss`)を追加し、各 allocator で ops/s と合わせて常駐メモリを記録できるようにした。
- 新規比較表 `PERF_COMPARISON_ALLOCATORS.md` を追加。C7-only / 1291024B / 161024B で HAKMEM(full/larson_guard) は ~50M ops/s / ~29MB RSS、system は ~9578M ops/s / ~1.6MB RSS、mimalloc は ~74126M ops/s / ~1.8MB RSS。
- SS stats (HAKMEM_SS_STATS_DUMP=1, full profile, 161024B ws=256/1M): live Superslab は C2=1, C7=1empty_events: C7=1、RSS は ~29MB。予算を 2 に絞っても同じ配置で RSS 変化なし → RSS は Superslab 枚数より TLS/Warm/Page stack 等の常駐分が支配的。
### 性能の現状Random Mixed, HEAD
- 条件: Release, `HAKMEM_TINY_PROFILE=full HAKMEM_WARM_TLS_BIND_C7=2 HAKMEM_WARM_C7_MAX=8 HAKMEM_WARM_C7_PREFETCH=4`, ws=256
- **C7-only (size=1024, iters=200K, ws=32)**
- policy=legacy: 47.3M / 47.3M / 43.9M ops/s平均 ≈ **46M**。C7 uc_miss=6660 / warm_hit=3329 / shared_lock=5 / tls_carve_success=3329。
- policy=autoLearner: score=lock*4+miss: 45.6M / 44.6M / 39.7M ops/s平均 ≈ **4345M**)、統計は legacy と同一C7 固定 ON
- guard 比較: full **42.4M ops/s** vs larson_guard **40.7M ops/s**-4%程度で安全側ガードを維持)。
- **1291024B (iters=1M, ws=256)**
- legacy: **51.5M ops/s**。C5 uc_miss=1/warm_hit=0/shared_lock=1、C6 uc_miss=1/warm_hit=0/shared_lock=2、C7 uc_miss=17196/warm_hit=8597/shared_lock=5/tls_carve_success=8597。
- auto: **51.9M ops/s**Learner=lock 重視でも C7 のみ ON、統計ほぼ同じ
- guard 比較: full **49.0M ops/s** vs larson_guard **48.4M ops/s**-1.2%)。
- **full random_mixed 161024B (iters=1M, ws=256)**
- legacy: **51.0M ops/s**。C7 uc_miss=16702/warm_hit=8350/shared_lock=5/tls_carve_success=8350C5/C6 は uc_miss=1〜2
- auto: **50.0M ops/s**C7 固定 ON のまま、他クラスはほぼ動かず)。
- 補足:
- WarmPool-STATS と TinyClassStats を統合。`HAKMEM_WARM_POOL_STATS=1` で C7-only 実行時に hits=3329 / misses=1 / prefilled=1 を確認TinyClassStats の warm_hit=3329 と一致)。
- `TinyClassPolicy``tls_carve_enabled` を追加し、デフォルトで C5C7 を ON。`TinyClassStats` に tls_carve_attempt/success を追加済み。
- Learner のスコアを `score = shared_lock * 4 + uc_miss` に変更済みauto プロファイル専用)。現状のワークロードでは C7 が圧倒的に優勢で、C5/C6 はまだほぼ選ばれない。
### サイズ→クラス対応HAKMEM_TINY_HEADER_CLASSIDX=1 のため size+1 で判定)
- `hak_tiny_size_to_class(size)``needed=size+1``g_size_to_class_lut_2k` を引くため、512B 要求は 513B として class 7 判定になる(現状の挙動は仕様どおり)。
- 代表サイズのマップデータサイズ→class_idx / 総バイト数)
- 8B → C116B stride
- 16B → C232B
- 32B → C364B
- 64B → C4128B
- 128B → C5256B
- 256B → C6512B
- 512B → C72048B stride / 32 blocks per slab
- 1024B → C7同上
- 512B 固定ベンチで C7 経路が動くのはこのヘッダ加算による設計上の結果。現時点では「C7 支配」を前提に C5/C6 は拡張枠として観測を続ける。
### C5/C6 専用ワークロードの速報Release, ws=512, iters=1,000,000, size fixed
- 条件: `HAKMEM_BENCH_MIN_SIZE=256 HAKMEM_BENCH_MAX_SIZE=256 (実質 C6)``HAKMEM_TINY_PROFILE=full``HAKMEM_WARM_TLS_BIND_C7=2``HAKMEM_TINY_STATS_DUMP=1`
- policy=legacy: Throughput ≈ **89.9M ops/s**。C6: uc_miss=5, warm_hit=1, shared_lock=2, tls_carve_attempt=1, tls_carve_success=1。
- policy=auto: Throughput ≈ **87.5M ops/s**。C6 の統計はほぼ同じuc_miss=5, warm_hit=1, tls_carve_attempt/success=1。C5 ほぼ負荷なし。
- 補足: C5/C6 はワーキングセットを広げても Warm/TLS carve のヒットは少数(キャッシュヒット優位なため)。専用負荷を増やす場合はさらに ws を広げて観測予定。
- Larson ベンチRelease, 10 runs, `./test_larson.sh`
- profile=full: 1.15〜1.26M ops/s
- profile=larson_guard: 1.10〜1.27M ops/s≈-3〜0%でほぼ同等)。`HAKMEM_SS_STATS_DUMP=1` で Superslab live が 1 前後に収まり、SEGV/OOM なし。サンプルログは `docs/analysis/SUPERSLAB_STATS_SNAPSHOT.md` に記録。
### 新しいログ/ENV スイッチ
- `HAKMEM_TINY_POLICY_LOG=0/1`: Policy 初期化/auto update のログ抑制(デフォルト ON
- `HAKMEM_TINY_WARM_LOG=0/1`: C7 prefill 関連ログPREFILL_META/skip 等)の抑制(デフォルト ON
- `HAKMEM_TINY_PAGEBOX_LOG=0/1`: Page Box の登録ログ抑制Debug のみ、デフォルト ON
- 長時間ラン時は上記を 0 にしてノイズを抑える運用を推奨。短時間デバッグ時のみ 1 にする。
### 次にやること(広い条件での安定化確認)
1. `HAKMEM_BENCH_MIN_SIZE=129 HAKMEM_BENCH_MAX_SIZE=1024` や通常の `bench_random_mixed_hakmem 1000000 256 42`
空スラブ限定ガードが副作用なく動くかを継続確認(現状 Release で 2930M ops/s を確認済み)。
2. ドキュメント更新:
- Release だけ C7 Warm が死んでいた根本原因 = 満杯 C7 slab を Shared Pool がリセットせず再供給していた。
- Acquire の空スラブ強制ガードStage3(LRU) 再利用時の Superslab 全スロットリセットWarm/TLS carve 有効化で、
C7-only Release が ~2025M ops/s クラスに回復し、Random Mixed 161024B Release も ~2930M ops/s クラスまで改善した。
3. 次フェーズ案:
- Superslab ガードStats/Reset/Stage3/Budget/larson_guardまで完了。以降は mimalloc/system との比較最適化や、必要に応じた C5/C6 Tiny-Plus 拡張を検討。
### 次フェーズTiny 全クラス向け Page Box / Warm / Policy 汎用化の検討)
- 方向性:
- 現在は C7 向け Tiny-PlusPage Box + Warm Pool + TLS Bindが安定したため、C1〜C7 まで「候補」として広げつつ、
実際にどのクラスで有効化するかは Policy Box学習/ENV側で制御する設計に進める。
- 設計方針(案):
- `TinyClassPolicyBox` を新設し、クラス別ポリシー構造体(`TinyClassPolicy{ page_box_enabled, warm_enabled, warm_cap, ... }`)を配列で保持。
- Hot pathTiny Front / Unified Cache / Page Box / Warm Pool`tiny_policy_get(class_idx)` でポリシーを読むだけにし、
学習/更新は `TinyPolicyLearnerBox` 側で行う。
- `TinyClassStatsBox` を導入し、クラス別に UC miss / warm hit / shared_pool_lock などの軽量カウンタを記録OBSERVE/LEARN モード用)。
- モードは FROZEN / OBSERVE / LEARN を ENV で切替可能にし、デフォルトは FROZENC5C7 のみ Page Box/Warm ON, 他クラス OFF
- 実装ステップ(案):
1. C7 Page Box / Warm / TLS Bind の API を「class_idx を引数に取る汎用形」に整理し、内部で `if (!policy->page_box_enabled) fallback` する形にリファクタ。
2. `TinyClassPolicy` struct と `tiny_policy_get(class_idx)` を導入し、Hot path から直接 `HAKMEM_*` ENV を参照しないようにするPolicy Box 経由に統一)。
3. `TinyClassStatsBox` を追加し、FROZEN/OBSERVE モードで C1〜C7 の stats を集計policy はまだ固定)。
4. `TinyPolicyLearnerBox` を追加し、LEARN モードで stats をもとに `page_box_enabled[]` / `warm_cap[]` を更新(ただし「同時に ON にできるクラス数」に上限を設ける)。
- 進捗メモ(実装済み):
- `TinyClassPolicyBox`/`TinyClassStatsBox`/`TinyPolicyLearnerBox` を追加し、デフォルトで C5〜C7 に Page Box + Warm を許可Warm cap=8
- unified_cache_refill の Page/Warm 経路は `tiny_policy_get()` の返り値でゲートし、Warm push は per-class cap を尊重。
- Page Box 初期化もデフォルトで C5〜C7 を有効化。OBSERVE 用の軽量 stats increment を UC miss / Warm hit に接続済み。
- 次ステップの設計メモ:
- TinyPageBoxContext を class 汎用構造に広げ、C5/C6 も「TLS Bind で page 登録 → UC refill で page 内 freelist からバッチ供給」を C7 と共有できるようにする(実装は未着手、設計メモのみ)。
### メモ
- ページフォルト問題は Prefault Box + ウォームアップで一定水準まで解消済みで、現在の主ボトルネックはユーザー空間の箱Unified Cache / free / Pool側に移っている。
- 以降の最適化は「箱を削る」ではなく、「HOT 層で踏む箱を減らし、Tiny 的なシンプル経路と Tiny-Plus 経路Page Box + Warmをクラス別ポリシーでどう使い分けるか」にフォーカスする。
## 今後のフォーカスC7 支配を前提に一旦整理)
- 設計明記: 257512→C6, 5132048→C7size+1 判定)。実負荷は C7 が受ける設計として確定。C5/C6 は拡張枠・観測対象。
- 優先度: C5-only ≈91M ops/s、512B 固定も C7 経路で ≈47M ops/s → C5/C6 最適化は auto/実験用に留め、本命は C7 Tiny-PlusPolicy。
- プロファイル運用: legacy=本番、auto=C7固定上位2クラス観測用のまま据え置き。学習拡張は新ワークロードで C5/C6 がホットになった際に検討。
- 次の大きな箱候補: (1) mimalloc/system とのフルベンチ整理(論文/README 更新)、(2) hakorune 側 PHI/JoinIR の開発にリソースを戻す。
## 巨大 BSS グローバルの棚卸しと今後
- `nm -S --size-sort bench_random_mixed_hakmem` と SS_STATS のサンプルから、RSS を支配しているのは Tiny 層ではなく巨大 BSS 配列であることを確認。
- 代表例: `g_super_reg` ≈24MB, `g_shared_pool` ≈2.3MB, `g_super_reg_by_class` ≈1MB, `g_rem_side` ≈1MB など。
- SS_STATSws=64, iters=10kでは live Superslab は C2=1, C7=1 程度で、巨大レジストリの大半は未使用キャパシティになっている。
- Tiny 用メモリ会計 Box`tiny_mem_stats_box`)では UC/Warm/Page/TLS/Policy-Stats 合計でも ≈40KB 程度と判明し、RSS≈29MB の主因ではないことを確認。
- docs/analysis/LARGE_GLOBALS_OVERVIEW.md に各大型シンボルのサイズ/役割と SS_STATS とのギャップを一覧化済み。
次フェーズ候補:
- Superslab Registry / Shared Pool / Remote Queue を Box 化し、プロファイル別に「必要なだけ動的確保」できる SuperRegBox / SharedPoolBox / RemoteSideBox への移行を検討。
- `HAKMEM_PROFILE` や ENV から「bench 向け縮小設定」と「本番向けフル設定」を切り替えられるようにし、RSS を抑えつつ Box 構造は維持する。
進捗巨大BSS Box化フェーズ
- docs/analysis/LARGE_GLOBALS_OVERVIEW.md に大型シンボルの定義元・役割・縮小目安を追記SuperReg/SharedPool/Remote など)。
- 設計スタブを追加:
- `core/box/super_reg_box.h` … レジストリ容量をプロファイルで切替するための API メモ。
- `core/box/shared_pool_box.h` … Shared Pool の容量/ガードをプロファイルに紐づけるための API メモ。
- `core/box/remote_side_box.h` … Remote Queue テーブルをプロファイルで縮小するための API メモ。
- `HAKMEM_PROFILE=bench` を追加し、SuperReg/SharedPool/Remote の「論理有効スロット」を 1/8〜1/16 に制限するラッパを実装(配列は現状サイズのまま)。`bench_random_mixed_hakmem` は full/bench ともビルド・完走済み。C7-only/1291024B/161024B で ops/s は ±数% 以内、RSS は ~32.6MB でほぼ不変(論理制限のみのため)。
- SuperReg/Remote を Box 内で動的確保に置き換え、`HAKMEM_PROFILE=bench` では実容量も縮小SuperReg: 1/8〜1/16、Remote: log2 を 12〜。C7-only 200k/ws32 では full=29.6MB → bench=7.2MB (ops ≈44.4M 同レンジ) まで RSS を削減できた。
- bench 実容量版での広いワークロード検証: 1291024B ws=256/1M は full=48.9M ops/s & 29.6MB → bench=49.2M & 7.2MB。161024B ws=256/1M は full=48.3M & 29.7MB → bench=48.8M & 7.2MB。SS_STATSbenchでも live Superslab は C2=1, C7=1 に収まり、Tiny 層メモリは ~41KB のまま。
- 次ステップ: SharedPool 側も必要なら動的化/縮小を検討しつつ、RSS をさらに攻めるか、CPU パス最適化に戻るか判断。***
### フェーズ整理と次の方針
- SharedPool は現状サイズを維持し、`HAKMEM_PROFILE=full` を本番、`HAKMEM_PROFILE=bench` を対 mimalloc/system の軽量プロファイルとして運用bench は SuperReg/Remote 縮小済み、RSS≈7.2MB)。
- 巨大BSS Box化フェーズは「bench で RSS≈7.2MB / ops≈同等」まで完了。今後は perfCPUサイクル最適化にフォーカス。
ホットパス perf フェーズの TODO
1. tiny_alloc_fast / tiny_free_fast_v2 の再プロファイル:残存分岐・間接呼び出し・重い箱を特定。
2. Unified Cache ヒットパスを最短化:ヒット時を 12 load + 軽分岐に近づける(必要なら C7 専用インライン版検討)。
3. free パス Gatekeeper/Box の再配線C7 ホットケースだけ分岐極小のストレートラインにする。
目標: シングルスレッド小オブジェクトで ~50M ops/s → 70M〜80M 帯を狙うmimalloc との差を半減イメージ)。***
補足CPU ホットパス観測メモ)
- `HAKMEM_PROFILE=bench HAKMEM_TINY_PROFILE=full HAKMEM_WARM_TLS_BIND_C7=2` で perf を試行したが、`perf_event_paranoid` 制約で `cycles` が取れず page-fault サンプルのみ(`__memset_avx2_unaligned_erms` が warmup を支配)。`perf.data` は即削除済み。集計結果と次の測定案は `docs/analysis/CPU_HOTPATH_OVERVIEW.md` に記載。
- C7 alloc/free flattening と UC ヒット簡略化の設計メモを追加:`docs/analysis/C7_HOTPATH_FLATTENING.md`, `docs/analysis/C7_FREE_HOTPATH.md`。実装はこれから。
- C7 ホットパス用フックを追加(`core/box/tiny_c7_hotpath_box.h` + `HAKMEM_TINY_C7_HOT`)。今は既存 Hot/Cold Box をクラス固定で呼ぶ薄いラッパなので挙動は同一。
- bench プロファイルの perf stat (3 run 平均):
- 161024B: cycles≈109.5M, inst≈233.5M (IPC≈2.13, br-miss≈2.90%)
- 161024B + `HAKMEM_TINY_C7_HOT=1`: cycles≈111.8M, inst≈242.1M (IPC≈2.16, br-miss≈2.75%)
### C7 ホットパス平坦化第1段階の結果メモ
- `HAKMEM_PROFILE=bench HAKMEM_TINY_PROFILE=full HAKMEM_WARM_TLS_BIND_C7=2`、1291024B ws=256/1MReleaseで:
- `HAKMEM_TINY_C7_HOT=0`: ≈49.7M ops/s
- `HAKMEM_TINY_C7_HOT=1`: ≈46.7M ops/s分岐ミスは僅かに改善するがスループットはイズ〜微減
- 161024B ws=256/1M では:
- hot=0: ops≈47.4M, IPC≈2.13, br-miss≈2.90%
- hot=1: ops≈47.447.6M, IPC≈2.16, br-miss≈2.75%
- 現状の C7 ホットパス実装は「ヒット専用 UC TLS→UC→cold 直線化」の初期版で、大幅な伸びはまだ無い。回帰はなく、分岐ミス率はわずかに改善。今後さらに UC ヒット専用関数の最短化や free 側の直線化を詰める余地あり。
- 方針: `HAKMEM_TINY_C7_HOT` は実験用スイッチとして残し、デフォルト OFF。perf フェーズは bench プロファイルで ≈50M ops/s / RSS ≈7MB を維持できる現行経路を基準に一旦完了とする。***