34 KiB
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 16–1024B の長尺プロファイル(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 の見直しが次課題。
- C7-only v2 ON で slow_prepare は
- 運用: 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 箇所)。
- alloc 側:
- 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.htiny_hotheap_page_v2… 概念上のTinyPageMetatiny_hotheap_class_v2… 概念上のTinyClassHeaptiny_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_v2current_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_v2cls[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)を lazilymalloc/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];- 優先順位:
hc->current_pageがあり、そのfreelistが非 NULL → 1 block pop してused++。hc->partial_pagesリストがあれば 1 枚取り出し、current_pageに昇格させてから pop。- どちらも空なら
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_slow(v1 TinyHeap / Superslab からのページ供給)
目的: Hot Box から見て 唯一の「ページ供給」入口 を 1 箇所に集約する。
作業指示:
- 関数案(実装ファイルは
core/hakmem_tiny.cか、専用のcore/box/tiny_hotheap_v2_cold_box.hでもよい):
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_pageorpartial_pagesに追加。 - freelist の初期化は Hot Box 側で実施 し、以降の pop/push は v2 が握る(v1 に再委譲しない)。
Step 3-2: page_retire_slow(全 free になったページの返却)
目的: ページが empty になった瞬間だけ Cold Box に touch する。
作業指示:
- 関数案:
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 する。
- page を
- 将来フェーズ:
- Warm Pool / Superslab への返却ロジックを v2 専用に寄せることで、
C 案(Segment+Page+Block)への移行パスとして利用する。
- Warm Pool / Superslab への返却ロジックを v2 専用に寄せることで、
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を設定する。
- bit7 が立っていれば
- これにより 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 経路にすぐ落とす。
- C7 ptr かつ Route=HOTHEAP_V2 かつ owner==self の場合のみ
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 ...
- v1 基準:
- Mixed 16–1024B:
- 当面は 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)
- v2 OFF: 39.64M ops/s,
- Mixed 16–1024B (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 OFF: 38.78M ops/s,
結論:
- 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 に移植する。
- C7-only で
- 非ゴール:
- 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++
- entry ごとに
tiny_hotheap_v2_free_fast内:- free で page が current になる/保持される場合
free_made_current++
- free で page が 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の振る舞いを以下のように揃える:- C7 用 lease API(
tiny_heap_c7_lease_page_for_v2()など)から 1 枚 page を取得。 tiny_hotheap_page_v2へ:base / capacity / meta / ss / slab_idx / strideをコピー。- freelist を page 内 carving で初期化(pop は v2 が握る)。
tiny_hotheap_class_v2* hc = &ctx->cls[7];に対して:hc->current_pageが NULL なら 必ずここで current_page にセット。- 既に current がある場合は
hc->partial_pagesに push。
- C7 用 lease API(
- 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.mddocs/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に反映する。
- alloc 時:
- 差分:
- 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 16–1024B (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()で初期化。
- v2 の
- 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: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は即NULLor fallback(C7-only 実験箱のまま)。v2ctx == NULL/hc == NULL/hc->stride == 0などは Fail-Fast(abort)で早期検出。
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〜ごく少数に収まっていること。
- v2 OFF: 既存どおり
- C7-only ベンチ (
備考
- 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 16–1024B:
- 短尺 (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。
- 短尺 (ws=256, iters=20k, PROFILE=C7_SAFE):
- 境界:
- Cold IF (
TinyColdIface) 経由の refill/retire は安定しており、cold_refill_fail/ fallback_v1 は 0 に張り付き。 - C7 v2 の Hot パスは
tiny_hotheap_page_v2.freelistのみで完結し、v1 TinyHeap の page/pop は参照しない構造になった。
- Cold IF (
結論(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 16–1024B 全体の性能を押し上げる。
- 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 に載せる最終フェーズ。
- PolicySnapshot / Route LUT に
- C6 拡張時に検討すべきポイント(設計メモのみ、実装は別フェーズ):
- ワークロード分布: Mixed 16–1024B で 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 戦略:
- C6-only bench プロファイルで C6 v2 を ON にし、C6-heavy なベンチで C6 v1 と A/B(少なくとも回帰なし)。
- Mixed 16–1024B で C7 v2 + C6 v2 構成と C7 v2 のみ構成を比較し、±5% 以内 or 微プラスであれば「C6 v2 を本命候補」とする。
- いずれも満たせない場合は、C6 v2 を C7 v2 と同様に研究箱(ENV で個別に OFF 可能)として維持し、本線は C7 v2 + C6 v1 のままにする。
メモ:
- 本ガイドは C7 フェーズまでの実装指針とログを含んでおり、C6/C5 拡張は「同じ TinyHotHeapBox v2 の枠内で class を増やす」作業として扱う。
- C6/C5 拡張の具体的な API 変更や stats 追加は、今後の Phase (例: Phase62 以降) で別途「C6 v2 指示書」として追記する想定。***