- Redefine TinyHotHeap v2 as per-thread Hot Box with clear boundaries - Add comprehensive OS statistics tracking for SS allocations - Implement route-based free handling for TinyHeap v2 - Add C6/C7 debugging and statistics improvements - Update documentation with implementation guidelines and analysis - Add new box headers for stats, routing, and front-end management
20 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 できる状態。
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 ポリシーの再修正に戻る。