diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 463b3d31..d191c980 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -114,6 +114,18 @@ - Mixed 16–1024B: v4 ON で SEGV なし(小幅回帰許容) - **方針**: C6 v4 は研究箱として**安定化完了**。本線には載せない(既存 mid/pool v1 を使用)。 +4. **Phase v5-0(SmallObject v5 設計・型/IF スケルトン)** ✅ 完了 + - **内容**: v5 の型定義・インターフェース・ENV ゲートのみ追加(機能は完全 OFF) + - **ファイル**: + - `docs/analysis/SMALLOBJECT_V5_DESIGN.md` - v5 設計ドキュメント + - `core/box/smallobject_hotbox_v5_box.h` - HotBox v5 型 + - `core/box/smallsegment_v5_box.h` - Segment v5 型 + - `core/box/smallobject_cold_iface_v5.h` - ColdIface v5 IF + - `core/box/smallobject_v5_env_box.h` - ENV ゲート + - `core/smallobject_hotbox_v5.c` - 実装 stub(fallback) + - **挙動**: 完全不変(v5 route は呼ばれない、ENV デフォルト OFF) + - **目標**: v5-1 で C6-only stub → v5-2 で本実装 → v5-3 で Mixed に段階昇格 + --- ### 5. 健康診断ラン(必ず最初に叩く 2 本) diff --git a/core/box/smallobject_cold_iface_v5.h b/core/box/smallobject_cold_iface_v5.h new file mode 100644 index 00000000..f1ec4eca --- /dev/null +++ b/core/box/smallobject_cold_iface_v5.h @@ -0,0 +1,20 @@ +// smallobject_cold_iface_v5.h - SmallObject Cold Interface v5(Phase v5-0) +// +// ページ割当・返却・リモート操作(v5-0 では宣言のみ) + +#ifndef HAKMEM_SMALLOBJECT_COLD_IFACE_V5_H +#define HAKMEM_SMALLOBJECT_COLD_IFACE_V5_H + +#include +#include "smallobject_hotbox_v5_box.h" +#include "smallsegment_v5_box.h" + +// Cold path: ページ割当・返却 +SmallPageMetaV5* small_cold_v5_refill_page(SmallHeapCtxV5* ctx, uint32_t class_idx); +void small_cold_v5_retire_page(SmallHeapCtxV5* ctx, SmallPageMetaV5* page); + +// リモート操作(将来、per-thread TLS free の際に使用) +bool small_cold_v5_remote_push(SmallPageMetaV5* page, void* ptr, uint32_t tid); +void small_cold_v5_remote_drain(SmallHeapCtxV5* ctx); + +#endif // HAKMEM_SMALLOBJECT_COLD_IFACE_V5_H diff --git a/core/box/smallobject_hotbox_v5_box.h b/core/box/smallobject_hotbox_v5_box.h new file mode 100644 index 00000000..4715b202 --- /dev/null +++ b/core/box/smallobject_hotbox_v5_box.h @@ -0,0 +1,42 @@ +// smallobject_hotbox_v5_box.h - SmallObject HotBox v5 型定義(Phase v5-0) +// +// この段階では型とインターフェース定義のみ。挙動は変わらない。 + +#ifndef HAKMEM_SMALLOBJECT_HOTBOX_V5_BOX_H +#define HAKMEM_SMALLOBJECT_HOTBOX_V5_BOX_H + +#include + +#define NUM_SMALL_CLASSES_V5 8 // C0–C7 + +// SmallPageMetaV5: v5 ページメタデータ +typedef struct SmallPageMetaV5 { + void* free_list; // フリーリスト先頭 + uint16_t used; // 使用中ブロック数 + uint16_t capacity; // このページの総容量 + uint8_t class_idx; // size class index + uint8_t flags; // reserved + uint16_t page_idx; // segment 内でのページインデックス + void* segment; // SmallSegmentV5* への backpointer +} SmallPageMetaV5; + +// SmallClassHeapV5: サイズクラス毎のホットヒープ状態 +typedef struct SmallClassHeapV5 { + SmallPageMetaV5* current; // 現在のページ(alloc 中) + SmallPageMetaV5* partial_head; // partial ページリスト + SmallPageMetaV5* full_head; // full ページリスト +} SmallClassHeapV5; + +// SmallHeapCtxV5: per-thread ホットヒープコンテキスト +typedef struct SmallHeapCtxV5 { + SmallClassHeapV5 cls[NUM_SMALL_CLASSES_V5]; +} SmallHeapCtxV5; + +// API +SmallHeapCtxV5* small_heap_ctx_v5(void); + +// Fast path(将来実装) +void* small_alloc_fast_v5(size_t size, uint32_t class_idx); +void small_free_fast_v5(void* ptr, uint32_t class_idx); + +#endif // HAKMEM_SMALLOBJECT_HOTBOX_V5_BOX_H diff --git a/core/box/smallobject_v5_env_box.h b/core/box/smallobject_v5_env_box.h new file mode 100644 index 00000000..26c80622 --- /dev/null +++ b/core/box/smallobject_v5_env_box.h @@ -0,0 +1,56 @@ +// smallobject_v5_env_box.h - SmallObject v5 環境ゲート(Phase v5-0) +// +// ENV ベース: HAKMEM_SMALL_HEAP_V5_ENABLED, HAKMEM_SMALL_HEAP_V5_CLASSES + +#ifndef HAKMEM_SMALLOBJECT_V5_ENV_BOX_H +#define HAKMEM_SMALLOBJECT_V5_ENV_BOX_H + +#include +#include + +// small_heap_v5_enabled() - グローバル v5 enable check +static inline int small_heap_v5_enabled(void) { + static int g_enabled = -1; + if (g_enabled == -1) { + const char* e = getenv("HAKMEM_SMALL_HEAP_V5_ENABLED"); + g_enabled = (e && *e && *e != '0') ? 1 : 0; + } + return g_enabled; +} + +// small_heap_v5_class_mask() - v5 対象クラスのビットマスク +static inline uint32_t small_heap_v5_class_mask(void) { + static uint32_t g_mask = (uint32_t)-1; // sentinel + if (g_mask == (uint32_t)-1) { + const char* e = getenv("HAKMEM_SMALL_HEAP_V5_CLASSES"); + if (e && *e) { + g_mask = (uint32_t)strtoul(e, NULL, 0); + } else { + g_mask = 0x0; // default: OFF + } + } + return g_mask; +} + +// small_heap_v5_class_enabled() - 指定クラスが v5 有効か +static inline int small_heap_v5_class_enabled(uint32_t class_idx) { + if (class_idx >= 8) return 0; + if (!small_heap_v5_enabled()) return 0; + uint32_t mask = small_heap_v5_class_mask(); + return (mask & (1u << class_idx)) ? 1 : 0; +} + +// 便利関数 +static inline int small_heap_v5_c6_enabled(void) { + return small_heap_v5_class_enabled(6); +} + +static inline int small_heap_v5_c5_enabled(void) { + return small_heap_v5_class_enabled(5); +} + +static inline int small_heap_v5_c7_enabled(void) { + return small_heap_v5_class_enabled(7); +} + +#endif // HAKMEM_SMALLOBJECT_V5_ENV_BOX_H diff --git a/core/box/smallsegment_v5_box.h b/core/box/smallsegment_v5_box.h new file mode 100644 index 00000000..6cd46888 --- /dev/null +++ b/core/box/smallsegment_v5_box.h @@ -0,0 +1,31 @@ +// smallsegment_v5_box.h - SmallSegment v5(Phase v5-0) +// +// 2MiB Segment / 64KiB Page ベースの O(1) page_meta lookup + +#ifndef HAKMEM_SMALLSEGMENT_V5_BOX_H +#define HAKMEM_SMALLSEGMENT_V5_BOX_H + +#include +#include "smallobject_hotbox_v5_box.h" + +#define SMALL_SEGMENT_V5_SIZE (2 * 1024 * 1024) // 2 MiB +#define SMALL_SEGMENT_V5_PAGE_SIZE (64 * 1024) // 64 KiB +#define SMALL_SEGMENT_V5_NUM_PAGES (SMALL_SEGMENT_V5_SIZE / SMALL_SEGMENT_V5_PAGE_SIZE) // 32 +#define SMALL_SEGMENT_V5_MAGIC 0xDEADBEEF +#define SMALL_SEGMENT_V5_PAGE_SHIFT 16 // log2(64KiB) + +// SmallSegmentV5: セグメント構造体 +typedef struct SmallSegmentV5 { + uintptr_t base; // セグメント先頭アドレス + uint32_t num_pages; // ページ数(通常は 32) + uint32_t owner_tid; // オーナースレッド ID + uint32_t magic; // 0xDEADBEEF for validation + SmallPageMetaV5 page_meta[SMALL_SEGMENT_V5_NUM_PAGES]; // page metadata array +} SmallSegmentV5; + +// API(v5-0 では宣言のみ、実装は v5-2) +SmallSegmentV5* small_segment_v5_acquire(void); +void small_segment_v5_release(SmallSegmentV5* seg); +SmallPageMetaV5* small_segment_v5_page_meta_of(void* ptr); + +#endif // HAKMEM_SMALLSEGMENT_V5_BOX_H diff --git a/core/smallobject_hotbox_v5.c b/core/smallobject_hotbox_v5.c new file mode 100644 index 00000000..e053987d --- /dev/null +++ b/core/smallobject_hotbox_v5.c @@ -0,0 +1,74 @@ +// smallobject_hotbox_v5.c - SmallObject HotBox v5 実装 stub(Phase v5-0) +// +// この段階では完全な fallback stub。v5 route は呼ばれない(ENV default OFF)。 + +#include +#include +#include "box/smallsegment_v5_box.h" +#include "box/smallobject_hotbox_v5_box.h" +#include "box/smallobject_cold_iface_v5.h" +#include "box/smallobject_v5_env_box.h" + +// TLS context +static __thread SmallHeapCtxV5 g_small_heap_ctx_v5; + +SmallHeapCtxV5* small_heap_ctx_v5(void) { + return &g_small_heap_ctx_v5; +} + +// Phase v5-0: Fast alloc(stub) +void* small_alloc_fast_v5(size_t size, uint32_t class_idx) { + (void)size; + (void)class_idx; + // v5-0: completely disabled, fallback to existing path + // actual implementation in v5-2 + return NULL; +} + +// Phase v5-0: Fast free(stub) +void small_free_fast_v5(void* ptr, uint32_t class_idx) { + (void)ptr; + (void)class_idx; + // v5-0: no-op + // actual implementation in v5-2 +} + +// Segment stub(v5-2 で実装) +SmallSegmentV5* small_segment_v5_acquire(void) { + return NULL; // stub +} + +void small_segment_v5_release(SmallSegmentV5* seg) { + (void)seg; + // stub +} + +SmallPageMetaV5* small_segment_v5_page_meta_of(void* ptr) { + (void)ptr; + return NULL; // stub +} + +// ColdIface stub(v5-2 で実装) +SmallPageMetaV5* small_cold_v5_refill_page(SmallHeapCtxV5* ctx, uint32_t class_idx) { + (void)ctx; + (void)class_idx; + return NULL; // stub +} + +void small_cold_v5_retire_page(SmallHeapCtxV5* ctx, SmallPageMetaV5* page) { + (void)ctx; + (void)page; + // stub +} + +bool small_cold_v5_remote_push(SmallPageMetaV5* page, void* ptr, uint32_t tid) { + (void)page; + (void)ptr; + (void)tid; + return false; // stub +} + +void small_cold_v5_remote_drain(SmallHeapCtxV5* ctx) { + (void)ctx; + // stub +} diff --git a/docs/analysis/SMALLOBJECT_V5_DESIGN.md b/docs/analysis/SMALLOBJECT_V5_DESIGN.md new file mode 100644 index 00000000..75750d6d --- /dev/null +++ b/docs/analysis/SMALLOBJECT_V5_DESIGN.md @@ -0,0 +1,129 @@ +# SmallObject HotBox v5 設計ドキュメント + +## 目的 + +16〜2KiB 帯の small-object/mid を **SmallObjectHotBox_v5** に集約し、Mixed 16–1024B を **mimalloc の 5割(50〜60M ops/s)** クラスに寄せる。 + +v4 は「TinyHeap 依存 + 重い page 管理」の反省対象として archive。C5/C6 は v4 ではなく **v5 に乗せる**。 + +--- + +## 箱構造 + +### Hot Path: SmallObjectHotBox_v5 +- **型**: `SmallHeapCtxV5` (per-thread) +- **状態**: `SmallClassHeapV5 cls[NUM_SMALL_CLASSES_V5]` (current/partial/full リスト) +- **特徴**: ptr→page→class を O(1) で判定、mid_desc_lookup / hak_super_lookup / classify_ptr を呼ばない + +### Cold Path: SmallColdIface_v5 +- `small_cold_v5_refill_page()`: ページ割当 +- `small_cold_v5_retire_page()`: ページ返却 +- `small_cold_v5_remote_push()`: リモート free +- `small_cold_v5_remote_drain()`: バッチ回収 + +### Segment: SmallSegmentBox_v5 +- **構成**: 2MiB Segment / 64KiB Page +- **ページメタ**: `SmallPageMetaV5 page_meta[]` (class_idx/used/capacity/freelist を直接保持) +- **O(1) lookup**: Segment mask + page_idx で `page_meta` に直接アクセス +- **API**: + - `small_segment_v5_acquire()`: セグメント確保 + - `small_segment_v5_page_meta_of()`: ptr → page_meta + +### Policy/Learning: SmallPolicySnapshot_v5 +- `route_kind` (TINY, SMALL_HEAP_V5, POOL_V1 など) +- `block_size` (各サイズクラスの実サイズ) +- `max_partial_pages` (partial リスト上限) +- Route/Policy 変更時に snapshot を再計算(lazy initialization) + +--- + +## 設計の芯 + +### 1. ptr→page→class の O(1) 判定 +```c +// SmallSegment mask計算 +SmallPageMetaV5* meta = small_segment_v5_page_meta_of(ptr); +// ↓ Segment base + (ptr - base) / PAGE_SIZE で直接インデックス計算 +``` +- TinyHeap lookup を呼ばない +- mid_desc_lookup / hak_super_lookup を呼ばない +- SmallSegment が所有するページなら即座に class_idx 取得可能 + +### 2. Hot/Cold の分離 +- **Hot**: current/partial リスト + TLS freelist (将来) +- **Cold**: SmallSegment ページプール + remote push/drain +- C7 ULTRA は L0 lane として維持、v5 は影響されず動く + +### 3. C7 ULTRA との共存 +- C7 ULTRA は「超ホットクラス専用 lane」として後段フェーズで検討 +- v5 は C7 ULTRA に依存しない(ULTRA が OFF でも v5 は動く) +- Segment/Policy は共有可能(内部実装は後で詰める) + +### 4. クラス対象 +- **初期**: C6(257–768B)→ C5(129–256B) +- **将来**: C4(65–128B)以下 +- C7(1024B)は ULTRA lane で十分だが、必要に応じて v5 也の optimize lane も検討 + +--- + +## フェーズ案 + +### Phase v5-0: 型・IF・ENV のみ(完全 OFF) +- `SmallObjectHotBox_v5_box.h`: 型定義 +- `SmallSegmentBox_v5.h`: Segment 構造定義 +- `SmallColdIface_v5.h`: Cold function 宣言(stub) +- `SmallObjectV5_env_box.h`: ENV ゲート(HAKMEM_SMALL_HEAP_V5_ENABLED=0 デフォルト) +- `smallobject_hotbox_v5.c`: HotBox 実装 stub(fallback) +- **挙動**: 完全不変、v5 route は呼ばれない + +### Phase v5-1: C6-only v5 route stub(front 経路だけ通す) +- tiny_route に `TINY_ROUTE_SMALL_HEAP_V5` 追加 +- ENV で `HAKMEM_SMALL_HEAP_V5_ENABLED=1 HAKMEM_SMALL_HEAP_V5_CLASSES=0x40` で C6 を v5 route に +- 中身は v1/pool fallback → v5-0 段階での A/B(route 経由は OK か確認) + +### Phase v5-2: C6-only v5 本実装(Segment + Page + TLS freelist) +- SmallSegment v5 の割当・ページ carve 実装 +- SmallHeapCtx v5 の alloc/free 実装 +- C6-heavy ベンチで v1 と A/B +- 目標: -10% 以下の回帰で安定 + +### Phase v5-3: Mixed での段階的 v5 昇格 +- hot class(C6 → C5 → C4)から順次 v5 に載せる +- Mixed 16–1024B で 50–60M ops/s を目指す +- C7 ULTRA と v5 の共存 tuning + +--- + +## 実装上の注意 + +1. **v4 との区別**: すべてのシンボルに `*_v5` suffix をつける → binary に両方いても競合しない +2. **fallback**: v5 enabled だが route に乗らない class は既存 v1/pool に自動 fallback +3. **route snapshot**: tiny_route_snapshot_init() で policy を計算 (per-thread, lazy) +4. **segment pool**: SmallSegment v5 は thread-local or global pool から取得(詳細は v5-2 で) + +--- + +## ターゲット性能 + +| Workload | v4/v3 | v5 目標 | vs mimalloc | +|----------|-------|--------|------------| +| C6-only (257–768B) | ~43M (v4) / ~47M (v1) | ~45–48M | − | +| C5-heavy (129–256B) | ~49M (v1) | ~48–50M | − | +| Mixed 16–1024B | ~44–45M | ~50–60M | ~50% | + +--- + +## 依存関係 + +- `SmallSegmentBox_v5`: SmallPageMetaV5 を直接管理 +- `SmallColdIface_v5`: SmallSegmentBox_v5 に refill/retire 依頼 +- `SmallObjectHotBox_v5`: SmallColdIface_v5 を呼ぶ +- tiny_route: SmallObjectHotBox_v5 へ C6/C5/... route +- policy/env: SmallObjectV5_env_box で class mask 管理 + +--- + +## アーカイブ参照 + +- `SmallObjectHotBox_v4`: TinyHeap 依存がある、page 管理が重い → v5 の反省対象 +- `Phase v4-mid-SEGV`: C6 v4 の SEGV 修正で SmallSegment 独立化済み → v5 で応用 diff --git a/perf.data.c6_mixed_v4 b/perf.data.c6_mixed_v4 new file mode 100644 index 00000000..5dbc6fdc Binary files /dev/null and b/perf.data.c6_mixed_v4 differ diff --git a/perf.data.c6_mixed_v4_long b/perf.data.c6_mixed_v4_long new file mode 100644 index 00000000..06857487 Binary files /dev/null and b/perf.data.c6_mixed_v4_long differ diff --git a/perf.data.c6_only_v4 b/perf.data.c6_only_v4 new file mode 100644 index 00000000..cc958b5f Binary files /dev/null and b/perf.data.c6_only_v4 differ diff --git a/perf.data.c6_v4 b/perf.data.c6_v4 new file mode 100644 index 00000000..72da572c Binary files /dev/null and b/perf.data.c6_v4 differ diff --git a/perf.data.c6_v4.old b/perf.data.c6_v4.old new file mode 100644 index 00000000..b32d5087 Binary files /dev/null and b/perf.data.c6_v4.old differ diff --git a/perf.data.c6_v4_mixed b/perf.data.c6_v4_mixed new file mode 100644 index 00000000..1ec33eec Binary files /dev/null and b/perf.data.c6_v4_mixed differ diff --git a/perf.data.c6_v4_mixed.old b/perf.data.c6_v4_mixed.old new file mode 100644 index 00000000..6c56ffac Binary files /dev/null and b/perf.data.c6_v4_mixed.old differ