172 lines
7.6 KiB
Markdown
172 lines
7.6 KiB
Markdown
# 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 を取りながら前に進めてください。***
|