# SmallObjectHotBox v3 Implementation Guide 対象と前提 ---------- - 対象: Tiny (16〜1KiB) と mid/smallmid の一部を統合して扱う SmallObjectHotBox v3 の実装タスク。 - 前提: - 現状の v1 TinyHeap / C7 SAFE / pool v1 を「安定線」とし、v3 は bench/研究プロファイルから段階的に導入する。 - TinyHotHeap v2 / pool v2 は研究箱として凍結済み。v3 では設計のインスピレーションとして扱い、直接の継承は行わない。 0. ゴールと非ゴール ------------------- - ゴール: - SmallObjectHotBox v3 を per-thread Hot Box として実装し、C7-only → C6/C5 → mid/smallmid の順に対象クラスを広げられる骨格を作る。 - Hot Box 側は heap→page→block のみを扱い、Superslab/Segment/Tier/Guard/Remote との境界を - alloc 側: `so_alloc_refill_slow(...)` - free 側: `so_page_retire_slow(...)` の 2 箇所に集約する。 - A/B: PolicySnapshot + ENV (`HAKMEM_SMALL_HEAP_V3_ENABLED`, `HAKMEM_SMALL_HEAP_V3_CLASSES`) で v1/v3 を即切替可能にする。 - 非ゴール: - Superslab/Segment/Tier/Guard/Remote の設計変更(サイズや Tier ポリシーの再定義)は行わない。 - C0〜C4 や 2KiB 超〜large サイズ帯を v3 ですべて置き換えること(v3 初期フェーズでは 16〜1024B/2048B 付近に絞る)。 - 学習層 (ACE/ELO) の仕様変更。PolicySnapshot の更新だけを学習側が持ち、Hot パスは snapshot を読むだけにする。 1. 型の導入 (Hot Box) --------------------- ファイル案: - `core/box/smallobject_hotbox_v3_box.h` … 型と inline API - `core/smallobject_hotbox_v3.c` … slow path 実装(任意) 作業指示: 1. `so_page_t` / `so_class_t` / `so_ctx_t` を定義する(`SMALLOBJECT_HOTBOX_V3_DESIGN.md` に準拠)。 - `so_page_t` : freelist / used / capacity / class_idx / flags / block_size / base / slab_ref / next。 - `so_class_t`: current / partial / max_partial / partial_count / block_size。 - `so_ctx_t` : `so_class_t cls[SMALLOBJECT_NUM_CLASSES];`。 2. TLS getter `so_tls_get()` を実装: ```c so_ctx_t* so_tls_get(void) { static __thread so_ctx_t* s_ctx; so_ctx_t* ctx = s_ctx; if (!ctx) { ctx = calloc(1, sizeof(so_ctx_t)); if (!ctx) abort(); s_ctx = ctx; for (int i = 0; i < SMALLOBJECT_NUM_CLASSES; i++) { ctx->cls[i].block_size = smallobject_block_size_for_class(i); ctx->cls[i].max_partial = default_partial_for_class(i); // 例: 2 } } return ctx; } ``` 2. Cold IF (SmallObjectColdIface) の実装 --------------------------------------- ファイル案: - `core/box/smallobject_cold_iface_v1.h` 作業指示: 1. Cold IF struct を定義: ```c typedef struct SmallObjectColdIface { so_page_t* (*refill_page)(void* cold_ctx, uint32_t class_idx); void (*retire_page)(void* cold_ctx, uint32_t class_idx, so_page_t* page); } SmallObjectColdIface; ``` 2. v1 TinyHeap / pool v1 / Superslab の既存 API を呼ぶ v1 ラッパを追加: - `smallobject_cold_refill_page_v1(void* cold_ctx, uint32_t ci)`: - Tiny/Pool v1 側から SmallObject 用ページを 1 枚借りるヘルパ(class_idx→Superslab/Segment→ページ構造を構築)。 - `so_page_t` に `base/block_size/capacity/slab_ref` をセットし返す。 - `smallobject_cold_retire_page_v1(void* cold_ctx, uint32_t ci, so_page_t* page)`: - page->slab_ref/base を使って v1 側にページ返却。 3. `SmallObjectColdIface smallobject_cold_iface_v1(void)` を実装し、Hot Box 側はこの IF を通してしか Cold Box を触らないようにする。 3. Hot パス実装 (alloc/free) ---------------------------- 3-1. alloc_fast / alloc_refill_slow ----------------------------------- 1. `static inline void* so_alloc_fast(so_ctx_t* ctx, uint32_t ci);` - current / partial から freelist pop。失敗時は `NULL` を返す(slow に任せる)。 2. `void* so_alloc(uint32_t ci);` - `ctx = so_tls_get();` - fast で hit すればそのまま返す。 - miss のとき: - `SmallObjectColdIface cold = smallobject_cold_iface_v1();` - `so_alloc_refill_slow(ctx, ci, &cold)` を呼ぶ。 3. `so_alloc_refill_slow` の中で: - v1 Cold IF から `so_page_t*` を 1 枚借りる。 - `so_page_t` 内の freelist が未構築なら block_size/capacity/base から carve。 - `hc->current` にセットしてから `so_alloc_fast` を再呼び出し。 3-2. free_fast / page_retire_slow --------------------------------- 1. `static inline void so_free_fast(so_ctx_t* ctx, uint32_t ci, void* ptr);` - `so_page_t* p = so_page_of(ptr);`(O(1)page_of、ヘッダ+mask 前提)。 - freelist push, `--used`。 - `used==0` のとき: - `partial_count < max_partial` なら partial リストに温存。 - それ以外は `so_page_retire_slow()` に渡す。 2. `so_page_retire_slow(so_ctx_t* ctx, uint32_t ci, so_page_t* p, SmallObjectColdIface* cold);` - Hot のリストから unlink。 - `cold->retire_page(cold_ctx, ci, p)` で Cold Box に返却。 - `so_page_t` ノードは free or reuse。 4. Front/Gate/Route 統合 ------------------------ 作業指示: 1. Route LUT に SmallObjectHotBox v3 用の route を追加: - 例: `TINY_ROUTE_SMALL_HEAP_V3`。 2. Policy/ENV: - `HAKMEM_SMALL_HEAP_V3_ENABLED` / `HAKMEM_SMALL_HEAP_V3_CLASSES` を追加し、class_mask で v3 を有効化。 - 初期値は 0(全クラス v1 のまま)。 3. Front(malloc/free)で: ```c if (small_heap_v3_enabled_for_class(class_idx)) { void* p = so_alloc((uint32_t)class_idx); if (p) return p; // v3 alloc 失敗時は静かに v1 へ fallback(stats に記録) } // 既存 Tiny/pool/legacy 経路へ ``` - free も同様に、v3 route のみ `so_free` を呼び、それ以外は現行経路へ。 5. Stats / Fail-Fast / A/B -------------------------- 5-1. Stats --------- 1. `so_stats_class_t` を定義し、クラス別に: - `alloc_calls`, `alloc_fast`, `alloc_refill`, `alloc_fallback_v1` - `free_calls`, `free_fast`, `free_fallback_v1` を `_Atomic` で持つ。 2. ENV `HAKMEM_SMALL_HEAP_V3_STATS=1` で destructor から 1 行ダンプ。 5-2. Fail-Fast -------------- 1. 範囲外 ptr / misaligned / header_missing など page_of の前提が壊れた場合は、デバッグフェーズでは abort する。 2. 構造安定後は、Fail-Fast から「ログ+v1 fallback」に切り替えられるように ifdef/ENV を用意する。 5-3. A/B -------- 1. C7-only プロファイル: - v3 OFF: 現行 C7 SAFE v1(または C7 v2)を基準にする。 - v3 ON : C7 クラスだけ SmallObjectHotBox v3 に経路を切り替え、ops/s と stats を比較。 2. Mixed 16–1024B: - C7-only v3 と C7+C6 v3 の A/B を取り、±5% 以内 or プラスであれば次のクラスに広げる。 6. 段階的 rollout と rollback ------------------------------ 作業指示: 1. すべての v3 変更は ENV で OFF にできるようにする: - `HAKMEM_SMALL_HEAP_V3_ENABLED=0` で完全に v1/v2 へ戻る。 2. クラス単位で v3 を有効にする: - まず C7-only(bit7)→ C6/C5 → mid/smallmid の順で classes マスクを広げる。 3. どのフェーズでも「v3 を OFF にすれば元の挙動に戻る」ことを前提に、Fail-Fast と stats を優先的に実装する。 このガイドに従って実装を進めれば、SmallObjectHotBox v3 を Box Theory に沿って段階的に導入しつつ、常に v1/v2 への安全な戻り道を確保できます。実装の各ステップは小さく分け、必ずベンチと stats で A/B を取りながら前に進めてください。***