Files
hakmem/docs/analysis/SMALLOBJECT_V7_DESIGN.md
Moe Charm (CI) ea905b2ccb docs: HAKMEM v2 generation summary and Phase v7-4 completion
- Add HAKMEM_V2_GENERATION_SUMMARY.md: comprehensive overview of v2 generation
- Update CURRENT_TASK.md: 'v2 generation complete' section
- Update SMALLOBJECT_V7_DESIGN.md: Phase v7-4 completion notes + v7-5 candidates

v2 generation freeze: ULTRA (FROZEN) / MID_v3 (stable) / v7 (research, code freeze)
Next: HakORune / JoinIR priority, HAKMEM resumes at v7-5 (multi-class expansion)

Layer structure (L0-L3) established, Box Theory implementation patterns confirmed.
Design documents serve as maps for future v7 second chapter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-12 04:00:55 +09:00

463 lines
17 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.

## SmallObjectHeap v7 / HAKMEM v3 コア設計メモ2025-12-11
このドキュメントは、ULTRA + MID v3 + V6 世代の上に新しく載せる
**SmallObjectHeap v7= HAKMEM v3 small/mid コア)** の設計方針をまとめたものです。
当面は設計・型スケルトンのみで、挙動は一切変更しません。
---
## 1. 位置づけと層構造Box Theory
### 1-1. 既存世代のまとめ
- L0: ULTRA lanes現行
- C4C7 ULTRA。C7 は 2MiB Segment + 64KiB Page + TLS freelistC7 ULTRA Box
- Mixed / C7-only で十分な性能が出ており、**FROZEN完成世代** とみなす。
- L1: HotBox v2 世代
- Tiny front v3 + TinyHeap v1小クラス
- MID v3257768B の mid/smallmid を TLS heap で扱う)。
- V6 C6-only headerless coreRegionId + Segment + TLS laneの研究箱。
- L2: Segment / Superslab / Warm / Remote
- L3: Policy/Learner + Stats + ENVACE/ELO/CAP 等)
この世代では、各帯に特化した箱ULTRA / MID v3 / V6を積み上げることで
Mixed 161024B を ~30M → ~44M ops/s まで底上げしたが、
small〜mid を一体で見る「共通の SmallObject コア」は存在しない。
### 1-2. v7 世代の狙い
v7 は L1 に新しく追加する **SmallObjectHotBox_v7** として設計する:
```text
Front (size→class→route LUT)
|
+-- L0: ULTRA lanes (C4C7, FROZEN)
|
+-- L1: SmallObjectHotBox_v7 ← NEW small/mid コア
|
+-- L1': TinyHeap v1 / MID v3 / V6 (fallback/legacy)
|
+-- L2: SegmentBox_v7 / ColdIface_v7
|
+-- L3: PolicyBox_v7 / RegionIdBox / PageStatsBox
```
目的:
- small例: 16〜1KiB or 16〜2KiBと mid の一部を **1 個の thread-local heap + segment** で扱う土台を作る。
- ULTRA 世代C4C7は L0 としてそのまま残すC7 ULTRA は独立 box
- headerless/v6 の実験で得た「RegionId + Segment + TLS lane + PageStats」の物理層パターンをコア側に反映する。
---
## 2. 型設計SmallHeapCtx_v7 / SmallSegment_v7
v7 の基本構造は v6/V3 の経験を統合したものとする。
### 2-1. SmallPageMeta_v7
Hot path で頻繁に触るフィールドと Stats 用フィールドを分離する。
```c
// Hot line: alloc/free で触るフィールド
typedef struct SmallPageMeta_v7 {
// ---- hot fields (cache line 0 想定) ----
void *free_list; // LIFO freelist: block -> next
uint32_t used; // 現在の使用スロット数
uint32_t capacity; // この page にある block スロット数
uint16_t class_idx; // サイズクラス (C0..C?)
uint16_t flags; // HOT/PARTIAL/FULL/REMOTE_PENDING 等
uint16_t page_idx; // Segment 内 index (0..N-1)
uint16_t reserved0; // アラインメント用
struct SmallSegment_v7 *segment; // Segment への back pointer
// ---- cold fields (Stats/Policy, cache line 1〜) ----
uint64_t alloc_count; // 累積 alloc 数
uint64_t free_count; // 累積 free 数
uint64_t remote_free_count; // 累積 remote free 数
uint16_t live_current; // 現在の live
uint16_t peak_live; // lifetime 最大 live
uint16_t remote_burst_max; // 一度の drain で吸い上げた remote の最大
uint16_t reserved1;
uint32_t epoch_first_alloc; // coarse epoch (L3 用)
uint32_t epoch_last_free; // 同上
} SmallPageMeta_v7;
```
設計ポイント:
- Hot path (alloc/free) では `free_list / used / capacity / class_idx` だけを触る。
- Stats/Learner は L2 retire 時に cold fields を `SmallPageStatsV7` にまとめて L3 に渡す。
- `segment` を持たせて退役時の SegmentBox 更新を簡単にする(必要であれば将来削る)。
### 2-2. SmallClassHeap_v7 / SmallHeapCtx_v7
各クラスの現在/部分/満杯ページと、小さな TLS magazine を持つ。
```c
typedef struct SmallClassHeap_v7 {
SmallPageMeta_v7 *current; // いま alloc に使っている page
SmallPageMeta_v7 *partial_head; // まだ空きのあるページ
SmallPageMeta_v7 *full_head; // FULL 判定のページCold 側に寄せる用)
void *local_freelist; // オプション: mini-ULTRA (class ローカル TLS)
uint16_t local_freelist_count;
uint16_t local_freelist_cap;
uint16_t class_idx;
uint16_t flags; // class 側のポリシーフラグ (ULTRA禁止など)
} SmallClassHeap_v7;
#define HAK_SMALL_NUM_CLASSES_V7 /* 例: 16〜24 */
typedef struct SmallHeapCtx_v7 {
SmallClassHeap_v7 cls[HAK_SMALL_NUM_CLASSES_V7];
} SmallHeapCtx_v7;
```
設計ポイント:
- v7 第1版では `local_freelist` は無効 (`cap=0`) にしておき、必要なクラスだけ Learner で有効化してもよい。
- クラス数は最初は「small側16〜1KiB or 2KiBをカバーする程度」に抑え、
mid を扱う `MidHeapCtx_v7` は別箱とする(後述)。
### 2-3. SmallSegment_v7
ULTRA の 2MiB/64KiB パターンをベースに、small v7 用 SegmentBox を定義する。
```c
#define SMALL_SEGMENT_SIZE_V7 (2u * 1024u * 1024u) // 2MiB
#define SMALL_PAGE_SIZE_V7 (64u * 1024u) // 64KiB
#define SMALL_PAGES_PER_SEG_V7 (SMALL_SEGMENT_SIZE_V7 / SMALL_PAGE_SIZE_V7)
typedef struct SmallSegment_v7 {
uintptr_t base; // 実データ領域の先頭アドレス
uint32_t num_pages; // 実際に使うページ数
uint32_t owner_tid; // 所有スレッド id
uint32_t flags; // SEGMENT_IN_USE / RETIRED 等
uint32_t region_kind; // REGION_SMALL_V7 / REGION_ULTRA / REGION_POOL 等
uint32_t segment_idx; // RegionIdBox 上の index
uint32_t free_page_head; // free page stack head
uint32_t free_page_count;
SmallPageMeta_v7 page_meta[SMALL_PAGES_PER_SEG_V7];
} SmallSegment_v7;
```
設計ポイント:
- `ptr & ~(SEG_SIZE-1)` で Segment に直行し、
`(ptr - base) >> PAGE_SHIFT``page_idx` を求めて `page_meta[page_idx]` に行ける O(1) 構造。
- small/mid/pool で Segment geometry を変えたい場合も、API は共通で持てるSegmentBox_v7 small / mid 用の 2 種類も可)。
---
## 3. RegionIdBox / header / class 判定方針v7 世代)
### 3-1. header の扱い
v6 C6-only headerless 実験から:
- header 完全削除は「Region lookup コスト」で相殺されがちで、劇的な改善には繋がらないケースが多い。
- ただし RegionId + Segment + page_meta.class_idx のパターンは
ptr→segment→page_meta→class を O(1) にする物理層として非常に有用。
v7 では次の方針とする:
1. ヘッダは **薄く残す**Fail-Fastlegacy/pool bridgeデバッグ用
2. small/mid の fast path では、できるだけ header を触らない。
- C7 ULTRA / 一部 hot クラス(将来の C6 ULTRA lane など)は完全 headerless も許可。
- SmallHeapCtx_v7 の core は「carve/refill 時に 1 回だけ書く」程度に抑える。
3. free 時の class 判定は:
- front/gate の hintsize→class / header + RegionIdBox + page_meta.class_idx を併用。
- v7 small pathでは、最終的には `page_meta.class_idx` を真とし、hint は OBSERVE 検証用とする。
### 3-2. RegionIdBox API
small/mid/pool 共通の ptr 分類箱として RegionIdBox_v7 を定義する:
```c
typedef enum {
REGION_UNKNOWN = 0,
REGION_SMALL_V7,
REGION_ULTRA,
REGION_MID_V7,
REGION_POOL_V3,
REGION_LARGE,
} region_kind_t;
typedef struct RegionLookupResult_v7 {
region_kind_t kind;
union {
struct {
SmallSegment_v7 *segment;
uint16_t page_idx;
} small_v7;
struct {
void *segment; // C7 ULTRA / mid v7 / pool v3 等
} other;
} u;
} RegionLookupResult_v7;
static inline RegionLookupResult_v7
region_id_lookup_v7(void *ptr);
```
small v7 free pathfast path:
```c
RegionLookupResult_v7 lk = region_id_lookup_v7(ptr);
if (likely(lk.kind == REGION_SMALL_V7)) {
SmallPageMeta_v7* page =
&lk.u.small_v7.segment->page_meta[lk.u.small_v7.page_idx];
uint8_t class_idx = page->class_idx;
small_heap_free_fast_v7(ctx, page, class_idx, ptr);
} else {
// ULTRA / MID / POOL / LEGACY へ bridge
}
```
移行モード:
- Phase OBSERVE: header-based class と page_meta.class_idx を比較して log/assert。挙動はまだ v2 世代のまま。
- Phase FROZEN: small v7 管理ページでは header を見ず、RegionId + page_meta.class_idx だけで動かす。
---
## 4. mid/pool との関係SmallHeapCtx_v7 vs MidHeapCtx_v7
v7 世代では small と mid を同じ物理層RegionIdBox + SegmentBox + PageStatsBoxに乗せつつ、
HotBox は別箱に分けるのが現実的:
```text
RegionIdBox / SegmentBox_v7 / PageStatsBox
|
+--> SmallHeapCtx_v7 (small: 16〜1KiB or 2KiB)
|
+--> MidHeapCtx_v7 (mid: 2〜16KiB or 2〜32KiB)
|
+--> PoolCtx_v3/v7 (さらに大きい / 特殊用途)
```
方針:
- **共通化するもの**:
- RegionIdBoxptr→region_kind + segment/page_idx
- Segment geometry APIsmall 用と mid 用に派生しても良い)
- PageStats 基本構造class_idx / alloc/free/remote / live/peak など)
- **専用箱にするもの**:
- SmallHeapCtx_v7small 特有の TLS/prefetch/クラス配置)
- MidHeapCtx_v7mid 特有の page サイズ・クラス分割・remote ポリシー)
- PoolCtx_v3/v7巨大オブジェクト特殊用途
橋渡し:
- RegionIdBox で kind != REGION_SMALL_V7 を検出したときのみ、
mid/pool の bridge_box`small_mid_bridge_free()` 等)に渡す。
- small core / mid core / pool core は互いを直接呼ばず、「bridge 1 箇所」で繋ぐ。
---
## 5. フェーズ分割v7-0 / v7-1 / v7-2 の指針)
いきなり small/mid 全体を v7 にするのではなく、C6-only small 帯から段階的に導入する。
### Phase v7-0: 型とインフラだけ追加(挙動一切変更なし)
目的:
- struct と設計 doc だけ追加し、ビルドと Box 理論上の位置づけを固める。
タスク:
- `SmallPageMeta_v7` / `SmallClassHeap_v7` / `SmallHeapCtx_v7` / `SmallSegment_v7` struct をヘッダに追加。
- RegionIdBox に `REGION_SMALL_V7``RegionLookupResult_v7` を追加(実装はまだダミーで OK
- ENV:
- `HAKMEM_SMALL_HEAP_V7_ENABLED=0`
- `HAKMEM_SMALL_HEAP_V7_CLASSES=0x0`
- front/gate は v7 に一切 route しない。
### Phase v7-1: C6-only v7 stubroute だけ v7 に向ける)
目的:
- front/gate・ENV・RegionIdBox の配線が壊れていないか確認する。
タスク:
- `TINY_ROUTE_SMALL_HEAP_V7` を route kind に追加。
- プロファイル: C6-only v7 stub モード(`CLASSES=0x40` など)を追加。
- `small_heap_alloc_fast_v7_stub(size, ci)` / `small_heap_free_fast_v7_stub(ptr, ci)` を実装し、
中身は即座に v2 世代MID v3 / V6 / pool v1にフォールバックするだけにする。
- RegionIdBox は OBSERVE モードで `region_id_lookup_v7(ptr)` を呼んで統計取得のみ(挙動不変)。
### Phase v7-2: C6-only v7 本実装small帯だけ
目的:
- C6-only の alloc/free を SmallHeapCtx_v7 + SmallSegment_v7 で本当に回し、
C6-heavy / Mixed で v3/V6/v2 本線と比較する。
タスク:
- SegmentBox_v7 と ColdIface_v7 を実装し、C6 pages の refill/retire を Segment v7 経由にする。
- `small_heap_alloc_fast_v7(size, ci)` / `small_heap_free_fast_v7(ptr, ci)` を実装:
- alloc: current→partial→cold_refill の順で page/freelist を消費。
- free: RegionIdBox で small_v7 page を特定し、page_meta.free_list に push必要時 retire
- プロファイル:
- C6-only v7 ON他クラスは ULTRA + MID v3 + V6 のまま)。
- ベンチ:
- C6-heavy / Mixed で v7 vs MID v3 vs V6 vs v2 本線を測り、
C6-only v7 の価値を評価(十分なら次の v7 拡張フェーズへ)。
---
## 6. まとめ
- v2 世代ULTRA + MID v3 + V6 C6-onlyは、Box Theory に沿ってかなりやり切った世代とみなし、ここで一度締める。
- v3 世代SmallObjectHeap v7は、「small〜mid を 1 個の SmallHeapCtx + Segment + RegionIdBox で扱う」第2章として設計する。
- まずは C6-only small 帯から v7 を導入し、ULTRA/MID v3 を壊さない形で徐々に適用範囲を広げていく。
### Phase v7-3: C6 TLS Segment Fast Path + Page Metadata Cache
目的:
- Phase v7-2 で明らかになった RegionIdBox binary search のオーバーヘッド(-7% vs legacyを削減する。
- "ほとんどの" C6 free パスで RegionIdBox lookup を避ける設計に改善。
主な最適化:
1. **TLS segment fast hint**:
- SmallHeapCtx_v7 に `tls_seg_base / tls_seg_end / tls_seg` を追加。
- free 初期段階で `if (addr >= tls_seg_base && addr < tls_seg_end)` をチェックして、
ほとんどの C6 free は RegionIdBox を呼ばずに page_idx を計算できるように。
2. **same-page page_meta TLS cache**:
- SmallHeapCtx_v7 に `last_page_base / last_page_end / last_page_meta` を追加。
- 前回と同じページ内の free は page_meta 検索をスキップ1-2% 改善期待)。
3. **RegionIdBox は TLS 範囲外のみ**:
- RegionIdBox は「TLS segment が知らない alloc」POOL / LEGACY / ULTRA 由来)の分類専用に限定。
- C6-only v7 の hot path では RegionIdBox を通さない。
4. **C6-only 維持**:
- Phase v7-3 でも C6 のみに絞る。
- C5/C4 への拡張は、v7 の性能が legacy に追いついた後に検討。
期待結果:
- TLS fast path で RegionIdBox overhead 大部分回避 → -7% から ±0〜+α への改善を目指す。
- SegmentBox_v7 / ColdIface_v7 の API は不変(内部最適化のみ)。
---
## 7. Phase v7-4: Policy Box (L3 層の明確化)
### Policy Box の役割
SmallPolicyV7 Box を L3 に配置し、「どのクラスをどの層に送るか」を一元管理:
```c
typedef struct SmallPolicyV7 {
SmallRouteKind route_kind[8]; // C0-C7
} SmallPolicyV7;
const SmallPolicyV7* small_policy_v7_snapshot(void);
```
### フロントの責務
フロントは Policy Snapshot を読んで route を選ぶだけ:
```c
const SmallPolicyV7* policy = small_policy_v7_snapshot();
SmallRouteKind route = policy->route_kind[class_idx];
switch (route) {
case SMALL_ROUTE_ULTRA: // L0
case SMALL_ROUTE_V7: // L1
case SMALL_ROUTE_MID_V3: // L1'
case SMALL_ROUTE_LEGACY: // L1'
}
```
### ENV の一元化
ENV 変数は Policy init で一度だけ読む:
- `HAKMEM_TINY_C7_ULTRA_ENABLED`
- `HAKMEM_SMALL_HEAP_V7_ENABLED` + `HAKMEM_SMALL_HEAP_V7_CLASSES`
- `HAKMEM_MID_V3_ENABLED` + `HAKMEM_MID_V3_CLASSES`
優先順位: ULTRA > v7 > MID_v3 > LEGACY (固定)
将来的にはクラスごとの柔軟な優先順位設定や、Learner 連携による動的ルート選択も可能。
### 段階移行
Phase v7-4 では v7 関連のみ Policy box 経由に変更。
ULTRA/MID_v3/LEGACY は既存の `tiny_route_env_box.h` を併用(後で統合予定)。
---
## 8. v7 第2章への設計メモPhase v7-4 完了時点)
### 現状C6-only 研究箱)
- **性能**: 56.3M ops/s (Phase v7-3, -4.3% overhead)
- **設計完了**: SmallHeapCtx / Segment / ColdIface / RegionIdBox 統一
- **Policy統合**: 完了route 一元化)
### -4.3% Overhead の内訳(仮説)
| 要因 | 推定 | 対策 |
|------|------|------|
| Page metadata 間接参照 | ~2% | Multi-class で分摊 |
| Extra validation | ~1% | Branch優化 |
| RegionIdBox fallback | ~1% | TLS cache強化 |
### Multi-class 拡張時の検討項目
1. **Segment 設計**:
- Option A: Class ごとに独立 segment (SmallSegment_v7_C6, v7_C5, ...)
- Option B: 複数 class を 1 segment 内で共存
- Decision point: TLS hint の複数 segment 対応
2. **TLS Context 拡張**:
```c
typedef struct SmallHeapCtx_v7_multi {
SmallClassHeap_v7 cls[8];
// Multi-class TLS hints
struct {
uintptr_t seg_base;
uintptr_t seg_end;
SmallSegment_v7* seg;
} tls_seg[5]; // C3-C7
} SmallHeapCtx_v7_multi;
```
3. **Overhead 分摊の期待値**:
- C6-only: -4.3% (current)
- C5+C6: -2% (overhead 薄まる)
- C4+C5+C6: -1% (さらに薄まる)
### Learner 連携Phase v7-5 候補)
**概要**: SmallPageStatsV7 から実行時最適 route を学習
```c
// Policy Box update interface
void small_policy_v7_update_from_learner(
const SmallLearnerStats* stats,
SmallPolicyV7* policy_out
);
```
**学習要件**:
- Alloc/free count, peak_live, lifetime_ms
- v7 vs MID_v3 の速度比較
- Learner の信頼度 threshold
### HeaderLess 統一(将来検討)
v7-5 以降でも header を削除できるかの検証:
- v6 headerless: page->class_idx で header-free を実装済み
- v7 適用: free 時に page_meta から class_idx を取得
- Benefit: 1 byte 削減 per allocationmicro, 但し alloc density up
### 次世代開始チェックリスト
- [ ] HAKMEM_V2_GENERATION_SUMMARY.md が地図として機能
- [ ] v7-4 時点の設計メモ (本セクション) が読み返せる
- [ ] HakORune / JoinIR が一段落or 並行可能に)
- [ ] v7 research box は冷凍庫に保存完了