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

172 lines
7.6 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.

# 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(1page_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. Frontmalloc/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 へ fallbackstats に記録)
}
// 既存 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 161024B:
- 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-onlybit7→ C6/C5 → mid/smallmid の順で classes マスクを広げる。
3. どのフェーズでも「v3 を OFF にすれば元の挙動に戻る」ことを前提に、Fail-Fast と stats を優先的に実装する。
このガイドに従って実装を進めれば、SmallObjectHotBox v3 を Box Theory に沿って段階的に導入しつつ、常に v1/v2 への安全な戻り道を確保できます。実装の各ステップは小さく分け、必ずベンチと stats で A/B を取りながら前に進めてください。***