423 lines
17 KiB
Markdown
423 lines
17 KiB
Markdown
|
|
# SmallObject Core v6 設計ドキュメント
|
|||
|
|
|
|||
|
|
## 目的
|
|||
|
|
|
|||
|
|
16〜2KiB 帯の small-object/mid を、**責務を厳密に分離した 4 層構造**で再設計し、
|
|||
|
|
Mixed 16–1024B を mimalloc の 5割(50〜60M ops/s)クラスに近づけるための「核」となる Core v6 の仕様を固定する。
|
|||
|
|
|
|||
|
|
v5 までは:
|
|||
|
|
- Segment/O(1) page_meta までは到達済みだが、
|
|||
|
|
- ヘッダ書き・page->used 管理・segment 判定などの責務が HotPath に残り続け、
|
|||
|
|
- C6-only でも v1/pool 比 -20% 前後から抜け出せなかった。
|
|||
|
|
|
|||
|
|
v6 では:
|
|||
|
|
- C7 ULTRA で成功している「TLS freelist + segment + mask free」パターンを L0 に、
|
|||
|
|
- small-object の本体は **ヘッダレス/side-meta 前提の Core v6 (L1)** として再定義し、
|
|||
|
|
- 安全性・学習・route の責務を Cold/Policy 側に徹底的に落とす。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 層構造(固定)
|
|||
|
|
|
|||
|
|
v6 では、small-object/mid を次の 4 層に固定する。
|
|||
|
|
|
|||
|
|
1. **L0: ULTRA lane**
|
|||
|
|
- C7・ごく少数の超ホットクラス専用。
|
|||
|
|
- TLS freelist + small ULTRA segment(2MiB / 64KiB page)+ mask 判定のみを HotPath とする。
|
|||
|
|
- ヘッダレス or side-meta 前提。header 書き・学習はすべて slow/refill 側。
|
|||
|
|
|
|||
|
|
2. **L1: SmallObject Core v6(新 HotBox)**
|
|||
|
|
- 16〜2KiB の大半を扱う per-thread heap。
|
|||
|
|
- 責務:
|
|||
|
|
- size→class 決定後の alloc/free(same-thread)のみ。
|
|||
|
|
- ptr→page→page_meta→freelist pop/push(ただし page_meta 参照は slow/refill で極力まとめる)。
|
|||
|
|
- ヘッダレス(block 先頭は freelist 用 next のみ)。class/region 情報は page_meta 側に持つ。
|
|||
|
|
|
|||
|
|
3. **L2: Segment / Remote / ColdIface**
|
|||
|
|
- Segment v6: 2MiB Segment / 64KiB Page + `page_meta[]`。
|
|||
|
|
- RemoteBox: cross-thread free キュー。
|
|||
|
|
- SmallColdIface_v6: HotBox からの唯一の橋渡し:
|
|||
|
|
- `refill_page(class_idx)`
|
|||
|
|
- `retire_page(page)`
|
|||
|
|
- `remote_push(page, ptr)`
|
|||
|
|
- `remote_drain()`
|
|||
|
|
- Superslab/OS/DSO guard/Budget は、この層の内部で完結させる。
|
|||
|
|
|
|||
|
|
4. **L3: Policy / Learning / Guard**
|
|||
|
|
- `SmallPolicySnapshot_v6`:
|
|||
|
|
- `route_kind[class]`(ULTRA / CORE / POOL / LEGACY)
|
|||
|
|
- `block_size[class]`
|
|||
|
|
- `max_tls_slots[class]` / `max_partial_pages[class]` など。
|
|||
|
|
- ENV と Stats を読み、snapshot を更新する箱。
|
|||
|
|
- L0/L1 は snapshot の値を読むだけ(HotPath 内で ENV や Stats を触らない)。
|
|||
|
|
|
|||
|
|
この 4 層は v6 の設計で固定とし、以降は「層内の微調整」はあっても層の責務は動かさない前提とする。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ヘッダレス / side-meta ポリシー
|
|||
|
|
|
|||
|
|
### L1/L0 のルール
|
|||
|
|
|
|||
|
|
L1/L0 の HotPath では:
|
|||
|
|
- **block 先頭は freelist 用 next ポインタ専用**とし、
|
|||
|
|
- Tiny header や region/class 情報を一切置かない(ヘッダレス)。
|
|||
|
|
|
|||
|
|
class_idx / region 情報が必要な場合は:
|
|||
|
|
- `SmallPageMetaV6` 側に `class_idx` や `region_tag` を持たせ、
|
|||
|
|
- free 時には `page = page_of(ptr)` → `page->class_idx` を読む。
|
|||
|
|
|
|||
|
|
### 外部との互換(既存 header の扱い)
|
|||
|
|
|
|||
|
|
既存 Tiny/mid/free は header ベースの検証を行っているので、
|
|||
|
|
v6 導入後は:
|
|||
|
|
- header が必要な経路は **L1/L0 の外側の「RegionIdBox」** で page 単位の情報に変換する:
|
|||
|
|
- map登録時: page ごとに region_id を registry に記録。
|
|||
|
|
- free 時: `page_of(ptr)`→`region_id` を見てどの allocator の所有物か判定。
|
|||
|
|
- L1/L0 は region/header の存在を知らず、「自分の page_meta かどうか」だけを ColdIface 経由で教えてもらう。
|
|||
|
|
|
|||
|
|
これにより:
|
|||
|
|
- HotPath から header 書き/読みを完全に排除しつつ、
|
|||
|
|
- 既存の header ベースの guard は RegionIdBox 側で段階的に移行・互換維持できる。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## SmallObject Core v6(L1)の型
|
|||
|
|
|
|||
|
|
### Segment/ページメタ
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
#define SMALL_SEGMENT_V6_SIZE (2 * 1024 * 1024) // 2MiB
|
|||
|
|
#define SMALL_PAGE_V6_SIZE (64 * 1024) // 64KiB
|
|||
|
|
#define SMALL_PAGES_PER_SEGMENT (SMALL_SEGMENT_V6_SIZE / SMALL_PAGE_V6_SIZE)
|
|||
|
|
|
|||
|
|
typedef struct SmallPageMetaV6 {
|
|||
|
|
void* free_list; // block先頭をnextとして使う
|
|||
|
|
uint16_t used; // 現在使用中スロット数
|
|||
|
|
uint16_t capacity; // ページ内スロット数
|
|||
|
|
uint8_t class_idx; // サイズクラス
|
|||
|
|
uint8_t flags; // FULL / PARTIAL / REMOTE_PENDING など
|
|||
|
|
uint16_t page_idx; // Segment 内 index
|
|||
|
|
void* segment; // SmallSegmentV6*
|
|||
|
|
} SmallPageMetaV6;
|
|||
|
|
|
|||
|
|
typedef struct SmallSegmentV6 {
|
|||
|
|
uintptr_t base; // Segment base address
|
|||
|
|
uint32_t num_pages;
|
|||
|
|
uint32_t owner_tid;
|
|||
|
|
uint32_t magic; // 例えば 0xC0REV6
|
|||
|
|
SmallPageMetaV6 page_meta[SMALL_PAGES_PER_SEGMENT];
|
|||
|
|
} SmallSegmentV6;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
ptr→page_meta の取得は mask+shift による O(1) で行う:
|
|||
|
|
```c
|
|||
|
|
static inline SmallPageMetaV6* small_page_meta_v6_of(void* ptr) {
|
|||
|
|
uintptr_t addr = (uintptr_t)ptr;
|
|||
|
|
uintptr_t seg_base = addr & ~(SMALL_SEGMENT_V6_SIZE - 1);
|
|||
|
|
SmallSegmentV6* seg = (SmallSegmentV6*)seg_base;
|
|||
|
|
if (unlikely(seg->magic != SMALL_SEGMENT_V6_MAGIC)) return NULL;
|
|||
|
|
size_t page_idx = (addr - seg_base) >> SMALL_PAGE_V6_SHIFT; // PAGE_SHIFT=16
|
|||
|
|
if (unlikely(page_idx >= seg->num_pages)) return NULL;
|
|||
|
|
return &seg->page_meta[page_idx];
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### per-class heap 状態
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
typedef struct SmallClassHeapV6 {
|
|||
|
|
SmallPageMetaV6* current; // よく使うページ
|
|||
|
|
SmallPageMetaV6* partial_head; // 空きありページの簡易リスト
|
|||
|
|
} SmallClassHeapV6;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### TLS heap context
|
|||
|
|
|
|||
|
|
ULTRA と CORE を併用することを想定し、クラス単位の TLS freelist を持つ:
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
#define SMALL_V6_TLS_CAP 32
|
|||
|
|
|
|||
|
|
typedef struct SmallHeapCtxV6 {
|
|||
|
|
SmallClassHeapV6 cls[NUM_SMALL_CLASSES_V6];
|
|||
|
|
|
|||
|
|
// TLS freelist per hot class (例: C6, C5, 将来必要なクラスだけ)
|
|||
|
|
void* tls_freelist_c6[SMALL_V6_TLS_CAP];
|
|||
|
|
uint8_t tls_count_c6;
|
|||
|
|
|
|||
|
|
void* tls_freelist_c5[SMALL_V6_TLS_CAP];
|
|||
|
|
uint8_t tls_count_c5;
|
|||
|
|
|
|||
|
|
// TLS ownership check 用(Hot segment は 1 つ)
|
|||
|
|
uintptr_t tls_seg_base; // Segment base address
|
|||
|
|
uintptr_t tls_seg_end; // base + SMALL_SEGMENT_V6_SIZE
|
|||
|
|
|
|||
|
|
// 将来: 他の hot class 用の TLS freelist を追加可能
|
|||
|
|
} SmallHeapCtxV6;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Core v6 HotPath のルール
|
|||
|
|
|
|||
|
|
### alloc(CORE route, C6/C5 の例)
|
|||
|
|
|
|||
|
|
前段(Front/Gate)は v3/v5 同様に size→class を LUT で決め、snapshot から route_kind を読む。
|
|||
|
|
CORE route の C6/C5 は SmallObject Core v6 に落とす。
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
void* small_alloc_fast_v6(size_t size, uint32_t class_idx, SmallHeapCtxV6* ctx,
|
|||
|
|
const SmallPolicySnapshotV6* snap) {
|
|||
|
|
small_route_kind_t route = snap->route_kind[class_idx];
|
|||
|
|
|
|||
|
|
if (route == SMALL_ROUTE_ULTRA) {
|
|||
|
|
return small_ultra_alloc_v6(size, class_idx, ctx, snap); // L0 lane
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (route != SMALL_ROUTE_CORE) {
|
|||
|
|
// pool v1 / legacy などにフォールバック
|
|||
|
|
return small_route_fallback_alloc(size, class_idx, snap);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 例: C6
|
|||
|
|
if (class_idx == C6_CLASS_IDX) {
|
|||
|
|
if (likely(ctx->tls_count_c6 > 0)) {
|
|||
|
|
return ctx->tls_freelist_c6[--ctx->tls_count_c6];
|
|||
|
|
}
|
|||
|
|
return small_core_refill_v6(ctx, class_idx, snap);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// C5 など他クラスも同様のTLS freelistパターンで処理
|
|||
|
|
...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### free(CORE route, same-thread, class_idx ヒント付き)
|
|||
|
|
|
|||
|
|
Core v6 では free 時に毎回 page_meta を読むのではなく、
|
|||
|
|
- 前段(header or size クラス判定)で算出済みの `class_idx` を引数として受け取り、
|
|||
|
|
- まずは **TLS segment 所有範囲チェック**だけで「自分の TLS に積めるか」を判定し、
|
|||
|
|
- TLS に積めなかった場合にのみ `small_page_meta_v6_of(ptr)` で page_meta を取得する。
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
static inline bool small_tls_owns_ptr_v6(const SmallHeapCtxV6* ctx, void* ptr) {
|
|||
|
|
uintptr_t addr = (uintptr_t)ptr;
|
|||
|
|
return addr >= ctx->tls_seg_base && addr < ctx->tls_seg_end;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void small_free_fast_v6(void* ptr, uint32_t class_idx,
|
|||
|
|
SmallHeapCtxV6* ctx,
|
|||
|
|
const SmallPolicySnapshotV6* snap) {
|
|||
|
|
small_route_kind_t route = snap->route_kind[class_idx];
|
|||
|
|
|
|||
|
|
if (route == SMALL_ROUTE_ULTRA) {
|
|||
|
|
small_ultra_free_v6(ptr, ctx, snap);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (route != SMALL_ROUTE_CORE) {
|
|||
|
|
small_route_fallback_free(ptr, snap);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Fast path: TLS segment 所有範囲内かつ TLS slot に空きがあれば、page_meta を見ずに TLS に積む
|
|||
|
|
if (likely(small_tls_owns_ptr_v6(ctx, ptr))) {
|
|||
|
|
if (class_idx == C6_CLASS_IDX && ctx->tls_count_c6 < SMALL_V6_TLS_CAP) {
|
|||
|
|
ctx->tls_freelist_c6[ctx->tls_count_c6++] = ptr;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (class_idx == C5_CLASS_IDX && ctx->tls_count_c5 < SMALL_V6_TLS_CAP) {
|
|||
|
|
ctx->tls_freelist_c5[ctx->tls_count_c5++] = ptr;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// TLS満杯 or TLS未対応クラス → slow pathへ
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Slow path: page_meta lookup + remote/retire 判定(頻度を下げる)
|
|||
|
|
SmallPageMetaV6* page = small_page_meta_v6_of(ptr);
|
|||
|
|
if (unlikely(page == NULL)) {
|
|||
|
|
small_route_fallback_free(ptr, snap); // v6管轄外 → legacy/poolへ
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// same-thread 判定は ColdIface/RemoteBox 側で page->owner_tid を見る
|
|||
|
|
if (unlikely(!small_page_owned_by_self(page))) {
|
|||
|
|
small_cold_v6_remote_push(page, ptr, small_self_tid());
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TLSでは受けられなかった分だけ page freelist に戻す
|
|||
|
|
void* head = page->free_list;
|
|||
|
|
*(void**)ptr = head;
|
|||
|
|
page->free_list = ptr;
|
|||
|
|
page->used--; // retire 判定・統計は slow側で扱う
|
|||
|
|
if (unlikely(page->used == 0)) {
|
|||
|
|
small_cold_v6_retire_page(page);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### refill / drain(L2 への委譲)
|
|||
|
|
|
|||
|
|
Core v6 の slow path では:
|
|||
|
|
- `small_core_refill_v6` が `small_cold_v6_refill_page(class_idx)` を叩き、返ってきた page からまとめてブロックを carve して TLS freelist に積む。
|
|||
|
|
- `small_cold_v6_retire_page` が used==0 の page を Segment pool に返す。
|
|||
|
|
- remote push/drain は RemoteBox 経由で行い、L1 は remote free の存在を意識しない。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 実装上の禁止事項(HotBox側の約束)
|
|||
|
|
|
|||
|
|
Core v6 HotBox(L1)は:
|
|||
|
|
- ヘッダを書かない/読まない。
|
|||
|
|
- Superslab/Tiny/Pool v1 の関数を直接呼ばない(必ず ColdIface v6 経由)。
|
|||
|
|
- Stats/Learning/ENV を直接参照しない(snapshot の値を読むだけ)。
|
|||
|
|
- mid_desc_lookup / hak_super_lookup / classify_ptr などの lookup 系関数を呼ばない。
|
|||
|
|
|
|||
|
|
これらはすべて L2/L3 の責務とし、v6 以降の最適化でもこの境界は維持する。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## L2→L3 Stats インターフェース
|
|||
|
|
|
|||
|
|
設計原則:
|
|||
|
|
- **L2→L3 には page lifetime のサマリだけを渡す**。
|
|||
|
|
- HotPath(alloc/free)から Stats を一切更新しない。
|
|||
|
|
|
|||
|
|
### Stats 構造体と通知
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
typedef struct SmallPageStatsV6 {
|
|||
|
|
uint8_t class_idx;
|
|||
|
|
uint32_t alloc_count; // この page からの総 alloc 数
|
|||
|
|
uint32_t free_count; // この page への総 free 数
|
|||
|
|
uint32_t remote_free_count; // cross-thread free の数
|
|||
|
|
uint32_t lifetime_ns; // carve → retire までの時間 (optional)
|
|||
|
|
} SmallPageStatsV6;
|
|||
|
|
|
|||
|
|
// L2 (ColdIface) が retire/refill 時に L3 (Policy) へ通知
|
|||
|
|
void small_policy_v6_on_page_retire(const SmallPageStatsV6* stats);
|
|||
|
|
void small_policy_v6_on_page_refill(uint8_t class_idx);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
通知タイミング:
|
|||
|
|
|
|||
|
|
| イベント | L2→L3 通知 | データ |
|
|||
|
|
|------------|------------------|-----------------------|
|
|||
|
|
| refill | on_page_refill | class_idx |
|
|||
|
|
| retire | on_page_retire | SmallPageStatsV6 全体 |
|
|||
|
|
| remote_drain | なし(L2 内部完結) | - |
|
|||
|
|
|
|||
|
|
L3 側ではクラス別に集計し、次回 snapshot の TLS cap や partial limit を更新する:
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
typedef struct SmallPolicyStateV6 {
|
|||
|
|
uint64_t total_allocs[NUM_SMALL_CLASSES_V6];
|
|||
|
|
uint64_t total_frees[NUM_SMALL_CLASSES_V6];
|
|||
|
|
uint64_t remote_frees[NUM_SMALL_CLASSES_V6];
|
|||
|
|
|
|||
|
|
uint32_t optimal_tls_cap[NUM_SMALL_CLASSES_V6];
|
|||
|
|
uint32_t optimal_partial_limit[NUM_SMALL_CLASSES_V6];
|
|||
|
|
} SmallPolicyStateV6;
|
|||
|
|
|
|||
|
|
void small_policy_v6_update_snapshot(SmallPolicySnapshotV6* snap,
|
|||
|
|
const SmallPolicyStateV6* state);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## レガシーとの橋渡し(RegionIdBox)
|
|||
|
|
|
|||
|
|
現状は header ベースの guard に依存しており、
|
|||
|
|
- free 時に header byte を読んで class_idx + magic を検証し、
|
|||
|
|
- どの allocator(Tiny/Pool/v3/v5)が所有者かを判定している。
|
|||
|
|
|
|||
|
|
v6 ではヘッダレス前提とするため、
|
|||
|
|
**page 単位で所有者を管理する RegionIdBox を導入し、段階的に header 依存を外す。**
|
|||
|
|
|
|||
|
|
```c
|
|||
|
|
typedef struct RegionIdBox RegionIdBox;
|
|||
|
|
|
|||
|
|
// page_base → region_id のマッピングを管理
|
|||
|
|
void region_id_box_register_page(void* page_base, uint32_t region_id);
|
|||
|
|
void region_id_box_unregister_page(void* page_base);
|
|||
|
|
uint32_t region_id_box_lookup(void* ptr);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
移行フェーズのイメージ:
|
|||
|
|
|
|||
|
|
- Phase 1 (v6-0/1):
|
|||
|
|
- v6 は header を書かないが、front は header を読んで class_idx を決める(v6 の外側の責務)。
|
|||
|
|
- v6 の page は RegionIdBox に登録しておき、fallback 判定に利用。
|
|||
|
|
- free 時: header→class_idx→route で v6 free へ入り、v6 内では header に触らない。
|
|||
|
|
- Phase 2 (v6-2+):
|
|||
|
|
- v6 alloc は完全ヘッダレス。
|
|||
|
|
- free 時: TLS hit(small_tls_owns_ptr_v6==true)の場合は header 読みを skip。
|
|||
|
|
- TLS miss 時だけ RegionIdBox で所有者を確認し、v6 か legacy/pool かを決める。
|
|||
|
|
- Phase 3(将来):
|
|||
|
|
- 全クラスが v6/新経路に乗った段階で header を完全廃止し、RegionIdBox が唯一の所有者判定手段になる。
|
|||
|
|
|
|||
|
|
互換性マトリクス(イメージ):
|
|||
|
|
|
|||
|
|
| ptr の出所 | free 判定 | 備考 |
|
|||
|
|
|---------------------|----------------------|-----------------|
|
|||
|
|
| v6 alloc (TLS hit) | TLS owns → v6 free | header 不使用 |
|
|||
|
|
| v6 alloc (TLS miss) | RegionIdBox → v6 free| header 不使用 |
|
|||
|
|
| legacy alloc | header → legacy free | 既存 guard 維持 |
|
|||
|
|
| pool v1 alloc | header → pool free | 既存 guard 維持 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## まとめ: v6 設計の固定事項
|
|||
|
|
|
|||
|
|
1. **class_idx ヒント**
|
|||
|
|
- class_idx の決定責務:
|
|||
|
|
- alloc: front の size→class LUT。
|
|||
|
|
- free: front の header→class 読み(v6 の外側)。
|
|||
|
|
- v6 への渡し方:
|
|||
|
|
- 関数引数で渡し、v6 側では header を一切触らない。
|
|||
|
|
|
|||
|
|
2. **TLS ownership check**
|
|||
|
|
- Hot segment は常に TLS 上 1 つ(`tls_seg_base`〜`tls_seg_end`)。
|
|||
|
|
- free の fast path では range check(2 CMP)のみで所有判定する。
|
|||
|
|
- multi-segment化する場合も、segment[0] のみ fast path、他は slow path として扱う。
|
|||
|
|
|
|||
|
|
3. **L2→L3 Stats**
|
|||
|
|
- retire/refill 時の page lifetime summary(SmallPageStatsV6)のみを渡す。
|
|||
|
|
- HotPath(alloc/free)では Stats を一切更新しない。
|
|||
|
|
|
|||
|
|
4. **RegionIdBox**
|
|||
|
|
- page 単位で所有者(v6 / legacy / pool)を管理。
|
|||
|
|
- 段階的に header ベース guard から RegionIdBox に移行し、最終的には header を廃止可能な設計にする。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## フェーズ案(v6)
|
|||
|
|
|
|||
|
|
1. **Phase v6-0: 設計ドキュメントと型・IF 追加(完全 OFF)**
|
|||
|
|
- 本ドキュメントを作成し、SmallPageMetaV6 / SmallClassHeapV6 / SmallHeapCtxV6 / SmallSegmentV6 / ColdIface_v6 の型とヘッダだけ追加。
|
|||
|
|
- ENV は `HAKMEM_SMALL_HEAP_V6_ENABLED=0` デフォルトで route からは一切呼ばれない。
|
|||
|
|
|
|||
|
|
2. **Phase v6-1: C6-only CORE v6 route stub**
|
|||
|
|
- C6 を route_snapshot で `SMALL_ROUTE_CORE_V6` に振れるようにしつつ、中身は v1/pool に即フォールバック(動作は変えない)。
|
|||
|
|
|
|||
|
|
3. **Phase v6-2: C6-only Core v6 実装(Segment + TLS freelist)**
|
|||
|
|
- C6 について ULTRA に似た TLS freelist + Segment ベースの Core v6 を実装。
|
|||
|
|
- C6-heavy で v1/pool と A/B、安定・回帰幅を確認。
|
|||
|
|
|
|||
|
|
4. **Phase v6-3: Mixed での段階的 CORE v6 昇格**
|
|||
|
|
- C6 → C5 → 他クラスと、hot class から CORE v6 に載せ、Mixed 16–1024B の perf を確認。
|
|||
|
|
- C7 ULTRA(L0)と CORE v6(L1)の共存チューニング。
|
|||
|
|
|
|||
|
|
以降の Phase は、この「層」と「責務」を変えずに micro-optimization を繰り返すフェーズとする。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 実装ステータス(2025-12-11)
|
|||
|
|
|
|||
|
|
- **v6-3**: C6-only で baseline 同等まで改善。
|
|||
|
|
- C6-heavy A/B: v6 OFF 27.1M → v6-3 ON **27.1M ops/s(±0%)** ✅
|
|||
|
|
- TLS ownership check + batch header write + TLS batch refill の薄型化完了。
|
|||
|
|
- **Mixed 安定化は v6-4 のスコープ**: v6 ON で hang 発生中、デバッグ中。
|