From dedfea27d5a280688a1870b1ff9ea5b86741f80c Mon Sep 17 00:00:00 2001 From: "Moe Charm (CI)" Date: Thu, 11 Dec 2025 03:19:18 +0900 Subject: [PATCH] =?UTF-8?q?Phase=20v5-0=20refactor:=20ENV=E7=B5=B1?= =?UTF-8?q?=E4=B8=80=E3=83=BB=E3=83=9E=E3=82=AF=E3=83=AD=E5=8C=96=E3=83=BB?= =?UTF-8?q?=E6=A7=8B=E9=80=A0=E4=BD=93=E6=9C=80=E9=81=A9=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ENV initialization を sentinel パターンで統一 - ENV_UNINIT/ENABLED/DISABLED 定数追加 - __builtin_expect で初期化チェックを最適化 - small_heap_v5_enabled/class_mask を統一パターンに変更 - ポインタマクロ化(O(1) segment/page 計算) - SMALL_SEGMENT_V5_BASE_FROM_PTR: ptr から segment base を mask で計算 - SMALL_SEGMENT_V5_PAGE_IDX: segment 内の page_idx を shift で計算 - SMALL_SEGMENT_V5_PAGE_META: page_meta への O(1) access(bounds check付き) - SMALL_SEGMENT_V5_VALIDATE_MAGIC: magic 検証 - SMALL_SEGMENT_V5_VALIDATE_PTR: Fail-Fast validation pipeline - SmallClassHeapV5 に partial_count 追加 - partial ページリストのカウンタを追加(refill/retire 最適化用) - SmallPageMetaV5 の field 再配置(L1 cache 最適化) - hot fields (free_list, used, capacity) を先頭に集約 - metadata (class_idx, flags, page_idx, segment) を後方配置 - total 24B、offset コメント追加 - route priority ENV 追加 - HAKMEM_ROUTE_PRIORITY={v4|v5|auto}(default: v4) - enum small_route_priority 定義 - small_route_priority() 関数追加 - segment_size override ENV 追加 - HAKMEM_SMALL_HEAP_V5_SEGMENT_SIZE(default: 2MiB) - power of 2 & >= 64KiB validation 挙動: 完全不変(v5 route は呼ばれない、ENV default OFF) テスト: Mixed 16–1024B で 43.0–43.8M ops/s(変化なし)、SEGV/assert なし 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 --- CURRENT_TASK.md | 19 ++++---- core/box/smallobject_hotbox_v5_box.h | 21 ++++---- core/box/smallobject_v5_env_box.h | 71 ++++++++++++++++++++++++---- core/box/smallsegment_v5_box.h | 42 ++++++++++++++++ 4 files changed, 128 insertions(+), 25 deletions(-) diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index d191c980..e7ac82c8 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -114,16 +114,17 @@ - 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) +4. **Phase v5-0(SmallObject v5 refactor: ENV統一・マクロ化・構造体最適化)** ✅ 完了 + - **内容**: v5 基盤の改善・最適化(挙動は完全不変) + - **改善項目**: + - ENV initialization を sentinel パターンで統一(ENV_UNINIT/ENABLED/DISABLED + `__builtin_expect`) + - ポインタマクロ化: `BASE_FROM_PTR`, `PAGE_IDX`, `PAGE_META`, `VALIDATE_MAGIC`, `VALIDATE_PTR` + - SmallClassHeapV5 に `partial_count` 追加 + - SmallPageMetaV5 の field 再配置(hot fields 先頭集約 → L1 cache 最適化, 24B) + - route priority ENV 追加: `HAKMEM_ROUTE_PRIORITY={v4|v5|auto}` + - segment_size override ENV 追加: `HAKMEM_SMALL_HEAP_V5_SEGMENT_SIZE` - **挙動**: 完全不変(v5 route は呼ばれない、ENV デフォルト OFF) + - **テスト**: Mixed 16–1024B で 43.0–43.8M ops/s(変化なし)、SEGV/assert なし - **目標**: v5-1 で C6-only stub → v5-2 で本実装 → v5-3 で Mixed に段階昇格 --- diff --git a/core/box/smallobject_hotbox_v5_box.h b/core/box/smallobject_hotbox_v5_box.h index 4715b202..9f513c1f 100644 --- a/core/box/smallobject_hotbox_v5_box.h +++ b/core/box/smallobject_hotbox_v5_box.h @@ -10,21 +10,26 @@ #define NUM_SMALL_CLASSES_V5 8 // C0–C7 // SmallPageMetaV5: v5 ページメタデータ +// Hot fields (alloc/free 頻繁アクセス) を先頭に集約(L1 cache 最適化) 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; + // Hot fields (alloc/free 頻繁アクセス) + void* free_list; // フリーリスト先頭 (offset 0) + uint16_t used; // 使用中ブロック数 (offset 8) + uint16_t capacity; // このページの総容量 (offset 10) + + // Metadata(初期化時のみ) + uint8_t class_idx; // size class index (offset 12) + uint8_t flags; // reserved (offset 13) + uint16_t page_idx; // segment 内でのページインデックス (offset 14) + void* segment; // SmallSegmentV5* への backpointer (offset 16) +} SmallPageMetaV5; // total 24B // SmallClassHeapV5: サイズクラス毎のホットヒープ状態 typedef struct SmallClassHeapV5 { SmallPageMetaV5* current; // 現在のページ(alloc 中) SmallPageMetaV5* partial_head; // partial ページリスト SmallPageMetaV5* full_head; // full ページリスト + uint32_t partial_count; // partial ページ数 } SmallClassHeapV5; // SmallHeapCtxV5: per-thread ホットヒープコンテキスト diff --git a/core/box/smallobject_v5_env_box.h b/core/box/smallobject_v5_env_box.h index 26c80622..51582145 100644 --- a/core/box/smallobject_v5_env_box.h +++ b/core/box/smallobject_v5_env_box.h @@ -7,29 +7,42 @@ #include #include +#include + +// ENV sentinel values +#define ENV_UNINIT (-1) +#define ENV_ENABLED (1) +#define ENV_DISABLED (0) + +// route priority enum +enum small_route_priority { + ROUTE_PRIORITY_V4 = 0, + ROUTE_PRIORITY_V5 = 1, + ROUTE_PRIORITY_AUTO = 2, +}; // small_heap_v5_enabled() - グローバル v5 enable check static inline int small_heap_v5_enabled(void) { - static int g_enabled = -1; - if (g_enabled == -1) { + static int g_enabled = ENV_UNINIT; + if (__builtin_expect(g_enabled == ENV_UNINIT, 0)) { const char* e = getenv("HAKMEM_SMALL_HEAP_V5_ENABLED"); - g_enabled = (e && *e && *e != '0') ? 1 : 0; + g_enabled = (e && *e && *e != '0') ? ENV_ENABLED : ENV_DISABLED; } - return g_enabled; + return (g_enabled == ENV_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) { + static int g_mask = ENV_UNINIT; // sentinel + if (__builtin_expect(g_mask == ENV_UNINIT, 0)) { const char* e = getenv("HAKMEM_SMALL_HEAP_V5_CLASSES"); if (e && *e) { - g_mask = (uint32_t)strtoul(e, NULL, 0); + g_mask = (int)strtoul(e, NULL, 0); } else { g_mask = 0x0; // default: OFF } } - return g_mask; + return (uint32_t)g_mask; } // small_heap_v5_class_enabled() - 指定クラスが v5 有効か @@ -53,4 +66,46 @@ static inline int small_heap_v5_c7_enabled(void) { return small_heap_v5_class_enabled(7); } +// small_route_priority() - route priority (v4/v5/auto) +// ENV: HAKMEM_ROUTE_PRIORITY={v4|v5|auto}, default: v4 +static inline int small_route_priority(void) { + static int g_priority = ENV_UNINIT; + if (__builtin_expect(g_priority == ENV_UNINIT, 0)) { + const char* e = getenv("HAKMEM_ROUTE_PRIORITY"); + if (e && *e) { + if (strcmp(e, "v5") == 0) { + g_priority = ROUTE_PRIORITY_V5; + } else if (strcmp(e, "auto") == 0) { + g_priority = ROUTE_PRIORITY_AUTO; + } else { + g_priority = ROUTE_PRIORITY_V4; // default or "v4" + } + } else { + g_priority = ROUTE_PRIORITY_V4; // default + } + } + return g_priority; +} + +// small_heap_v5_segment_size() - segment size override +// ENV: HAKMEM_SMALL_HEAP_V5_SEGMENT_SIZE, default: 2MiB (2*1024*1024) +static inline size_t small_heap_v5_segment_size(void) { + static int g_size = ENV_UNINIT; + if (__builtin_expect(g_size == ENV_UNINIT, 0)) { + const char* e = getenv("HAKMEM_SMALL_HEAP_V5_SEGMENT_SIZE"); + if (e && *e) { + size_t sz = (size_t)strtoul(e, NULL, 0); + // validate: must be power of 2, >= 64KiB + if (sz >= (64 * 1024) && (sz & (sz - 1)) == 0) { + g_size = (int)sz; + } else { + g_size = (2 * 1024 * 1024); // fallback to default + } + } else { + g_size = (2 * 1024 * 1024); // default: 2MiB + } + } + return (size_t)g_size; +} + #endif // HAKMEM_SMALLOBJECT_V5_ENV_BOX_H diff --git a/core/box/smallsegment_v5_box.h b/core/box/smallsegment_v5_box.h index 6cd46888..09a0a18c 100644 --- a/core/box/smallsegment_v5_box.h +++ b/core/box/smallsegment_v5_box.h @@ -14,6 +14,48 @@ #define SMALL_SEGMENT_V5_MAGIC 0xDEADBEEF #define SMALL_SEGMENT_V5_PAGE_SHIFT 16 // log2(64KiB) +// ポインタマクロ - O(1) segment/page 計算 + +// SMALL_SEGMENT_V5_BASE_FROM_PTR(ptr) - ptr から segment base を mask で計算 +#define SMALL_SEGMENT_V5_BASE_FROM_PTR(ptr) \ + ((SmallSegmentV5*)((uintptr_t)(ptr) & ~(SMALL_SEGMENT_V5_SIZE - 1))) + +// SMALL_SEGMENT_V5_PAGE_IDX(seg, ptr) - segment 内の page_idx を shift で計算 +#define SMALL_SEGMENT_V5_PAGE_IDX(seg, ptr) \ + (((uintptr_t)(ptr) - (uintptr_t)(seg)->base) >> SMALL_SEGMENT_V5_PAGE_SHIFT) + +// SMALL_SEGMENT_V5_PAGE_META(seg, ptr) - page_meta への O(1) access(bounds check付き) +#define SMALL_SEGMENT_V5_PAGE_META(seg, ptr) \ + ({ \ + SmallSegmentV5* _seg = (seg); \ + if (__builtin_expect(!_seg, 0)) { \ + (SmallPageMetaV5*)NULL; \ + } else { \ + size_t _idx = SMALL_SEGMENT_V5_PAGE_IDX(_seg, (ptr)); \ + (__builtin_expect(_idx < _seg->num_pages, 1)) ? \ + &_seg->page_meta[_idx] : (SmallPageMetaV5*)NULL; \ + } \ + }) + +// SMALL_SEGMENT_V5_VALIDATE_MAGIC(seg) - magic 検証 +#define SMALL_SEGMENT_V5_VALIDATE_MAGIC(seg) \ + (__builtin_expect((seg) && (seg)->magic == SMALL_SEGMENT_V5_MAGIC, 1)) + +// SMALL_SEGMENT_V5_VALIDATE_PTR(ptr) - Fail-Fast validation pipeline +// ptr が valid な v5 segment 内にあるかを検証 +#define SMALL_SEGMENT_V5_VALIDATE_PTR(ptr) \ + ({ \ + int _valid = 0; \ + if (__builtin_expect((ptr) != NULL, 1)) { \ + SmallSegmentV5* _seg = SMALL_SEGMENT_V5_BASE_FROM_PTR(ptr); \ + if (SMALL_SEGMENT_V5_VALIDATE_MAGIC(_seg)) { \ + size_t _idx = SMALL_SEGMENT_V5_PAGE_IDX(_seg, (ptr)); \ + _valid = (_idx < _seg->num_pages); \ + } \ + } \ + _valid; \ + }) + // SmallSegmentV5: セグメント構造体 typedef struct SmallSegmentV5 { uintptr_t base; // セグメント先頭アドレス