Fix tiny lane success handling for TinyHeap routes

This commit is contained in:
Moe Charm (CI)
2025-12-07 23:06:50 +09:00
parent a6991ec9e4
commit 9502501842
5 changed files with 95 additions and 20 deletions

View File

@ -11,6 +11,11 @@
- Prefault Box`ss_prefault_box.h`は追加済みだが、4MB MAP_POPULATE 問題を避けるためデフォルト OFF`HAKMEM_SS_PREFAULT=0`)に設定。
### 直近の成果
- TinyHeap クラスマスクC6 A/B 試験)と C6 ベンチ速報
- ENV `HAKMEM_TINY_HEAP_CLASSES` を追加し、bitmask で TinyHeap に載せるクラスを制御(デフォルト 0x80=C7 のみ。Gate も per-class で TinyHeap/旧フロントを切替。
- SLL refill/prewarm は `tiny_heap_class_route_enabled(cls)` で早期 return するため、C6 を TinyHeap に載せても TLS SLL を踏まない 2 層構造を維持。
- ベンチ (Release, iters=20k, ws=256, min=257 max=768): TinyHeap OFF ≈45.7M ops/s / C6 TinyHeap (`HEAP_CLASSES=0x40`) ≈39.7M / C6+C7 TinyHeap (`0xC0`) ≈34.1M (Tiny lane failed 警告あり)。
- Mixed 161024B でも TinyHeap OFF ≈46.8M / C7 only (`0x80`) ≈39.4M / C6+C7 (`0xC0`) ≈33.8MTiny lane failed 警告が出る。Gate 側判定の整理が今後の課題)。
- C7 TinyHeap Phase 3stride キャッシュmeta-light 実装)
- `tiny_heap_class_t` に stride キャッシュを追加し、ctx 初期化時に全クラスの stride を前計算。`tiny_heap_page_pop()` は hcls->stride を使うようにして C7 alloc の算術コストを削減。
- free 側で class7 は「今 free した page を current_page に優先」するように変更し、alloc_slow_prepare の頻度を下げる方向に調整。
@ -243,6 +248,14 @@
- TLS SLL との分離をクラス単位に拡張: `sll_refill_small_from_ss` / `sll_refill_batch_from_ss` / `hak_tiny_prewarm_tls_cache``tiny_heap_class_route_enabled(cls)` のとき即 return/skipC6 も TinyHeap に載せたら SLL を経由しない)。
- ドキュメント: TinyHeapBox/C7HotBox 設計にクラス bitmask と multi-class 対応の方針を追記。ベンチは今後 C6/C7 切替パターンで再計測予定。
### Phase 9: Tiny lane 判定を TinyHeap と整合
- `hak_alloc_at` で Tiny route の class_idx / TinyHeap route ON/OFF を保持し、Tiny front NULL 時に TinyHeap を直接試行。TinyHeap が有効なクラスでの NULL は静かなフォールバック扱いにし、`Tiny lane failed` 警告は legacy Tiny route が本当に失敗した場合のみ出す。
- Gate から TinyHeap 経路で成功した alloc/free は Tiny lane 成功として扱うよう統一C6/C7 の mixed で出ていた警告を抑止)。
- ベンチ (Release, iters=20k, ws=256):
- C6 偏重 (min=257 max=768): OFF≈47.8M / C6-only TinyHeap≈39.2M / C6+C7 TinyHeap≈31.3M(警告なし)。
- Mixed 161024B: OFF≈47.6M / C7-only TinyHeap≈36.9M / C6+C7 TinyHeap≈30.3M(警告なし)。
- ドキュメント更新: Tiny lane 判定と TinyHeap 整合のメモを `docs/analysis/TINY_HEAP_BOX_DESIGN.md` / `docs/analysis/C7_HOTBOX_DESIGN.md` に追記。
ホットパス perf フェーズの TODO
1. tiny_alloc_fast / tiny_free_fast_v2 の再プロファイル:残存分岐・間接呼び出し・重い箱を特定。
2. Unified Cache ヒットパスを最短化:ヒット時を 12 load + 軽分岐に近づける(必要なら C7 専用インライン版検討)。

View File

@ -6,7 +6,8 @@
#include "../hakmem_tiny.h" // For tiny_get_max_size() + hak_lane_classify.inc.h
#include "../hakmem_pool.h" // Phase 2: For hak_pool_try_alloc() (Pool lane 1025B-52KB)
#include "../hakmem_smallmid.h" // For Small-Mid Front Box (Phase 17-1)
#include "tiny_heap_env_box.h" // TinyHeap front gate (C7)
#include "tiny_heap_env_box.h" // TinyHeap front gate (C7 / multi-class)
#include "tiny_heap_box.h" // TinyHeapBox alloc/free helpers
#include "tiny_c7_hotbox.h" // tiny_c7_alloc_fast wrapper
#ifdef HAKMEM_POOL_TLS_PHASE1
@ -70,6 +71,9 @@ inline void* hak_alloc_at(size_t size, hak_callsite_t site) {
// Phase 16: Dynamic Tiny max size (ENV: HAKMEM_TINY_MAX_CLASS)
// Default: 1023B (C0-C7), reduced to 255B (C0-C5) when Small-Mid enabled
// Phase 17-1: Auto-adjusted to avoid overlap with Small-Mid
int tiny_class_idx = -1;
int tiny_heap_route = 0;
int tiny_tried = 0;
if (__builtin_expect(size <= tiny_get_max_size(), 1)) {
#if HAKMEM_DEBUG_TIMING
HKM_TIME_START(t_tiny);
@ -86,12 +90,21 @@ inline void* hak_alloc_at(size_t size, hak_callsite_t site) {
HKM_TIME_END(HKM_CAT_TINY_ALLOC, t_tiny);
#endif
// PERF_OPT: likely hint - tiny allocations usually succeed (hot path)
tiny_class_idx = hak_tiny_size_to_class(size);
tiny_heap_route = (tiny_class_idx >= 0 && tiny_heap_class_route_enabled(tiny_class_idx));
tiny_tried = 1;
if (__builtin_expect(tiny_ptr != NULL, 1)) { hkm_ace_track_alloc(); return tiny_ptr; }
// TinyHeap front (C7) は Tiny lane の成功として扱う
if (__builtin_expect(size == 1024 && tiny_c7_heap_mode_enabled(), 0)) {
void* c7_ptr = tiny_c7_alloc_fast(size);
if (c7_ptr) { hkm_ace_track_alloc(); return c7_ptr; }
// TinyHeap route is also "Tiny lane success" (C7 or other enabled classes)
if (__builtin_expect(tiny_heap_route, 0)) {
void* th_ptr = NULL;
if (tiny_class_idx == 7 && tiny_c7_hot_enabled()) {
th_ptr = tiny_c7_alloc_fast(size);
} else {
th_ptr = tiny_heap_alloc_class_fast(tiny_heap_ctx_for_thread(), tiny_class_idx, size);
}
if (th_ptr) { hkm_ace_track_alloc(); return th_ptr; }
}
// PHASE 7 CRITICAL FIX: No malloc fallback for Tiny failures
@ -227,7 +240,7 @@ inline void* hak_alloc_at(size_t size, hak_callsite_t site) {
#endif
ptr = hak_os_map_boundary(size, site_id);
} else {
// LANE_TINY failed - this is a design bug!
// LANE_TINY failed - treat TinyHeap route as normal fallback, legacy Tiny failure is a bug
HAK_LANE_ASSERT_NO_FALLBACK(LANE_FALLBACK, size);
static _Atomic int oom_count = 0;
const int c7_heap_on = (size == 1024 && tiny_heap_box_enabled());
@ -240,8 +253,15 @@ inline void* hak_alloc_at(size_t size, hak_callsite_t site) {
return NULL;
}
int count = atomic_fetch_add(&oom_count, 1);
if (count < 10) {
fprintf(stderr, "[HAKMEM] BUG: Tiny lane failed for size=%zu (should not happen)\n", size);
if (tiny_heap_route) {
if (!HAKMEM_BUILD_RELEASE && count < 3) {
fprintf(stderr, "[HAKMEM] TinyHeap route fallback size=%zu class=%d (Tiny lane bypass)\n",
size, tiny_class_idx);
}
} else {
if (tiny_tried && count < 10) {
fprintf(stderr, "[HAKMEM] BUG: Tiny lane failed for size=%zu (should not happen)\n", size);
}
}
errno = ENOMEM;
return NULL;

View File

@ -105,6 +105,20 @@ Phase 7: クラス選択式 TinyHeapC6/C5 拡張のためのゲート)
- Gate: `malloc_tiny_fast` / `free_tiny_fast` がクラスごとに TinyHeap 経路を選択。C7 は `tiny_c7_heap_mode_enabled()``HAKMEM_TINY_C7_HOT` 連動)を維持しつつ、他クラスは `tiny_heap_alloc/free_class_fast()` を使う薄ラッパで扱う。
- TLS SLL 側もクラス単位で分離し、`sll_refill_small_from_ss` / `sll_refill_batch_from_ss` / `hak_tiny_prewarm_tls_cache` が TinyHeap クラスを早期 return/skip。C7 は「TinyHeapBox ↔ Superslab/Tier/Guard」だけを踏む二層構造のまま。
Phase 8: C6 を TinyHeap に載せた観測
-------------------------------------
- TinyHeap ON + `HAKMEM_TINY_HEAP_CLASSES=0x40` で C6 を TinyHeap に載せ、SLL/prewarm/refill が early return していることを確認C7 と同じ二層構造で動作)。
- ベンチ (Release, iters=20k, ws=256, min=257 max=768): TinyHeap OFF ≈45.7M ops/s、C6 TinyHeap ≈39.7M ops/s、C6+C7 TinyHeap (mask=0xC0) ≈34.1M ops/s。
- Mixed 161024B (iters=20k, ws=256): TinyHeap OFF ≈46.8M ops/s、C7 only TinyHeap ≈39.4M ops/s、C6+C7 TinyHeap ≈33.8M ops/s。いずれも Tiny lane failed 警告が出るケースありGate 側の判定/フォールバック整理が今後の課題)。
Phase 9: Tiny lane 判定を TinyHeap と揃える
------------------------------------------
- Gate (`hak_alloc_at`) が TinyHeap 経路を「Tiny lane の成功」として扱うように修正。class_idx を保持し、TinyHeap クラスなら TinyHeap 直接呼び出しも試行し、NULL の場合は静かなフォールバック(警告は legacy Tiny route のみ)。
- 警告抑止後のベンチ (Release, iters=20k, ws=256):
- C6 偏重 (min=257 max=768): OFF≈47.8M / C6 only TinyHeap≈39.2M / C6+C7 TinyHeap≈31.3M(警告なし)。
- Mixed 161024B: OFF≈47.6M / C7 only TinyHeap≈36.9M / C6+C7 TinyHeap≈30.3M(警告なし)。
- 依然として性能は TinyHeap OFF より低いケースがあるため、C6/C7 の slow_prepare 削減や current_page 利用強化を次フェーズで行う。
TinyHeapBox への載せ替えPhase 1.0 構造)
------------------------------------------
- C7HotBox の実体を `core/box/tiny_heap_box.h` の汎用 TinyHeapBox 上に配置し、型は `tiny_heap_ctx_t` / `tiny_heap_page_t` へ統一。

View File

@ -100,6 +100,34 @@ Phase 7: クラス選択式 TinyHeapC6 拡張の足場)
- TLS SLL との切り離しをクラス単位に拡張: `sll_refill_small_from_ss` / `sll_refill_batch_from_ss` / `hak_tiny_prewarm_tls_cache``tiny_heap_class_route_enabled(cls)` なら即 return/skip。TinyHeap クラスは Superslab↔TinyHeapBox のみを通る。
- 例: `HAKMEM_TINY_HEAP_CLASSES=0x40` で C6 だけ TinyHeap、`0xC0` で C6+C7 TinyHeap。今後のベンチで C6-only / mixed ワークロードの hit 率と slow_prepare 割合を確認する。
Phase 8: C6 TinyHeap A/B と経路確認
-----------------------------------
- ルートC6 を TinyHeap に載せた場合)
- alloc: `malloc_tiny_fast → class_idx=6 → tiny_heap_class_route_enabled(6)=1 → tiny_heap_alloc_class_fast(ctx,6,size)` → current/partial を使い、枯渇時のみ Superslab/Tier/Guard に降りる。
- free : `free_tiny_fast → header→class_idx=6 → tiny_heap_class_route_enabled(6)=1 → tiny_heap_free_class_fast(ctx,6,ptr)` → page 内 free_list で完結し、empty 時だけ slow 境界へ。
- SLL/Prewarm 切り離し: `sll_refill_small_from_ss` / `sll_refill_batch_from_ss` / `hak_tiny_prewarm_tls_cache``tiny_heap_class_route_enabled(cls)` で C6 も early return/skip するため、TinyHeap クラスは TLS SLL を一切踏まない。
- ベンチ (Release, iters=20k, ws=256, min=257 max=768)
- TinyHeap OFF (`HEAP_BOX=0`): ≈45.7M ops/s。
- C6 だけ TinyHeap (`HEAP_BOX=1` `HEAP_CLASSES=0x40` `C7_HOT=0`): ≈39.7M ops/s。
- C6+C7 TinyHeap (`HEAP_BOX=1` `HEAP_CLASSES=0xC0` `C7_HOT=1`): ≈34.1M ops/s、Tiny lane failed 警告が発生(要調査)。
- Mixed 161024B (iters=20k, ws=256)
- TinyHeap OFF: ≈46.8M ops/s。
- C7 のみ TinyHeap (`HEAP_CLASSES=0x80`): ≈39.4M ops/sTiny lane failed 警告あり)。
- C6+C7 TinyHeap (`HEAP_CLASSES=0xC0`): ≈33.8M ops/sTiny lane failed 警告あり)。
- メモ: C6/C7 を TinyHeap に載せた際に Tiny lane failed 警告が出るケースがある。現状は A/B 計測を優先し、次フェーズで lane 判定の整合・TinyHeap fallback の整理が必要。
Phase 9: Tiny lane 判定の整理TinyHeap を「成功」とみなす)
--------------------------------------------------------
- 問題: C6/C7 を TinyHeap に載せた mixed ワークロードで `Tiny lane failed` 警告が出ていたGate 目線で Tiny が失敗扱いになっていた。TLS SLL は踏んでいないので、TinyHeap 成功を Tiny lane 成功として扱うのが正しい。
- 変更 (core/box/hak_alloc_api.inc.h):
- `hak_alloc_at` に Tiny route 状態を保持するフラグclass_idx / TinyHeap route on/offを追加。
- Tiny front が NULL でも、TinyHeap route が有効なクラスは TinyHeap を直接試し、成功したら Tiny lane 成功として即 return。
- Tiny lane 失敗ログは「TinyHeap route off かつ tiny_tried」時のみ出す。TinyHeap route の NULL はベンチ用フォールバック扱いで静かに ENOMEM を返す。
- 結果 (警告抑止後、Release, iters=20k, ws=256):
- C6 偏重 (min=257 max=768): OFF≈47.8M / C6のみ TinyHeap≈39.2M / C6+C7≈31.3M(警告なし)。
- Mixed 161024B: OFF≈47.6M / C7のみ TinyHeap≈36.9M / C6+C7≈30.3M(警告なし)。
- 今後: TinyHeap route の性能はまだ OFF より下がるケースがあるため、slow_prepare/hit 率の改善や C6 向け最適化を別フェーズで実施する。
今後の拡張ステップ
------------------
- C5〜C6 を TinyHeapBox に移す際は `tiny_heap_alloc_class_fast()` を流用し、Box 境界 (ページ補給/返却) の 1 箇所化を維持する。

View File

@ -30,19 +30,19 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \
core/box/ss_hot_prewarm_box.h core/box/hak_alloc_api.inc.h \
core/box/../hakmem_tiny.h core/box/../hakmem_pool.h \
core/box/../hakmem_smallmid.h core/box/tiny_heap_env_box.h \
core/box/c7_hotpath_env_box.h core/box/tiny_c7_hotbox.h \
core/box/tiny_heap_box.h core/box/../hakmem_tiny_superslab.h \
core/box/c7_hotpath_env_box.h core/box/tiny_heap_box.h \
core/box/../hakmem_tiny_superslab.h \
core/box/../superslab/superslab_inline.h core/box/../tiny_tls.h \
core/box/../hakmem_tiny_superslab.h core/box/../tiny_box_geometry.h \
core/box/mid_large_config_box.h core/box/../hakmem_config.h \
core/box/../hakmem_features.h core/box/hak_free_api.inc.h \
core/hakmem_tiny_superslab.h core/box/../hakmem_trace_master.h \
core/box/front_gate_v2.h core/box/external_guard_box.h \
core/box/../hakmem_stats_master.h core/box/ss_slab_meta_box.h \
core/box/../superslab/superslab_types.h core/box/slab_freelist_atomic.h \
core/box/fg_tiny_gate_box.h core/box/tiny_free_gate_box.h \
core/box/ptr_type_box.h core/box/ptr_conversion_box.h \
core/box/tiny_ptr_bridge_box.h \
core/box/tiny_c7_hotbox.h core/box/mid_large_config_box.h \
core/box/../hakmem_config.h core/box/../hakmem_features.h \
core/box/hak_free_api.inc.h core/hakmem_tiny_superslab.h \
core/box/../hakmem_trace_master.h core/box/front_gate_v2.h \
core/box/external_guard_box.h core/box/../hakmem_stats_master.h \
core/box/ss_slab_meta_box.h core/box/../superslab/superslab_types.h \
core/box/slab_freelist_atomic.h core/box/fg_tiny_gate_box.h \
core/box/tiny_free_gate_box.h core/box/ptr_type_box.h \
core/box/ptr_conversion_box.h core/box/tiny_ptr_bridge_box.h \
core/box/../hakmem_tiny_superslab_internal.h \
core/box/../hakmem_build_flags.h core/box/../box/ss_hot_cold_box.h \
core/box/../box/../superslab/superslab_types.h \
@ -167,13 +167,13 @@ core/box/../hakmem_pool.h:
core/box/../hakmem_smallmid.h:
core/box/tiny_heap_env_box.h:
core/box/c7_hotpath_env_box.h:
core/box/tiny_c7_hotbox.h:
core/box/tiny_heap_box.h:
core/box/../hakmem_tiny_superslab.h:
core/box/../superslab/superslab_inline.h:
core/box/../tiny_tls.h:
core/box/../hakmem_tiny_superslab.h:
core/box/../tiny_box_geometry.h:
core/box/tiny_c7_hotbox.h:
core/box/mid_large_config_box.h:
core/box/../hakmem_config.h:
core/box/../hakmem_features.h: