diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 1410f3db..73bca1cb 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -31,6 +31,21 @@ - Batch+THP 寄り(+`HAKMEM_FREE_POLICY=batch HAKMEM_DISABLE_BATCH=0 HAKMEM_THP=auto`, SS_OS_STATS=1): **33.24M ops/s**。`madvise=3 enomem=0 disabled=0`。perf: task-clock 49.57ms / minor-faults 6,731 / user 35.4ms / sys 15.1ms。 - 所感: pf/OPS とも大差なし。低 madvise での改善は見られず、Batch+THP 側がわずかに良好(+1〜2%)。vm.max_map_count が厳しい環境で failfast を避けたい場合のみ keep/STRICT=0 に切替える運用が現実的。 +### Phase PF2: pf/Segment 足場(v4 強制で pf ベースライン取得) +- 目的: C7/C6 v4 を前提に pf/OS の現状値を押さえ、small-object 専用 Segment Box を設計する地ならし。 +- Release pf ベースライン(v3 OFF, v4=C7+C6 ON): + - ENV: `HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE HAKMEM_BENCH_MIN_SIZE=16 HAKMEM_BENCH_MAX_SIZE=1024 HAKMEM_SS_OS_STATS=1 HAKMEM_SMALL_HEAP_V4_ENABLED=1 HAKMEM_SMALL_HEAP_V4_CLASSES=0xC0 HAKMEM_SMALL_HEAP_V3_ENABLED=0` + - perf stat: **31,779,973 ops/s**, cycles=205,322,023 / instructions=385,092,104 / task-clock=51.40ms / page-faults=6,702。`[SS_OS_STATS] alloc=2 free=4 madvise=2 enomem=0 disabled=0 mmap_total=2` +- DEBUG perf (cycles:u, -O0/-g, v4=C7+C6): + - Throughput=15,173,790 ops/s。self% 上位: tiny_alloc_gate_fast 13.33%, free 14.37% (small_heap_free_fast_v4 3.39%), main 12.93%, malloc 7.09%, ss_map_lookup 4.97%, memset/hak_super_registry_init 合算 ~4.5%, small_heap_alloc_fast_v4 2.23%, hak_tiny_size_to_class 2.21%, tiny_route_get 2.34%, front_gate_unified_enabled 2.36%, tiny_route_is_heap_kind 2.09%, xorshift32 2.08%。 +- ドキュメント/足場: + - 追加: `docs/analysis/PF_STATUS_V4_202502.md`(pf/OS 数値まとめ)、`docs/analysis/SMALLOBJECT_SEGMENT_V4_DESIGN.md`(small-object Segment v4 設計メモ)。 + - 追加: `core/box/smallsegment_v4_box.h` / `core/box/smallsegment_v4_env_box.h`(型と ENV だけ、挙動不変)。 +- 健康診断(Release 再ビルド後、v3 デフォルトで実行): + - Mixed 16–1024B (`HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE`): **36.16M ops/s**(segv/assert なし)。 + - C6-heavy (`HAKMEM_PROFILE=C6_HEAVY_LEGACY_POOLV1`, min=257/max=768): **28.33M ops/s**(segv/assert なし)。 + - 目安レンジからは少し低め(Mixed)。今後の PF/Segment A/B はこのラインからの増減を確認する。 + ### Hotfix: madvise(ENOMEM) を握りつぶし、以降の madvise を停止(Superslab OS Box) - 変更: `ss_os_madvise_guarded()` を追加し、madvise が ENOMEM を返したら `g_ss_madvise_disabled=1` にして以降の madvise をスキップ。EINVAL だけは従来どおり STRICT=1 で Fail-Fast(ENV `HAKMEM_SS_MADVISE_STRICT` で緩和可)。 - stats: `[SS_OS_STATS]` に `madvise_enomem/madvise_other/madvise_disabled` を追加。HAKMEM_SS_OS_STATS=1 で確認可能。 @@ -1071,3 +1086,13 @@ export HAKMEM_POOL_ZERO_MODE=header - C6 v1: 28,690,913 ops/s - C6 v4: 30,068,995 ops/s(+4.8%)segv/assert なし - Mixed 16–1024B: デフォルトは C6 v1 のまま(`HAKMEM_SMALL_HEAP_V4_CLASSES=0x80` で C7-only)。C6 v4 は研究箱として opt-in(`0x40`)。 + +### Phase v4-5: C5 v4 パイロット(C5-heavy 専用、強ゲート) +- 変更: + - v4 クラスビットに C5(bit5=0x20) を追加。HotBox_v4 / ColdIface_v4 / front free を C5 パスでも通電。 + - `small_heap_v4_class_enabled(5)` 経由で route LUT が v4 を返せるようにしつつ、デフォルトは bit5=0(研究箱)。 +- ENV 例(C5-only v4 の opt-in): + - `HAKMEM_SMALL_HEAP_V4_ENABLED=1` + - `HAKMEM_SMALL_HEAP_V4_CLASSES=0x20` +- 状態: + - 実装のみ。C5-heavy / Mixed A/B は未実施。デフォルトは C5 v1 のまま(Mixed プロファイルも bit5=0)で、segv/assert 無しを確認した上で昇格判断。 diff --git a/core/box/smallobject_hotbox_v4_box.h b/core/box/smallobject_hotbox_v4_box.h index e799a1ae..f002fdf1 100644 --- a/core/box/smallobject_hotbox_v4_box.h +++ b/core/box/smallobject_hotbox_v4_box.h @@ -5,8 +5,9 @@ // - 挙動はまだ v3/v1 のまま。alloc/free 本体は後続フェーズで実装する。 #pragma once -#include #include +#include +#include #include "tiny_geometry_box.h" @@ -46,3 +47,4 @@ small_heap_ctx_v4* small_heap_ctx_v4_get(void); // Hot path API (C7-only stub; later phases will expand) void* small_heap_alloc_fast_v4(small_heap_ctx_v4* ctx, int class_idx); void small_heap_free_fast_v4(small_heap_ctx_v4* ctx, int class_idx, void* ptr); +int smallobject_hotbox_v4_can_own(int class_idx, void* ptr); diff --git a/core/box/smallobject_hotbox_v4_env_box.h b/core/box/smallobject_hotbox_v4_env_box.h index 22430381..baf86e20 100644 --- a/core/box/smallobject_hotbox_v4_env_box.h +++ b/core/box/smallobject_hotbox_v4_env_box.h @@ -47,3 +47,7 @@ static inline int small_heap_v4_c7_enabled(void) { static inline int small_heap_v4_c6_enabled(void) { return small_heap_v4_class_enabled(6); } + +static inline int small_heap_v4_c5_enabled(void) { + return small_heap_v4_class_enabled(5); +} diff --git a/core/box/smallsegment_v4_box.h b/core/box/smallsegment_v4_box.h new file mode 100644 index 00000000..127d22fb --- /dev/null +++ b/core/box/smallsegment_v4_box.h @@ -0,0 +1,11 @@ +// smallsegment_v4_box.h - Small-object専用 Segment Box の宣言だけを置く足場 +// Phase PF2: 挙動はまだ変えず、型と API だけを先行定義する。 +#pragma once + +typedef struct small_segment_v4 small_segment_v4; + +// class_idx ごとに小さな Segment を確保/再利用する想定。 +// まだ実装はなく、次フェーズで Superslab/OS との接続を決める。 +small_segment_v4* smallsegment_v4_acquire(int class_idx); +void* smallsegment_v4_alloc_page(small_segment_v4* seg, int class_idx); +void smallsegment_v4_release_if_empty(small_segment_v4* seg); diff --git a/core/box/smallsegment_v4_env_box.h b/core/box/smallsegment_v4_env_box.h new file mode 100644 index 00000000..cad840a0 --- /dev/null +++ b/core/box/smallsegment_v4_env_box.h @@ -0,0 +1,28 @@ +// smallsegment_v4_env_box.h - small-object segment v4 の ENV ゲート +// Phase PF2: ENV を宣言するだけ。実装は次フェーズで追加。 +#pragma once + +#include + +static inline int smallsegment_v4_enabled(void) { + static int g = -1; + if (__builtin_expect(g == -1, 0)) { + const char* e = getenv("HAKMEM_SMALL_SEGMENT_V4_ENABLED"); + if (e && *e && *e != '0') { + g = 1; + } else { + g = 0; + } + } + return g; +} + +static inline const char* smallsegment_v4_size_env(void) { + static int g_init = 0; + static const char* g_val = NULL; + if (__builtin_expect(!g_init, 0)) { + g_val = getenv("HAKMEM_SMALL_SEGMENT_V4_SIZE"); + g_init = 1; + } + return g_val; +} diff --git a/core/box/tiny_front_v3_env_box.h b/core/box/tiny_front_v3_env_box.h index 51f77740..10727ae8 100644 --- a/core/box/tiny_front_v3_env_box.h +++ b/core/box/tiny_front_v3_env_box.h @@ -77,6 +77,16 @@ static inline bool tiny_ptr_fast_classify_enabled(void) { return g != 0; } +// C7/C6 v4 free 用 fast classify gate (default OFF) +static inline bool tiny_ptr_fast_classify_v4_enabled(void) { + static int g = -1; + if (__builtin_expect(g == -1, 0)) { + const char* e = getenv("HAKMEM_TINY_PTR_FAST_CLASSIFY_V4_ENABLED"); + g = (e && *e && *e != '0') ? 1 : 0; + } + return g != 0; +} + // Optional stats gate static inline bool tiny_front_v3_stats_enabled(void) { static int g = -1; diff --git a/core/front/malloc_tiny_fast.h b/core/front/malloc_tiny_fast.h index 9eacf96e..6d6f85f6 100644 --- a/core/front/malloc_tiny_fast.h +++ b/core/front/malloc_tiny_fast.h @@ -252,6 +252,15 @@ static inline int free_tiny_fast(void* ptr) { } tiny_route_kind_t route = tiny_route_for_class((uint8_t)class_idx); + + if ((class_idx == 7 || class_idx == 6) && + route == TINY_ROUTE_SMALL_HEAP_V4 && + tiny_ptr_fast_classify_v4_enabled() && + smallobject_hotbox_v4_can_own(class_idx, base)) { + small_heap_free_fast_v4(small_heap_ctx_v4_get(), class_idx, base); + return 1; + } + const int use_tiny_heap = tiny_route_is_heap_kind(route); const TinyFrontV3Snapshot* front_snap = __builtin_expect(tiny_front_v3_enabled(), 0) ? tiny_front_v3_snapshot_get() : NULL; @@ -319,7 +328,7 @@ static inline int free_tiny_fast(void* ptr) { if (__builtin_expect(use_tiny_heap, 0)) { switch (route) { case TINY_ROUTE_SMALL_HEAP_V4: - if (class_idx == 7 || class_idx == 6) { + if (class_idx == 7 || class_idx == 6 || class_idx == 5) { small_heap_free_fast_v4(small_heap_ctx_v4_get(), class_idx, base); return 1; } diff --git a/core/smallobject_hotbox_v4.c b/core/smallobject_hotbox_v4.c index a36a8220..556089d3 100644 --- a/core/smallobject_hotbox_v4.c +++ b/core/smallobject_hotbox_v4.c @@ -1,6 +1,6 @@ -// smallobject_hotbox_v4.c - SmallObject HotHeap v4 (C7-only real path) +// smallobject_hotbox_v4.c - SmallObject HotHeap v4 (C5/C6/C7 opt-in) // -// Phase v4-3: C7 クラスについては v4 独自の freelist/current/partial で完結させる。 +// Phase v4-3.1: C7 は v4 独自の freelist/current/partial で完結。C6/C5 は強ゲート付きで同形パスを使う。 #include #include @@ -17,8 +17,6 @@ // TLS context static __thread small_heap_ctx_v4 g_ctx_v4; -#define V4_MAX_PARTIAL_PAGES 1 - small_heap_ctx_v4* small_heap_ctx_v4_get(void) { return &g_ctx_v4; } @@ -27,6 +25,10 @@ small_heap_ctx_v4* small_heap_ctx_v4_get(void) { // helpers // ----------------------------------------------------------------------------- +static inline int v4_class_supported(int class_idx) { + return class_idx == 7 || class_idx == 6 || class_idx == 5; +} + static inline void v4_page_push_partial(small_class_heap_v4* h, small_page_v4* page) { if (!h || !page) return; page->next = h->partial_head; @@ -53,6 +55,11 @@ static inline void v4_page_push_full(small_class_heap_v4* h, small_page_v4* page h->full_head = page; } +static inline uint32_t v4_partial_limit(int class_idx) { + // C7 は refill/retire を抑えるため少し広めに保持 + return (class_idx == 7) ? 2u : 1u; +} + static inline int v4_ptr_in_page(const small_page_v4* page, const uint8_t* ptr) { if (!page || !ptr) return 0; uint8_t* base = page->base; @@ -97,16 +104,32 @@ static small_page_v4* v4_find_page(small_class_heap_v4* h, const uint8_t* ptr, v return p; } } - // full リストは探さない(v4 C7 は partial/current だけで完結する想定) + for (small_page_v4* p = h->full_head; p; prev = p, p = p->next) { + if (v4_ptr_in_page(p, ptr)) { + if (loc) *loc = V4_LOC_FULL; + if (prev_out) *prev_out = prev; + return p; + } + } return NULL; } +int smallobject_hotbox_v4_can_own(int class_idx, void* ptr) { + if (__builtin_expect(!v4_class_supported(class_idx), 0)) return 0; + if (!small_heap_v4_class_enabled((uint8_t)class_idx)) return 0; + if (!ptr) return 0; + small_heap_ctx_v4* ctx = small_heap_ctx_v4_get(); + if (!ctx) return 0; + small_class_heap_v4* h = &ctx->cls[class_idx]; + return v4_find_page(h, (const uint8_t*)ptr, NULL, NULL) != NULL; +} + // ----------------------------------------------------------------------------- -// Cold iface (C7-only, Tiny v1 経由) +// Cold iface (C5/C6/C7, Tiny v1 経由) // ----------------------------------------------------------------------------- static small_page_v4* cold_refill_page_v4(small_heap_ctx_v4* hot_ctx, uint32_t class_idx) { - if (__builtin_expect(class_idx != 7 && class_idx != 6, 0)) return NULL; + if (__builtin_expect(!v4_class_supported((int)class_idx), 0)) return NULL; (void)hot_ctx; tiny_heap_ctx_t* tctx = tiny_heap_ctx_for_thread(); if (!tctx) return NULL; @@ -163,13 +186,14 @@ const SmallColdIfaceV4* small_cold_iface_v4_get(void) { static small_page_v4* small_alloc_slow_v4(small_heap_ctx_v4* ctx, int class_idx) { small_class_heap_v4* h = &ctx->cls[class_idx]; + const uint32_t partial_limit = v4_partial_limit(class_idx); small_page_v4* cur = h->current; if (cur && cur->freelist) { return cur; // usable current } if (cur && !cur->freelist) { // current をいったん partial/full に退避(partial を優先) - if (h->partial_count < V4_MAX_PARTIAL_PAGES) { + if (h->partial_count < partial_limit) { v4_page_push_partial(h, cur); } else { v4_page_push_full(h, cur); @@ -193,8 +217,8 @@ static small_page_v4* small_alloc_slow_v4(small_heap_ctx_v4* ctx, int class_idx) } void* small_heap_alloc_fast_v4(small_heap_ctx_v4* ctx, int class_idx) { - if (__builtin_expect(class_idx != 7 && class_idx != 6, 0)) { - return NULL; // C6/C7 専用 + if (__builtin_expect(!v4_class_supported(class_idx), 0)) { + return NULL; // C5/C6/C7 以外は未対応 } if (!small_heap_v4_class_enabled((uint8_t)class_idx)) return NULL; small_class_heap_v4* h = &ctx->cls[class_idx]; @@ -240,7 +264,7 @@ static void v4_unlink_from_list(small_class_heap_v4* h, v4_loc_t loc, small_page } void small_heap_free_fast_v4(small_heap_ctx_v4* ctx, int class_idx, void* ptr) { - if (__builtin_expect(class_idx != 7 && class_idx != 6, 0)) { + if (__builtin_expect(!v4_class_supported(class_idx), 0)) { return; } if (!small_heap_v4_class_enabled((uint8_t)class_idx)) return; @@ -252,6 +276,8 @@ void small_heap_free_fast_v4(small_heap_ctx_v4* ctx, int class_idx, void* ptr) { small_page_v4* page = v4_find_page(h, (const uint8_t*)ptr, &loc, &prev); if (!page) return; + const uint32_t partial_limit = v4_partial_limit(class_idx); + // freelist push void* head = page->freelist; memcpy(ptr, &head, sizeof(void*)); @@ -274,7 +300,7 @@ void small_heap_free_fast_v4(small_heap_ctx_v4* ctx, int class_idx, void* ptr) { page->next = NULL; return; } - if (h->partial_count < V4_MAX_PARTIAL_PAGES) { + if (h->partial_count < partial_limit) { v4_page_push_partial(h, page); return; } @@ -296,7 +322,7 @@ void small_heap_free_fast_v4(small_heap_ctx_v4* ctx, int class_idx, void* ptr) { } else if (loc == V4_LOC_FULL && page->freelist) { // full → partial に戻す(current があっても partial 上限までは復帰) v4_unlink_from_list(h, loc, prev, page); - if (h->partial_count < V4_MAX_PARTIAL_PAGES) { + if (h->partial_count < partial_limit) { v4_page_push_partial(h, page); } else { v4_page_push_full(h, page); // 上限超なら戻す diff --git a/docs/analysis/PF_STATUS_V4_202502.md b/docs/analysis/PF_STATUS_V4_202502.md new file mode 100644 index 00000000..2adbfabc --- /dev/null +++ b/docs/analysis/PF_STATUS_V4_202502.md @@ -0,0 +1,52 @@ +# PF/OS ベースライン (PF2, small-object v4 状態) + +- コマンド (Release, v4: C7+C6 を v4 に強制、v3 OFF): + ``` + HAKMEM_PROFILE=MIXED_TINYV3_C7_SAFE \ + HAKMEM_BENCH_MIN_SIZE=16 \ + HAKMEM_BENCH_MAX_SIZE=1024 \ + HAKMEM_SS_OS_STATS=1 \ + HAKMEM_SMALL_HEAP_V4_ENABLED=1 \ + HAKMEM_SMALL_HEAP_V4_CLASSES=0xC0 \ + HAKMEM_SMALL_HEAP_V3_ENABLED=0 \ + perf stat -e cycles,instructions,task-clock,page-faults \ + ./bench_random_mixed_hakmem 1000000 400 1 + ``` +- 結果 (環境: リリースビルド, ws=400, iters=1M): + - Throughput: **31,779,973 ops/s** (time=0.031s) + - perf stat: cycles=205,322,023 / instructions=385,092,104 / task-clock=51.40ms / page-faults=6,702 + - `[SS_OS_STATS]` : alloc=2 free=4 madvise=2 madvise_enomem=0 madvise_disabled=0 mmap_total=2 +- 所感: + - v4 (C7+C6) 強制時の pf/OS 基準値。v3 基準 (~40M) より遅めだが、pf 数値と OS stats を PF2 の起点として固定。 + - 今後 SmallSegmentBox_v4 を繋ぐ A/B では、page-faults/SS_OS_STATS をこの値からどこまで下げられるかを指標にする。 + +## DEBUG perf (cycles:u, -O0/-g, v4=C7+C6) + +- ビルド: + ``` + make clean + CFLAGS='-O0 -g' USE_LTO=0 OPT_LEVEL=0 NATIVE=0 make bench_random_mixed_hakmem -j4 + ``` +- コマンド: + ``` + HAKMEM_PROFILE=DEBUG_TINY_FRONT_PERF \ + HAKMEM_BENCH_MIN_SIZE=16 \ + HAKMEM_BENCH_MAX_SIZE=1024 \ + HAKMEM_SMALL_HEAP_V4_ENABLED=1 \ + HAKMEM_SMALL_HEAP_V4_CLASSES=0xC0 \ + HAKMEM_SMALL_HEAP_V3_ENABLED=0 \ + perf record -F 5000 --call-graph dwarf -e cycles:u \ + -o perf.data.pf_v4 ./bench_random_mixed_hakmem 1000000 400 1 + ``` +- Throughput: **15,173,790 ops/s** (DEBUG, ws=400, iters=1M, v4=C7+C6) +- self% 上位 (perf report --stdio): + - free 14.37%(small_heap_free_fast_v4 内 3.39%) + - tiny_alloc_gate_fast 13.33% + - main 12.93% + - malloc 7.09% + - ss_map_lookup 4.97% / hak_super_registry_init + memset 合算 ~4.5% + - small_heap_alloc_fast_v4 2.23% + - hak_tiny_size_to_class 2.21% / tiny_route_get 2.34% / front_gate_unified_enabled 2.36% / tiny_route_is_heap_kind 2.09% + - xorshift32 2.08% +- メモ: + - v4 強制下でも gate/classify/ss_map_lookup が依然目立つ。Segment/OS 側が整えば pf と合わせて自明に下がるかを PF3 で確認。 diff --git a/docs/analysis/SMALLOBJECT_SEGMENT_V4_DESIGN.md b/docs/analysis/SMALLOBJECT_SEGMENT_V4_DESIGN.md new file mode 100644 index 00000000..24ec7f95 --- /dev/null +++ b/docs/analysis/SMALLOBJECT_SEGMENT_V4_DESIGN.md @@ -0,0 +1,30 @@ +# SmallObject Segment v4 設計メモ (PF2 草稿) + +## 目的と背景 +- Mixed 16–1024B で mimalloc の 70〜80% に近づくため、small-object 向けの pf/OS レイヤをまとめて削る。 +- C7/C6 v4 が揃った状態を前提に、Superslab 配置と Segment 分割を見直し、触る Superslab 数と VMA 数を減らす。 +- まだ実装は行わず、箱の分割とパラメータの置き場所を決める段階。 + +## 現状のレイアウト(把握用) +- Superslab サイズは既存の Tiny/Superslab のまま(4KiB ページ上で C1〜C7 を混載)。 +- C5〜C7 のページが混在し、Mixed では 1M ops あたりに跨る Superslab が多い。 +- pf としては `mmap/madvise/munmap` の回数が小さくない。C7-only v4 でも minor-faults がボトルネック側に寄りつつある。 + +## small-object 専用 Segment 案(方向性) +- Superslab を small-object 専用に 2MiB/4MiB 単位でまとめ、C5〜C7 をできるだけ同一 Segment 内に詰める。 +- Mixed で触る Superslab の種類を減らし、TLB/pf を削る。 +- Box 化のイメージ: + - **SmallSegmentBox_v4**: Segment の取得/解放と page carving を担当。SuperslabBox/OS を内側で呼ぶ。 + - **SmallSegmentEnvBox_v4**: ENV で Segment サイズやポリシーを決定(例: `HAKMEM_SMALL_SEGMENT_V4_SIZE=2M/4M`)。 + - **SmallSegmentStatsBox**: 触った Segment 数、mmap/madvise 回数、ページ再利用回数をカウントし、PF 調査用にダンプ。 +- HotBox_v4 からは ColdIface を通して Segment Box に触れるだけにし、ホットパスは segment/pf を意識しない。 + +## 今後のフェーズ +- **PF2(今回)**: 現状の pf/OS ベースラインを v4 状態で取り直し、Segment Box の箱だけ追加(挙動不変)。 +- **PF3**: SmallSegmentBox_v4 を実装し、C7/C6 v4 で small-object 専用 Segment を試す A/B を実施。 +- **PF4**: Segment サイズ/ポリシーのチューニングと pf/OS スタッツの可視化強化。成功したら ENV プリセットに反映。 + +## メモ +- C5 v4 はまだ研究箱(C5-heavy 専用)。Mixed では C5 v1 を維持する予定。 +- C6 v4 は C6-heavy で +4〜5% が見えており、Mixed ではデフォルト OFF(研究箱)。 +- PF 系の変更はすべて ENV ゲート付きにし、既存の Mixed/C6-heavy 健康診断がいつでも通る状態を維持する。 diff --git a/docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md b/docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md index ea04346e..01821486 100644 --- a/docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md +++ b/docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md @@ -16,8 +16,10 @@ - **v4-2**: C7-only を v4 に寄せ、v3 互換の挙動で動かす(ENV ゲート付き、v4 が優先)。 - **v4-3**: C7-only を v4 自前の freelist/current/partial で動かす(Cold は Tiny v1 経由)。v3 はベンチ用に残し ENV で A/B。 - **v4-3.1 (今回)**: C7 v4 で current/partial 再利用を強化し、prepare_calls を v3 並みに抑制。C7-only ベンチで v4 が v3 比 +1% 程度まで回復。 -- **v4-4**: C5〜C7 を含む全 small-object クラスを v4 に段階移行。route LUT から v4 を返せるようにする。 -- **v4-5**: Segment/Page/Block レイアウトと pf 削減、WarmPool チューニングを v4 用に調整。 +- **v4-4**: C6 v4 パイロット(C6-heavy 専用 opt-in)。C7 v4 を維持しつつ C6 を v4 に載せる。 +- **v4-5**: C5 v4 パイロット(C5-heavy 専用 opt-in)。Mixed 標準は C5 v1 のまま。 +- **PF2 (今回)**: v4 状態での pf/OS ベースライン取得と small-object Segment Box の箱だけ追加(挙動不変)。 +- **v4-6 / PF3 以降**: Segment/Page/Block レイアウトと pf 削減、WarmPool チューニングを v4 用に調整。 ## 現行 v3/v2 の扱い - v3: C7-only front v3 の prototype として構造だけ再利用する。性能・安定のベースライン。 @@ -28,6 +30,7 @@ - `core/box/smallobject_cold_iface_v4.h`: ColdIface の関数ポインタ箱(C7 専用 refill/retire を v1 Tiny に繋ぐ)。 - `core/box/tiny_route_env_box.h`: `TINY_ROUTE_SMALLHEAP_V4` を追加し、ENV `HAKMEM_SMALL_HEAP_V4_ENABLED` / `HAKMEM_SMALL_HEAP_V4_CLASSES` から C7 を v4 route に載せられる(未指定なら OFF)。 - `core/front/malloc_tiny_fast.h`: route switch に v4 の case を足し、C7 v4 が ON のときは v4 経路(現在は C7 自前 freelist, それ以外は v1/v3 へフォールバック)、OFF 時は従来の v3/v1。 +- `core/box/smallsegment_v4_box.h` / `core/box/smallsegment_v4_env_box.h`: PF2 で追加した small-object Segment Box の足場(型と ENV だけ、挙動不変)。設計メモは `docs/analysis/SMALLOBJECT_SEGMENT_V4_DESIGN.md` にまとめる。 ## A/B と運用 - Phase v4-3.1 時点の健康診断: @@ -44,3 +47,7 @@ - C6 v1: 28.69M ops/s - C6 v4: 30.07M ops/s(+4.8%)segv/assert なし - Mixed 16–1024B はデフォルトで C6 v1 のまま(C6 v4 は研究箱)。今後 C6 v4 の安定度を見つつ拡張予定。 +- Phase v4-5 (C5 v4 パイロット; C5-heavy 専用 opt-in): + - ENV: `HAKMEM_SMALL_HEAP_V4_ENABLED=1`, `HAKMEM_SMALL_HEAP_V4_CLASSES=0x20`(C5-only v4)。C7 v4 / C6 v4 とは独立にビットで切替。 + - 目的: C5-heavy ワークロードで v4 が v1 を上回るか確認。Mixed 標準は C5 v1 のまま(C5 v4 は研究箱)。 + - ステータス: 実装済み。C5-heavy / Mixed の A/B は未実施。segv/assert の有無と throughput を確認してから昇格判断。