Files
hakmem/docs/design/TINY_HOTHEAP_V2_IMPLEMENTATION_GUIDE.md
2025-12-09 21:50:15 +09:00

594 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TinyHotHeap v2 Implementation Guide (A案 → C案の入口)
日付: 2025-12-05
対象: 実装担当 AI / 開発者向け指示書
関連ドキュメント:
- `docs/analysis/TINY_HEAP_V2_DESIGN.md` (Phase36+ 設計 / A/B/C 案・箱構造)
- `docs/analysis/TINY_HEAP_BOX_DESIGN.md` (v1 TinyHeapBox / C7 HotBox)
- `docs/analysis/C7_HOTBOX_DESIGN.md` (既存 C7 HotBox 設計)
- `CURRENT_TASK.md` (Phase36 状況メモ)
- ステータス: Phase36 で C7-only の Hot 部current_page+freelistを v2 で自前管理する暫定実装を投入済み。Superslab/Tier/Stats は v1 に委譲する lease/refill/retire 境界で A/B できる状態。
### Phase65/66: C7-only フェーズ完了サマリ
- C7-only / Mixed 161024B の長尺プロファイルws=400, iters=1M, PROFILE=C7_SAFEで、v2 ON/OFF いずれも `HEAP_STATS[7].slow≈1`・refill≈1 に収束し、性能は v1 比で ±5% 以内(むしろ数%プラス)。
- 短尺ベンチ20k/ws=64で見える refill≒50 はウォームアップ由来と判断され、本命プロファイルに影響しないことを確認。
- 運用上の扱い:
- デフォルト構成では `HAKMEM_TINY_HOTHEAP_V2=0`C7 SAFE v1を維持。
- C7-only の bench/pro 用プロファイルでは `HAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80` を opt-in 推奨とし、v2 を本命候補の Hot Box として使う。
- C6 v2 は構造こそ通電したものの perf 未達のため、引き続き研究箱classes=0x40/0xC0 を明示したときだけ有効)に留める。
### Phase60 速報C7-only 空ページ保持ポリシー)
- 追加したもの:
- `max_partial_pages`C7 デフォルト 2`partial_count` を Hot Box に追加し、free で `used==0` の page は一度 partial へ温存。上限超のみ retire を呼ぶ。
- partial push/pop/peak と retire_v2 を v2 stats に追加(`HAKMEM_TINY_HOTHEAP_V2_STATS=1` で確認)。
- 初期ベンチ:
- C7-only v2 ON で slow_prepare は `alloc_lease` と一致≈48 回。live ブロックが多く page が空にならないため partial/retire は未発火。
- Mixed でも v2 ON は +2〜3% だが slow≈refill(42)。空ページを作れる workload またはページ容量/lease の見直しが次課題。
- 運用: v2 は引き続き研究箱(デフォルト OFF。C7-only で安定後に Mixed への適用を検討する。
---
## 0. ゴールと非ゴール
- ゴール
- TinyHotHeap v2 を **per-thread Hot Box** として実装し、C7-only から段階的に C6/C5 へ拡張できる骨格を作る。
- Hot Box 側は **heap→page→block のみ** を扱い、Superslab/Tier/Remote/Stats/Learning との境界は
- alloc 側: `tiny_hotheap_v2_refill_slow(...)`
- free 側: `tiny_hotheap_v2_page_retire_slow(...)`
の 1 箇所に集約するBox Theory: 境界 1 箇所)。
- A/B: `HAKMEM_TINY_HOTHEAP_V2` / `HAKMEM_TINY_HOTHEAP_CLASSES` / Route Snapshot により、
C7-only で v1 C7_SAFE と v2 Hot Box を即時切り替え可能にする。
- 非ゴール(このガイドの範囲外)
- Superslab/Tier/Guard/Remote のフル再設計C 案の Segment+Page+Block までは行かない)。
- C0〜C4 や mid/large サイズ帯の設計変更。
- 学習層 (ACE/ELO) の仕様変更。Hot path は従来どおり Snapshot を読むだけとする。
---
## 1. 箱の対応関係(概念 → 既存型へのマッピング)
設計ドキュメントでは便宜的に:
- `TinyPageMeta` / `TinyClassHeap` / `TinyHeapCtx`
という名称で説明しているが、実装では既に存在する v2 skeleton を利用する:
- ファイル: `core/box/tiny_hotheap_v2_box.h`
- `tiny_hotheap_page_v2` … 概念上の `TinyPageMeta`
- `tiny_hotheap_class_v2` … 概念上の `TinyClassHeap`
- `tiny_hotheap_ctx_v2` … 概念上の `TinyHeapCtx`
実装では **この既存ヘッダを Hot Box の中核** とし、
他のファイルからは基本的に `tiny_hotheap_v2_*` API 経由でしか触らない。
---
## 2. Hot Box 実装ステップ
### Step 2-1: 型の見直しと拡張 (core/box/tiny_hotheap_v2_box.h)
目的: `tiny_hotheap_page_v2` / `tiny_hotheap_class_v2` / `tiny_hotheap_ctx_v2`
Phase36 設計の A 案Hot Boxに揃える。
作業指示:
- `tiny_hotheap_page_v2`
- すでに `freelist/used/capacity/base/meta/ss/slab_idx/next` を持っているので、
**ページ内 freelist と Cold 側リンク用の最小限メタ** として継続利用する。
- 必要であれば `flags`HOT/PARTIAL/FULLなどの軽量フラグを追加してよい。
- `lease_page` フィールドは「v1 page への橋渡し用」なので、
Phase1 では残しておき、将来的には A 案が安定した時点で削除/無効化を検討する。
- `tiny_hotheap_class_v2`
- `current_page` / `partial_pages` / `full_pages` が A 案の `TinyClassHeap` に相当する。
- `storage_page` は Phase32 の「C7 1 枚 lease」専用だが、Phase1 では
- C7-only: storage を current_page として使う
- 複数ページ化後: storage は「最初の page」または「固定 1 枚キャッシュ」として扱う
形で再利用してよい(完全削除は後のフェーズでも可)。
- `stride` はクラスごとの block サイズ(バイト数)として維持。
- `tiny_hotheap_ctx_v2`
- `cls[TINY_HOTHEAP_MAX_CLASSES]` の配列で全 Tiny class をカバー済み。
Phase1 では **C7-only を有効** にし、C6/C5 は未使用のままでよい。
このステップでは **まだ関数実装をいじらず、型だけを A 案に整合** させる。
### Step 2-2: TLS 取得 API の実装 (core/hakmem_tiny.c など)
目的: Hot Box の入口を 1 箇所に揃える。
作業指示:
- `tiny_hotheap_v2_tls_get()` の実装:
- `g_tiny_hotheap_ctx_v2``__thread`)を lazily `malloc`/`calloc` し、`memset` でゼロ初期化。
- 初期化時に `tiny_hotheap_v2_page_reset(&cls[i].storage_page)` など、
最低限のリセットを行うBox 内に初期化を閉じ込める)。
- 返り値は `tiny_hotheap_ctx_v2*`。以降、Hot Box の関数は **必ず ctx を通して状態にアクセス** する。
### Step 2-3: alloc Hot パスの実装 (tiny_hotheap_v2_box.h)
目的: C7-only の `tiny_hotheap_v2_alloc()`**page 内 freelist + current/partial** だけで完結させる。
推奨構造:
- `static inline void* tiny_hotheap_v2_alloc_fast(tiny_hotheap_ctx_v2* ctx, uint8_t class_idx);`
- `void* tiny_hotheap_v2_alloc(uint8_t class_idx);` は Gate から呼ばれる薄いラッパとして、
- `ctx = tiny_hotheap_v2_tls_get();`
- `return tiny_hotheap_v2_alloc_fast(ctx, class_idx);`
だけを行う。
Hot パスのロジックC7 専用版):
- `tiny_hotheap_class_v2* hc = &ctx->cls[class_idx];`
- 優先順位:
1. `hc->current_page` があり、その `freelist` が非 NULL → 1 block pop して `used++`
2. `hc->partial_pages` リストがあれば 1 枚取り出し、`current_page` に昇格させてから pop。
3. どちらも空なら `tiny_hotheap_v2_refill_slow(ctx, class_idx)` へ降りる。
注意:
- Phase1 では **C7-only** を対象とし、`class_idx == 7` 以外は即座に v1 経路へフォールバックしてよい。
- `tiny_hotheap_v2_refill_slow` は次節の Cold Box との境界関数として後から実装する。
### Step 2-4: free Hot パスの実装 (tiny_hotheap_v2_box.h)
目的: C7-only の `tiny_hotheap_v2_free()` を page 内 freelist push + empty 判定だけにする。
推奨構造:
- `static inline void tiny_hotheap_v2_free_fast(tiny_hotheap_ctx_v2* ctx, uint8_t class_idx, void* p, struct TinySlabMeta* meta);`
- `void tiny_hotheap_v2_free(uint8_t class_idx, void* p, void* meta);` は Gate 用ラッパとして、
- `ctx = tiny_hotheap_v2_tls_get();`
- `tiny_hotheap_v2_free_fast(ctx, class_idx, p, (struct TinySlabMeta*)meta);`
のみ行う。
Hot パスのロジックC7 専用版):
- `tiny_hotheap_page_v2* page = tiny_hotheap_v2_page_of(ctx, class_idx, p, meta);`
- Phase1 では meta/base/slab_idx から page を特定するヘルパを 1 箱に閉じ込める(実装場所はこのヘッダ or 専用 C ファイル)。
- `*(void**)p = page->freelist; page->freelist = p; page->used--;`
- `page->used == 0` になったら `tiny_hotheap_v2_page_retire_slow(ctx, class_idx, page);` を呼ぶ。
備考:
- Phase1 では **Remote Queue / cross-thread free は従来経路にフォールバック** してよい。
具体的には:
- 所有スレッド以外からの free であれば v1 の remote 経路を即呼び出す。
- 所有スレッド判定には既存の TLS/owner 情報を使うOwnership Box を汚さない)。
---
## 3. Cold Box 境界実装ステップ
### Step 3-1: refill_slowv1 TinyHeap / Superslab からのページ供給)
目的: Hot Box から見て **唯一の「ページ供給」入口** を 1 箇所に集約する。
作業指示:
- 関数案(実装ファイルは `core/hakmem_tiny.c` か、専用の `core/box/tiny_hotheap_v2_cold_box.h` でもよい):
```c
tiny_hotheap_page_v2*
tiny_hotheap_v2_refill_slow(tiny_hotheap_ctx_v2* ctx, uint8_t class_idx);
```
- Phase1 では実装を **既存 v1 TinyHeap/C7 SAFE に橋渡しするだけ** に留める:
- `tiny_heap_c7_lease_page_for_v2()` など、既存の C7 lease API を利用して 1 枚 page をもらう。
- 取得した `TinySlabMeta*` / `SuperSlab*` / `base` / `capacity``tiny_hotheap_page_v2` にコピーし、`current_page` or `partial_pages` に追加。
- freelist の初期化は **Hot Box 側で実施** し、以降の pop/push は v2 が握るv1 に再委譲しない)。
### Step 3-2: page_retire_slow全 free になったページの返却)
目的: ページが empty になった瞬間だけ Cold Box に touch する。
作業指示:
- 関数案:
```c
void
tiny_hotheap_v2_page_retire_slow(tiny_hotheap_ctx_v2* ctx,
uint8_t class_idx,
tiny_hotheap_page_v2* page);
```
- Phase1 の挙動:
- page を `current_page` / `partial_pages` / `full_pages` から unlink。
- v1 側に「ページ free」イベントとして渡す:
- Superslab / Warm Pool / Tier / Guard の扱いは v1 に任せるv2 は触らない)。
- Cold Stats Box があれば、ここで delta を flush する。
- 将来フェーズ:
- Warm Pool / Superslab への返却ロジックを v2 専用に寄せることで、
C 案Segment+Page+Blockへの移行パスとして利用する。
---
## 4. Gate / Route / ENV の配線ステップ
### Step 4-1: Route Snapshot への v2 統合
作業指示:
- ファイル: `core/box/tiny_route_box.h` 付近(`g_tiny_route_class[]` の決定ロジック)。
- ENV:
- `HAKMEM_TINY_HOTHEAP_V2` / `HAKMEM_TINY_HOTHEAP_CLASSES` を読み、
- bit7 が立っていれば `g_tiny_route_class[7] = TINY_ROUTE_HOTHEAP_V2;`
- それ以外は従来通り `TINY_ROUTE_HEAP_V1` / `TINY_ROUTE_LEGACY`
を設定する。
- これにより front 側は `class_idx` 決定後に
- `route = g_tiny_route_class[class_idx];`
- `switch (route) { HOTHEAP_V2 / HEAP_V1 / LEGACY }`
だけで経路を決定できる。
### Step 4-2: front からの呼び出しmalloc_tiny_fast / free_tiny_fast
作業指示:
- ファイル: `core/hakmem_tiny.c` + 各種 `tiny_alloc_fast*.inc.h` / `tiny_free_fast_v2.inc.h`
- C7-only モードの Gate で:
- `route == TINY_ROUTE_HOTHEAP_V2` かつ `size` が C7 クラスにマップされる場合にのみ
`tiny_hotheap_v2_alloc(7)` / `tiny_hotheap_v2_free(7, p, meta)` を呼ぶ。
- それ以外は従来通り v1 TinyHeap / legacy 経路へフォールバックする。
- Free 側では:
- C7 ptr かつ Route=HOTHEAP_V2 かつ owner==self の場合のみ `tiny_hotheap_v2_free` を試す。
- 条件に当てはまらない場合は Remote Queue / v1 free 経路にすぐ落とす。
---
## 5. 可視化・Fail-Fast・A/B の運用
### Step 5-1: v2 専用 Stats の追加(任意だが推奨)
作業指示:
- 既存の `tiny_stats_box` / `tiny_class_stats_box` に倣って、
- `alloc_calls / alloc_fast / alloc_slow_refill / alloc_fb_v1`
- `free_calls / free_fast / free_fb_v1`
のような v2 専用カウンタを追加。
- ENV:
- `HAKMEM_TINY_HOTHEAP_V2_STATS=1` のときだけ destructor で 1 行ログを出す。
### Step 5-2: Fail-Fast ポリシー
作業指示:
- 範囲外 ptr / page_of 失敗 / meta 不整合など、**Hot Box の前提が壊れた場合は即 abort** する。
- v2 実装中は「誤魔化しのフォールバック」を避け、
問題が出たら Fail-Fast で原因を特定するAGENTS.md の方針通り)。
### Step 5-3: 推奨ベンチコマンド(実装後に利用)
実装完了後、以下のようなプロファイルで A/B を行う(ここでは指示のみ、実行は別フェーズ):
- C7-only:
- v1 基準: `HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_HOTHEAP_V2=0 ...`
- v2: `HAKMEM_BENCH_C7_ONLY=1 HAKMEM_TINY_HEAP_PROFILE=C7_SAFE HAKMEM_TINY_HOTHEAP_V2=1 HAKMEM_TINY_HOTHEAP_CLASSES=0x80 ...`
- Mixed 161024B:
- 当面は v1 C7_SAFE を基準に残し、v2 は C7-only が十分安定してから評価する。
---
## 6. 実装順序のまとめ(チェックリスト)
- [ ] 型整理: `tiny_hotheap_page_v2` / `tiny_hotheap_class_v2` / `tiny_hotheap_ctx_v2` を Phase36 A 案に整合させる。
- [ ] TLS 初期化: `tiny_hotheap_v2_tls_get()` を実装し、Hot Box 内に状態を閉じ込める。
- [ ] alloc Hot パス: `tiny_hotheap_v2_alloc_fast()` / `tiny_hotheap_v2_alloc()` を C7-only で実装。
- [ ] free Hot パス: `tiny_hotheap_v2_free_fast()` / `tiny_hotheap_v2_free()` を C7-only で実装。
- [ ] Cold 境界: `tiny_hotheap_v2_refill_slow()` / `tiny_hotheap_v2_page_retire_slow()` を v1 TinyHeap への橋渡しとして実装。
- [ ] Route/Gate: `tiny_route_box` と front を更新し、C7-only で v1/v2/legacy を A/B 切り替え可能にする。
- [ ] Stats/Fail-Fast: v2 専用 stats と assert/abort を追加し、問題発生時にすぐ気付けるようにする。
このガイドは「箱」と「境界」の位置だけを固定するものであり、
細かな最適化C7 超ホットレーン / C6/C5 への拡張 / C 案への橋渡し)は Phase36 以降のサブフェーズで順次詰める前提とする。
---
## 7. Phase37: C7 current_page ポリシー修正指示書
ベンチ結果サマリ(現状 v2 の問題)
----------------------------------
Release, PROFILE=C7_SAFE での観測:
- C7-only (ws=64, iters=20k)
- v2 OFF: 39.64M ops/s, `HEAP_STATS[7] fast=11015 slow=1`
- v2 ON : 26.89M ops/s, `HEAP_STATS[7] fast=97 slow=32758`(ほぼ全て slow_prepare
- Mixed 161024B (ws=256, iters=20k)
- v2 OFF: 38.78M ops/s, `fast=5691 slow=1`
- v2 ON : 33.26M ops/s, `fast=141 slow=16654`
結論:
- v2 ON では `current_page` がほぼ活きておらず、**毎回 slow_prepare に落ちている**。
- 現状の v2 を運用で使うのは危険なため、当面のデフォルトは **v2 OFF (C7_SAFE + HOTHEAP_V2=0)** を維持する。
この Phase37 の目的
-------------------
- 目的:
- C7-only で **`current_page` をきちんと保持・再利用し、slow_prepare をほぼゼロに抑える**。
- v1 C7 SAFE / TinyHeapBox の current_page ポリシーを v2 Hot Box に移植する。
- 非ゴール:
- C6/C5 への展開。
- Cold Box (Superslab/Tier/Remote/Stats) の構造変更。
ざっくりタスク一覧
------------------
- [ ] v2 専用 current_page デバッグ統計の追加
- [ ] refill_slow → current_page セット手順の見直し
- [ ] free 側で current_page を再利用するポリシーの導入
- [ ] retire 条件の見直しempty でもすぐ返さない)
- [ ] v1 C7 SAFE current_page ポリシーとの比較・差分吸収
- [ ] C7-only / Mixed ベンチで slow_prepare を再確認
以下、それぞれの具体指示。
Step 7-1: current_page デバッグ統計の追加
----------------------------------------
目的:
- v2 が「どこで current_page を失って slow_prepare に落ちているか」を**1 箇所で見える化**する。
作業指示:
- 参考: `docs/analysis/TINY_HEAP_BOX_DESIGN.md` にある C7 current_page stats`prepare_calls` など)。
- 新規 struct を追加(場所は `tiny_hotheap_v2_box.h` か、専用 stats ファイルでも良い):
- `uint64_t prepare_calls;`
- `uint64_t prepare_with_current_null;`
- `uint64_t prepare_from_partial;`
- `uint64_t free_made_current;`
- `uint64_t page_retired;`
- ENV `HAKMEM_TINY_HOTHEAP_V2_STATS=1` のときのみカウンタを更新・dump する。
- カウントポイント:
- `tiny_hotheap_v2_alloc_fast` 内:
- entry ごとに `prepare_calls++`
- `hc->current_page==NULL` のとき `prepare_with_current_null++`
- partial から current に昇格したとき `prepare_from_partial++`
- `tiny_hotheap_v2_free_fast` 内:
- free で page が current になる/保持される場合 `free_made_current++`
- `tiny_hotheap_v2_page_retire_slow` 内:
- `page_retired++`
Step 7-2: refill_slow → current_page セットの修正
-----------------------------------------------
目的:
- refill 後に必ず「C7 用の current_page が 1 枚セットされる」ようにする。
作業指示:
- `tiny_hotheap_v2_refill_slow` の振る舞いを以下のように揃える:
1. C7 用 lease API`tiny_heap_c7_lease_page_for_v2()` など)から 1 枚 page を取得。
2. `tiny_hotheap_page_v2` へ:
- `base / capacity / meta / ss / slab_idx / stride` をコピー。
- freelist を page 内 carving で初期化pop は v2 が握る)。
3. `tiny_hotheap_class_v2* hc = &ctx->cls[7];` に対して:
- `hc->current_page` が NULL なら **必ずここで current_page にセット**
- 既に current がある場合は `hc->partial_pages` に push。
- refill 後に `hc->current_page` が NULL のままにならないよう、Fail-Fast assert を入れても良い(デバッグ時)。
Step 7-3: free 側で current_page を維持・再利用する
-----------------------------------------------
目的:
- C7-only では「同じ page 内で alloc/free が揺れる」ケースが多いため、
free 側で current_page をなるべく保持・再利用する。
作業指示:
- `tiny_hotheap_v2_free_fast` で、以下のようなポリシーを入れるv1 TinyHeapBox SAFE と同等イメージ):
- `page->used > 0` かつ `page->freelist != NULL` の page は **current_page 候補**
- `hc->current_page` が NULL の場合は、free した page を current に据え直す。
- `hc->current_page` が他の page を指していても、C7-only フェーズでは「free された page に空きがあるなら current に切り替える」実験をして良い(後で safe なポリシーに絞る)。
- これにより、C7-only ベンチで `prepare_calls` に対して `prepare_with_current_null` がほぼ 0 に近づくことを期待する。
Step 7-4: retire 条件の見直し
-----------------------------
目的:
- v2 ON で empty page を早々に Cold Box に返しすぎると、current_page を毎回失って slow_prepare 連発になる。
作業指示:
- `tiny_hotheap_v2_page_retire_slow` を呼ぶ条件を見直す:
- Phase37 では「C7-only ベンチでは page が empty になってもすぐには返さない」実験を許容する。
- 具体案:
- `page->used == 0` でも、まず `hc->partial_pages` の一員として残す(一定枚数を超えたら返却)。
- C7-only フェーズでは `max_partial_pages` を 1〜2 に固定して試す。
- 本番運用向けには、後続フェーズで安全側にチューニングし直す前提で、「今は slow_prepare を殺すことを最優先」にしてよい。
Step 7-5: v1 C7 SAFE current_page ポリシーとの比較
-----------------------------------------------
目的:
- 「すでにうまく動いている v1 C7 SAFE / TinyHeapBox の current_page 設計」を v2 に再利用する。
作業指示:
- 参照:
- `docs/analysis/TINY_HEAP_BOX_DESIGN.md`
- `docs/analysis/C7_HOTBOX_DESIGN.md`
- この2つから:
- alloc 時: `prepare_calls=1` に抑えるための current 固定ロジック
- free 時: empty page の扱いULTRA/SAFE の違い)
を抜き出し、v2 Hot Box の `alloc_fast` / `free_fast` / `page_retire_slow` に反映する。
- 差分:
- v1 TinyHeapBox は meta/ss_active 更新も Hot 側が握っていたが、v2 では Cold Stats Box に寄せる方針。
- そのため meta/active の更新部分だけは v1 と同じにせず、**current_page に関わるポリシー部分だけをコピー** する。
Step 7-6: 再ベンチと判定基準
---------------------------
作業指示:
- C7-only (ws=64, iters=20k, PROFILE=C7_SAFE) で:
- v2 OFF: 39〜40M ops/s既存ベースライン
- v2 ON : 目標として **少なくとも v2 OFF と同等 ±5% 以内** を目指す。
- `HEAP_STATS[7] fast≈11015 slow≈1` に戻ることを確認。
- v2 current_page stats では:
- `prepare_calls` に対して `prepare_with_current_null` が ≪1% 程度
- Mixed 161024B (ws=256, iters=20k) では:
- v2 OFF の 38〜39M ops/s に対して **±5% 以内** を許容範囲とする。
- C7-only が十分安定・同等以上であれば、Mixed の調整は後続フェーズで良い。
判定:
- 上記基準を満たせば「Phase37: current_page ポリシー修正完了」とし、
次フェーズで C6/C5 への拡張や C7 超ホットレーンB案を検討できる。
- 満たせない場合は v2 を引き続き **デフォルト OFF / 研究用箱** としたまま、
current_page / retire ポリシーの再修正に戻る。
---
## 8. Phase58: TinyColdIface 導入後の課題整理と次の実装指示
現状ステータスPhase58 時点)
------------------------------
- `core/box/tiny_cold_iface_v1.h``TinyColdIface` が導入され、v1 TinyHeap の
- `tiny_heap_prepare_page()``refill_page(cold_ctx, class_idx)`
- `tiny_heap_page_becomes_empty()``retire_page(cold_ctx, class_idx, page)`
としてラップ済み。Hot Box 側からはこの IF だけを見れば Superslab/Tier/Stats に触れられる状態になっている。
- C7 v2 の Cold 境界は次のように接続済み:
- `tiny_hotheap_v2_refill_slow()`:
- `TinyColdIface cold = tiny_cold_iface_v1();`
- `tiny_heap_ctx_t* cold_ctx = tiny_heap_ctx_for_thread();`
- `ipage = cold.refill_page(cold_ctx, class_idx)` で v1 から `tiny_heap_page_t` を 1 枚借りる。
- v2 側の `tiny_hotheap_page_v2` ノードを確保し、`base/capacity/meta/ss/slab_idx` をコピー。
- freelist が無い場合は v2 が `used=0` にリセットし、`tiny_hotheap_v2_build_freelist()` で carve する。
- freelist がある場合は `lease_page->meta->freelist` を v2 freelist で更新。
- `hc->current_page` に必ず freelist 付きページが入るよう Fail-Fast チェックを追加。
- `tiny_hotheap_v2_page_retire_slow()`:
- v2 の `current_page` / `partial_pages` / `full_pages` から対象ページを unlink。
- `cold.retire_page(cold_ctx, class_idx, page->lease_page)` を呼んで v1 側へ返却。
- `storage_page` 以外は `free(page)`、storage は `tiny_hotheap_v2_page_reset()` で初期化。
- TLS 初期化 (`tiny_hotheap_v2_tls_get()`) では、`tiny_hotheap_ctx_v2``calloc` し、各クラスの `storage_page` を reset、`stride``tiny_stride_for_class(i)` で事前設定するようにした。
- v2 Stats:
- `g_tiny_hotheap_v2_c7_*``alloc_calls/route_hits/alloc_fast/alloc_refill/alloc_fallback_v1/free_*`
`cold_refill_fail` / `cold_retire_calls` を追加し、`HAKMEM_TINY_HOTHEAP_V2_STATS=1` で destructor ダンプ。
残っている問題(なぜ v2 ON で SEGV するか)
-----------------------------------------
- `tiny_hotheap_v2_try_pop()` は依然として v1 TinyHeap の page API に強く依存している:
- `candidate->lease_page``ipage` として取り出し、
- `v1hcls->current_page = ipage;`
- `tiny_heap_page_pop(v1hcls, 7, ipage);`
- 必要なら `tiny_heap_page_mark_full(v1hcls, ipage);`
を呼んだうえで、
- `candidate->freelist = ipage->free_list;`
- `candidate->used = ipage->used;`
と v2 側 state にもコピーしている。
- これは Box Theory 的には
> Hot Box (v2) が Cold Box (v1 TinyHeap) の内部状態 (`free_list/used`) を直接操作している
ことになり、境界が二重になっている。
- refill で v2 が独自に carve した freelist と、v1 の `tiny_heap_page_pop()` が更新する `free_list/used/meta` がずれていくと、
- 無効な `ipage->base` / `capacity` / `meta` を deref したり
- v2 の `candidate->freelist` が壊れた状態で次の pop に進んでしまう
可能性がある。現状の SIGSEGV はこのあたりの不整合に起因していると考えられる。
Phase58 でやるべきこと(実装指示)
---------------------------------
### 8-1. `tiny_hotheap_v2_try_pop()` から v1 依存を外し、v2 freelist だけで完結させる
目的:
- Hot Box v2 は「自分の freelist を自分で pop する箱」とし、Cold Box v1 には refill/retire でしか触れないようにする。
作業指示:
- `tiny_hotheap_v2_try_pop()` を次の方針で書き換える:
- 引数から `tiny_heap_class_t* v1hcls` を削除し、`TinyColdIface` / v1 TinyHeap の型に依存しない形にする。
- `candidate` から直接 freelist を pop:
```c
static inline void* tiny_hotheap_v2_try_pop(tiny_hotheap_page_v2* candidate,
TinyHeapClassStats* stats,
int stats_on) {
if (!candidate || !candidate->freelist || candidate->used >= candidate->capacity) {
return NULL;
}
void* user = candidate->freelist;
candidate->freelist = *(void**)user;
candidate->used++;
if (__builtin_expect(stats != NULL, 0)) {
atomic_fetch_add_explicit(&stats->alloc_fast_current, 1, memory_order_relaxed);
}
if (stats_on) {
atomic_fetch_add_explicit(&g_tiny_hotheap_v2_c7_alloc_fast, 1, memory_order_relaxed);
}
return tiny_region_id_write_header(user, 7);
}
```
- v1 TinyHeap (`tiny_heap_page_pop` / `tiny_heap_page_mark_full` / `v1hcls->current_page` など) の呼び出しは完全に削除する。
- `candidate->lease_page` は **Cold 側に返すための token** として保持するだけにし、Hot path では一切触らない。
### 8-2. Cold 境界 (`refill_page` / `retire_page`) を「イベント 2 箇所だけ」に限定する
目的:
- Hot Box v2 と Cold Box v1 の境界を「page を借りる」「page を返す」の 2 箇所だけにし、meta/used/freelist の二重管理をやめる。
作業指示:
- `tiny_hotheap_v2_refill_slow()`:
- `TinyColdIface.refill_page()` から返ってきた `tiny_heap_page_t* ipage` については、
- `base` / `capacity` / `slab_idx` / `meta` / `ss` など **geometry 情報だけ** を読む。
- `ipage->free_list` / `ipage->used` は Hot path では信頼しないv2 が自前で carve した freelist を使う)。
- v2 側の `tiny_hotheap_page_v2` に freelist を構築したら、以降の alloc/free は v2 freelist だけで完結させる。
- どうしても meta に初期値を書き戻す必要がある場合は、Cold Stats Box 経由の更新に寄せる(直接 meta->used に触らない方向を優先)。
- `tiny_hotheap_v2_page_retire_slow()`:
- `page->used == 0` かつ v2 内のリストから unlink した段階でのみ `TinyColdIface.retire_page()` を呼ぶ。
- 返却後は `page->lease_page` を含めて v2 側 state を破棄または reset し、同じ token を Hot path から再利用しない。
### 8-3. 安全側のガードと Stats での確認ポイント
目的:
- v2 を再度 ON にした際、segv や Cold IF への過剰依存がないかをすぐに検知できるようにする。
作業指示:
- `tiny_hotheap_v2_alloc()` / `tiny_hotheap_v2_free()` の入口で:
- `class_idx != 7` は即 `NULL` or fallbackC7-only 実験箱のまま)。
- `v2ctx == NULL` / `hc == NULL` / `hc->stride == 0` などは Fail-Fastabortで早期検出。
- `tiny_hotheap_v2_try_pop()`:
- `candidate->capacity == 0` や `candidate->used > candidate->capacity` の場合は即 `NULL` を返す(デバッグビルドでは 1 回だけログ)。
- Stats:
- C7-only ベンチ (`ws=64, iters=20k, PROFILE=C7_SAFE`) で:
- v2 OFF: 既存どおり `HEAP_STATS[7] fast≈11015 slow≈1`。
- v2 ON:
- `alloc_fast` が 1 回目の page refill 後に `route_hits` と同程度まで増えていくこと。
- `cold_refill_fail` が常に 0 付近であること。
- `alloc_fallback_v1` / `free_fallback_v1` が 0〜ごく少数に収まっていること。
備考
----
- Phase58 の目的は **「TinyColdIface を導入したうえで、v2 Hot Box と v1 TinyHeap の境界を 2 箇所 (refill/retire) に絞ること」** であり、
この段階では性能よりも安定性segv しないこと)と Box 境界の明確化を優先する。
- C7-only で v2 が v1 と同等レベルで安定したら、次フェーズで C6/C5 への拡張や perf チューニング(分岐削減・命令数削減)に進む。
---
## 9. Phase60/61: C7-only フェーズ完了と次のターゲット (C6 拡張) メモ
現状まとめC7 v2 フェーズの着地)
---------------------------------
- C7-only:
- v2 OFF (C7 SAFE v1) ≈ 42M ops/s / slow≈1。
- v2 ON (C7-only, classes=0x80) ≈ 50M ops/s / slow≈40〜50 → 空ページ保持ポリシー導入前の状態。
- 空ページ保持ポリシー導入 (`max_partial_pages` / `partial_count` 追加) 後も、C7-only ではページが実質 full のまま回るため partial/retire はほぼ発火せず、slow は主に refill 回数として現れる。
- Mixed 161024B:
- 短尺 (ws=256, iters=20k, PROFILE=C7_SAFE):
- v2 OFF: ≈43.3M ops/s, HEAP_STATS[7] fast=5691 slow=1。
- v2 ON: ≈44.6M ops/s約 +3%, HEAP_STATS[7] fast=5691 slow=1, fail/fallback=0。
- 長尺 (ws=400, iters=1M, PROFILE=C7_SAFE):
- v2 OFF: ≈41.6M ops/s, HEAP_STATS[7] fast≈283k slow=1。
- v2 ON: ≈42.4M ops/s約 +2%, HEAP_STATS[7] fast≈283k slow=1, fail/fallback=0。
- 境界:
- Cold IF (`TinyColdIface`) 経由の refill/retire は安定しており、`cold_refill_fail` / fallback_v1 は 0 に張り付き。
- C7 v2 の Hot パスは `tiny_hotheap_page_v2.freelist` のみで完結し、v1 TinyHeap の page/pop は参照しない構造になった。
結論C7 フェーズ)
-------------------
- C7 v2 Hot Box は:
- C7-only / Mixed / 短尺・長尺のいずれでも v1 C7 SAFE を上回るスループットを達成。
- slow_prepare は v2 OFF/ON ともに 1長尺またはワークロード由来の refill 回数程度に収まり、Cold IF の異常ではない。
- fail/fallback=0 で、v2→v1 フォールバックに頼らずに Hot Box 単体で完結できている。
- 運用上の位置づけ:
- 標準デフォルト: 引き続き `HAKMEM_TINY_HOTHEAP_V2=0`(どの環境でも即 v1 C7 SAFE に戻せるようにする)。
- bench/研究プロファイル: C7 クラスに限り `HAKMEM_TINY_HOTHEAP_V2=1` / `HAKMEM_TINY_HOTHEAP_CLASSES=0x80` を推奨設定とし、C7 v2 を本命候補として扱う。
次のターゲット候補 (C6/C5 拡張の入り口)
--------------------------------------
- 目的:
- TinyHotHeap v2 の設計ゴールどおり、C7-only から C6/C5 へ段階的に適用範囲を広げて、Mixed 161024B 全体の性能を押し上げる。
- Gate/Policy 側の前提:
- PolicySnapshot / Route LUT に `tiny_heap_version[class_idx]` または `HAKMEM_TINY_HOTHEAP_CLASSES` のマスクを持ち、
- C7: まず v2 を有効(研究/bench向け
- C6: 将来的に `classes |= 0x40` で C6 を v2 に昇格させる余地を残す。
- C5: 同様に `classes |= 0x20` で C5 を v2 に載せる最終フェーズ。
- C6 拡張時に検討すべきポイント(設計メモのみ、実装は別フェーズ):
- ワークロード分布: Mixed 161024B で C6 がどの程度トラフィックを持つか(既存 FRONT_CLASS stats を参考にする)。
- 以前の Tiny C6 v1 実験では Mixed 回帰があったため、C6 v2 では:
- Route/Gate で C6 の Hot path を C7 と同じ 1 LUT + 1 switch に揃える。
- Unified Cache / WarmPool / Superslab へのアクセス回数が増えないようにするpure Hot Box 化を徹底)。
- rollout 戦略:
1. C6-only bench プロファイルで C6 v2 を ON にし、C6-heavy なベンチで C6 v1 と A/B少なくとも回帰なし
2. Mixed 161024B で C7 v2 + C6 v2 構成と C7 v2 のみ構成を比較し、±5% 以内 or 微プラスであれば「C6 v2 を本命候補」とする。
3. いずれも満たせない場合は、C6 v2 を C7 v2 と同様に研究箱ENV で個別に OFF 可能)として維持し、本線は C7 v2 + C6 v1 のままにする。
メモ:
- 本ガイドは C7 フェーズまでの実装指針とログを含んでおり、C6/C5 拡張は「同じ TinyHotHeapBox v2 の枠内で class を増やす」作業として扱う。
- C6/C5 拡張の具体的な API 変更や stats 追加は、今後の Phase (例: Phase62 以降) で別途「C6 v2 指示書」として追記する想定。***