diff --git a/AGENTS.md b/AGENTS.md index c2f9a14d..2b6eb3c2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -81,6 +81,29 @@ この AGENTS.md は、箱理論の適用・コーディング・デバッグ・A/B 評価の“共通言語”です。新しい最適化や経路を足す前に、まず箱と境界を設計してから手を動かしましょう。 +--- + +## Learning Layer(ACE / ELO / Learner)の箱化ポリシー + +ACE/ELO/CAP Learner などの「学習する機能」も、Tiny や Superslab と同様に Box として扱います。 +ホットパスを汚さず、いつでも FROZEN/OFF に戻せるようにすることが原則です。 + +- 学習は上層の箱に閉じ込める + - L0 Tiny / L1 Superslab / TLS SLL / Remote Queue は **学習ロジックを持たない**。 + - ELO / ACE Controller / CAP Learner は「ポリシー箱」として、ノブやしきい値だけを更新する。 + - ホットパス側は「現在のポリシー値」を読むだけにし、学習の有無を意識しない。 + +- FROZEN / LEARN / OBSERVE を明確に分ける + - FROZEN: 学習 OFF。固定ポリシーのみ使用(デフォルト運用)。 + - LEARN: バックグラウンドでポリシー更新を行う(ベンチ / 研究用)。 + - OBSERVE: Tiny などの下層の箱を「観測だけ」するモード(動作は変えない)。 + - モード切り替えは `HAKMEM_MODE` / `HAKMEM_ACE_ENABLED` / `HAKMEM_LEARN` 等の ENV から行い、いつでも戻せるようにする。 + +- ドキュメントと設計の窓口 + - 学習レイヤ全体の構造と責務は `docs/analysis/LEARNING_LAYER_OVERVIEW.md` にまとめる。 + - 各学習 Box(ELO / ACE Controller / CAP Learner)の詳細仕様や A/B 結果は、docs/analysis / docs/benchmarks / docs/paper 配下に箱ごとに整理する。 + - AGENTS.md では「学習は必ず別箱」「ホットパスを汚さない」「ENV で切り戻せる」というルールだけを守る。 + --- diff --git a/HAKMEM_ARCHITECTURE_OVERVIEW.md b/HAKMEM_ARCHITECTURE_OVERVIEW.md index 21ec5ff0..31e1f6f5 100644 --- a/HAKMEM_ARCHITECTURE_OVERVIEW.md +++ b/HAKMEM_ARCHITECTURE_OVERVIEW.md @@ -35,7 +35,9 @@ HAKMEMは**4層アーキテクチャ**で設計されています: │ - Bundle-based refill (バンドル単位でリフィル) │ │ - CAP学習 (ヒット率ベースで容量自動調整) │ │ │ -│ [ACE Controller] 学習エンジン (Adaptive Control Engine) │ +│ [ACE Controller] 学習エンジン │ +│ - ACE = Agentic Context Engineering │ +│ (実装コンテキストでは Adaptive Control/Cache Engine) │ │ - CAP学習: ヒット率 vs 目標値 → CAP ±Δ │ │ - W_MAX学習: UCB1 bandit + Canary deployment │ │ - DYN1自動割り当て: サイズヒストグラムからピーク検出 │ diff --git a/README.md b/README.md index 3dfecfed..84685a1a 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ - `tests/{unit,integration,stress}/` - Tests by type - **Details**: `FOLDER_REORGANIZATION_2025_11_01.md` -### ✅ ACE Learning Layer Phase 1 Complete (Adaptive Control Engine) +### ✅ ACE Learning Layer Phase 1 Complete (ACE = Agentic Context Engineering / Adaptive Control Engine) - **Status**: Phase 1 Infrastructure COMPLETE ✅ (2025-11-01) - **Goal**: Fix weak workloads with adaptive learning - Fragmentation stress: 3.87 → 10-20 M ops/s (2.6-5.2x target) diff --git a/core/box/hak_alloc_api.inc.h b/core/box/hak_alloc_api.inc.h index 1992e818..8711f3a7 100644 --- a/core/box/hak_alloc_api.inc.h +++ b/core/box/hak_alloc_api.inc.h @@ -32,6 +32,10 @@ inline void* hak_alloc_at(size_t size, hak_callsite_t site) { #if HAKMEM_DEBUG_TIMING HKM_TIME_START(t0); #endif + static _Atomic int g_hak_alloc_at_trace = 0; + if (atomic_fetch_add_explicit(&g_hak_alloc_at_trace, 1, memory_order_relaxed) < 128) { + HAK_TRACE("[hak_alloc_at_enter]\n"); + } if (!g_initialized) hak_init(); // Adaptive CAS: Register thread on first allocation diff --git a/core/box/hak_core_init.inc.h b/core/box/hak_core_init.inc.h index 057b008a..f015b5fb 100644 --- a/core/box/hak_core_init.inc.h +++ b/core/box/hak_core_init.inc.h @@ -37,6 +37,7 @@ void hak_init(void) { } static void hak_init_impl(void) { + HAK_TRACE("[init_impl_enter]\n"); g_init_thread = pthread_self(); atomic_store_explicit(&g_initializing, 1, memory_order_release); @@ -44,6 +45,7 @@ static void hak_init_impl(void) { // This MUST be called before ANY allocation (Tiny/Mid/Large/Learner) // dlsym() initializes function pointers to real libc (bypasses LD_PRELOAD) hkm_syscall_init(); + HAK_TRACE("[init_impl_after_syscall_init]\n"); // CRITICAL FIX (BUG #10): Pre-detect jemalloc ONCE during init, not on hot path! // This prevents infinite recursion: malloc → hak_jemalloc_loaded → dlopen → malloc → ... @@ -58,6 +60,7 @@ static void hak_init_impl(void) { HAKMEM_LOG("Detected jemalloc: will avoid interposing\n"); } } + HAK_TRACE("[init_impl_after_jemalloc_probe]\n"); // Optional: one-shot SIGSEGV backtrace for early crash diagnosis do { diff --git a/core/box/hak_free_api.inc.h b/core/box/hak_free_api.inc.h index 76a0cc5d..74e9ce21 100644 --- a/core/box/hak_free_api.inc.h +++ b/core/box/hak_free_api.inc.h @@ -82,6 +82,10 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) { #if HAKMEM_DEBUG_TIMING HKM_TIME_START(t0); #endif + static _Atomic int g_hak_free_at_trace = 0; + if (atomic_fetch_add_explicit(&g_hak_free_at_trace, 1, memory_order_relaxed) < 128) { + HAK_TRACE("[hak_free_at_enter]\n"); + } (void)site; (void)size; int fg_misclass = 0; // Set when FG said Tiny but registry rejects // Optional lightweight trace of early free calls (first few only) diff --git a/core/box/hak_wrappers.inc.h b/core/box/hak_wrappers.inc.h index 11719980..abb250d6 100644 --- a/core/box/hak_wrappers.inc.h +++ b/core/box/hak_wrappers.inc.h @@ -88,6 +88,10 @@ void* malloc(size_t size) { #ifndef NDEBUG uint64_t count = atomic_fetch_add(&malloc_count, 1); #endif + static _Atomic int g_wrap_malloc_trace_count = 0; + if (atomic_fetch_add_explicit(&g_wrap_malloc_trace_count, 1, memory_order_relaxed) < 256) { + HAK_TRACE("[wrap_malloc_enter]\n"); + } // NDEBUG: malloc_count increment disabled - removes 27.55% bottleneck // Phase 20-2: BenchFast mode (structural ceiling measurement) @@ -219,6 +223,10 @@ void* malloc(size_t size) { } void free(void* ptr) { + static _Atomic int g_wrap_free_trace_count = 0; + if (atomic_fetch_add_explicit(&g_wrap_free_trace_count, 1, memory_order_relaxed) < 256) { + HAK_TRACE("[wrap_free_enter]\n"); + } atomic_fetch_add_explicit(&g_free_wrapper_calls, 1, memory_order_relaxed); if (!ptr) return; @@ -449,6 +457,10 @@ void free(void* ptr) { } void* calloc(size_t nmemb, size_t size) { + static _Atomic int g_wrap_calloc_trace_count = 0; + if (atomic_fetch_add_explicit(&g_wrap_calloc_trace_count, 1, memory_order_relaxed) < 128) { + HAK_TRACE("[wrap_calloc_enter]\n"); + } // CRITICAL FIX (BUG #8): Increment lock depth FIRST, before ANY libc calls g_hakmem_lock_depth++; @@ -522,6 +534,10 @@ void* calloc(size_t nmemb, size_t size) { } void* realloc(void* ptr, size_t size) { + static _Atomic int g_wrap_realloc_trace_count = 0; + if (atomic_fetch_add_explicit(&g_wrap_realloc_trace_count, 1, memory_order_relaxed) < 128) { + HAK_TRACE("[wrap_realloc_enter]\n"); + } if (g_hakmem_lock_depth > 0) { wrapper_record_fallback(FB_LOCKDEPTH, "[wrap] libc realloc: lockdepth\n"); extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } int realloc_init_wait = hak_init_wait_for_ready(); if (__builtin_expect(realloc_init_wait <= 0, 0)) { wrapper_record_fallback(FB_INIT_WAIT_FAIL, "[wrap] libc realloc: init_wait\n"); extern void* __libc_realloc(void*, size_t); return __libc_realloc(ptr, size); } diff --git a/core/box/ss_allocation_box.c b/core/box/ss_allocation_box.c index 985ec9a4..94591b28 100644 --- a/core/box/ss_allocation_box.c +++ b/core/box/ss_allocation_box.c @@ -9,6 +9,7 @@ #include "ss_ace_box.h" #include "ss_slab_management_box.h" #include "hakmem_super_registry.h" +#include "ss_addr_map_box.h" #include "hakmem_tiny_config.h" #include "hakmem_policy.h" // Phase E3-1: Access FrozenPolicy for never-free policy #include "tiny_region_id.h" @@ -296,11 +297,25 @@ SuperSlab* superslab_allocate(uint8_t size_class) { // Phase 1: Register SuperSlab in global registry for fast lookup // CRITICAL: Register AFTER full initialization (ss structure is ready) uintptr_t base = (uintptr_t)ss; - if (!hak_super_register(base, ss)) { + int reg_ok = hak_super_register(base, ss); + if (!reg_ok) { // Registry full - this is a fatal error fprintf(stderr, "HAKMEM FATAL: SuperSlab registry full, cannot register %p\n", ss); // Still return ss to avoid memory leak, but lookups may fail } + do { + static _Atomic uint32_t g_ss_reg_log_shot = 0; + uint32_t shot = atomic_fetch_add_explicit(&g_ss_reg_log_shot, 1, memory_order_relaxed); + if (shot < 4) { + fprintf(stderr, + "[SS_REG_DEBUG] class=%u ss=%p reg_ok=%d map_count=%zu\n", + (unsigned)size_class, + (void*)ss, + reg_ok, + g_ss_addr_map.count); + fflush(stderr); + } + } while (0); return ss; } diff --git a/core/box/ss_tls_hint_box.c b/core/box/ss_tls_hint_box.c.old similarity index 100% rename from core/box/ss_tls_hint_box.c rename to core/box/ss_tls_hint_box.c.old diff --git a/core/box/ss_tls_hint_box.h b/core/box/ss_tls_hint_box.h.old similarity index 100% rename from core/box/ss_tls_hint_box.h rename to core/box/ss_tls_hint_box.h.old diff --git a/core/box/tls_sll_box.h b/core/box/tls_sll_box.h index 9ce38bfa..34731723 100644 --- a/core/box/tls_sll_box.h +++ b/core/box/tls_sll_box.h @@ -35,6 +35,7 @@ #include "../ptr_trace.h" #include "../tiny_debug_ring.h" #include "../hakmem_super_registry.h" +#include "ss_addr_map_box.h" #include "../superslab/superslab_inline.h" #include "tiny_next_ptr_box.h" #include "tiny_header_box.h" // Header Box: Single Source of Truth for header operations @@ -250,6 +251,10 @@ static inline void tls_sll_diag_next(int class_idx, hak_base_ptr_t base, hak_bas static inline bool tls_sll_push_impl(int class_idx, hak_base_ptr_t ptr, uint32_t capacity, const char* where) { + static _Atomic int g_tls_push_trace = 0; + if (atomic_fetch_add_explicit(&g_tls_push_trace, 1, memory_order_relaxed) < 256) { + HAK_TRACE("[tls_sll_push_impl_enter]\n"); + } HAK_CHECK_CLASS_IDX(class_idx, "tls_sll_push"); // Class mask gate (narrow triage): if disallowed, reject push @@ -275,6 +280,7 @@ static inline bool tls_sll_push_impl(int class_idx, hak_base_ptr_t ptr, uint32_t void* raw_ptr = HAK_BASE_TO_RAW(ptr); // Detect meta/class mismatch on push (first few only). + bool push_valid = true; do { static _Atomic uint32_t g_tls_sll_push_meta_mis = 0; struct SuperSlab* ss = hak_super_lookup(raw_ptr); @@ -283,6 +289,7 @@ static inline bool tls_sll_push_impl(int class_idx, hak_base_ptr_t ptr, uint32_t if (sidx >= 0 && sidx < ss_slabs_capacity(ss)) { uint8_t meta_cls = ss->slabs[sidx].class_idx; if (meta_cls < TINY_NUM_CLASSES && meta_cls != (uint8_t)class_idx) { + push_valid = false; uint32_t n = atomic_fetch_add_explicit(&g_tls_sll_push_meta_mis, 1, memory_order_relaxed); if (n < 4) { fprintf(stderr, @@ -295,8 +302,27 @@ static inline bool tls_sll_push_impl(int class_idx, hak_base_ptr_t ptr, uint32_t fflush(stderr); } } + } else { + push_valid = false; + static _Atomic uint32_t g_tls_sll_push_no_ss = 0; + uint32_t n = atomic_fetch_add_explicit(&g_tls_sll_push_no_ss, 1, memory_order_relaxed); + if (n < 4) { + extern int g_super_reg_initialized; + extern SSAddrMap g_ss_addr_map; + fprintf(stderr, + "[TLS_SLL_PUSH_NO_SS] cls=%d base=%p from=%s reg_init=%d map_count=%zu\n", + class_idx, + raw_ptr, + where ? where : "(null)", + g_super_reg_initialized, + g_ss_addr_map.count); + fflush(stderr); + } } } while (0); + if (!push_valid) { + return false; // Drop malformed pointer instead of corrupting TLS SLL + } #if HAKMEM_TINY_HEADER_CLASSIDX // Validate header on push - detect blocks pushed without header write @@ -492,6 +518,10 @@ static inline bool tls_sll_push_impl(int class_idx, hak_base_ptr_t ptr, uint32_t static inline bool tls_sll_pop_impl(int class_idx, hak_base_ptr_t* out, const char* where) { + static _Atomic int g_tls_pop_trace = 0; + if (atomic_fetch_add_explicit(&g_tls_pop_trace, 1, memory_order_relaxed) < 256) { + HAK_TRACE("[tls_sll_pop_impl_enter]\n"); + } HAK_CHECK_CLASS_IDX(class_idx, "tls_sll_pop"); // Class mask gate: if disallowed, behave as empty if (__builtin_expect(((g_tls_sll_class_mask & (1u << class_idx)) == 0), 0)) { @@ -594,7 +624,33 @@ static inline bool tls_sll_pop_impl(int class_idx, hak_base_ptr_t* out, const ch // PERF DEBUG: Count header corruption resets static _Atomic uint64_t g_hdr_reset_count = 0; uint64_t cnt = atomic_fetch_add_explicit(&g_hdr_reset_count, 1, memory_order_relaxed); - if (cnt % 10000 == 0) { + // Narrow diagnostics for early shots to root-cause corruption. + static _Atomic uint32_t g_hdr_reset_diag = 0; + uint32_t shot = atomic_fetch_add_explicit(&g_hdr_reset_diag, 1, memory_order_relaxed); + if (shot < 8) { + SuperSlab* ss_diag = hak_super_lookup(raw_base); + int slab_idx = ss_diag ? slab_index_for(ss_diag, raw_base) : -1; + uint8_t meta_cls = 0xff; + if (ss_diag && slab_idx >= 0 && slab_idx < ss_slabs_capacity(ss_diag)) { + meta_cls = ss_diag->slabs[slab_idx].class_idx; + } + void* raw_next_diag = NULL; + PTR_NEXT_READ("tls_hdr_reset_diag", class_idx, raw_base, 0, raw_next_diag); + fprintf(stderr, + "[TLS_SLL_HDR_RESET] shot=%u cls=%d base=%p got=0x%02x expect=0x%02x " + "next=%p meta_cls=%u slab_idx=%d last_writer=%s last_push=%p count=%llu\n", + shot + 1, + class_idx, + raw_base, + got, + expect, + raw_next_diag, + (unsigned)meta_cls, + slab_idx, + g_tls_sll_last_writer[class_idx] ? g_tls_sll_last_writer[class_idx] : "(null)", + HAK_BASE_TO_RAW(s_tls_sll_last_push[class_idx]), + (unsigned long long)cnt); + } else if (cnt % 10000 == 0) { fprintf(stderr, "[TLS_SLL_HDR_RESET] cls=%d base=%p got=0x%02x expect=0x%02x count=%llu\n", class_idx, raw_base, got, expect, (unsigned long long)cnt); } @@ -811,9 +867,9 @@ static inline bool tls_sll_push_guarded(int class_idx, hak_base_ptr_t ptr, uint3 tls_sll_pop_impl((cls), (out), __func__) #else # define tls_sll_push(cls, ptr, cap) \ - tls_sll_push_impl((cls), (ptr), (cap), NULL) + tls_sll_push_impl((cls), (ptr), (cap), __func__) # define tls_sll_pop(cls, out) \ - tls_sll_pop_impl((cls), (out), NULL) + tls_sll_pop_impl((cls), (out), __func__) #endif -#endif // TLS_SLL_BOX_H \ No newline at end of file +#endif // TLS_SLL_BOX_H diff --git a/core/hakmem.c b/core/hakmem.c index 09f1c54e..3efc8a78 100644 --- a/core/hakmem.c +++ b/core/hakmem.c @@ -106,6 +106,7 @@ static uint64_t get_rss_kb(void); #include "box/hak_free_api.inc.h" __attribute__((constructor)) static void hakmem_ctor_install_segv(void) { + HAK_TRACE("[ctor1_hakmem_ctor_install_segv]\n"); const char* dbg = getenv("HAKMEM_DEBUG_SEGV"); if (dbg && atoi(dbg) != 0) { #if !HAKMEM_BUILD_RELEASE @@ -160,12 +161,14 @@ static inline void hak_ld_env_init(void) { } __attribute__((constructor)) static void hak_ld_env_ctor(void) { + HAK_TRACE("[ctor2_hak_ld_env_ctor]\n"); hak_ld_env_init(); } // Priority-2 Refactoring: Initialize ENV cache at library load time (eliminate ~2000 syscalls/sec) __attribute__((constructor)) static void hak_env_cache_ctor(void) { + HAK_TRACE("[ctor3_hak_env_cache_ctor]\n"); hakmem_env_cache_init(); } @@ -181,6 +184,7 @@ static int g_force_libc_alloc = -1; // 1=force libc, 0=use hakmem, -1=uninitial #endif __attribute__((constructor)) static void hak_force_libc_ctor(void) { + HAK_TRACE("[ctor4_hak_force_libc_ctor]\n"); // Cache FORCE_LIBC and WRAP_TINY at load time to avoid hot-path getenv #ifndef HAKMEM_FORCE_LIBC_ALLOC_BUILD if (g_force_libc_alloc < 0) { @@ -427,4 +431,4 @@ void hak_print_stats(void) { // ============================================================================ #include "box/hak_wrappers.inc.h" -// (wrappers moved to box/hak_wrappers.inc.h) \ No newline at end of file +// (wrappers moved to box/hak_wrappers.inc.h) diff --git a/core/hakmem_shared_pool.c b/core/hakmem_shared_pool.c index 54468e39..f22cbbee 100644 --- a/core/hakmem_shared_pool.c +++ b/core/hakmem_shared_pool.c @@ -569,13 +569,30 @@ int sp_freelist_pop_lockfree(int class_idx, SharedSSMeta** meta_out, int* slot_i // Allocator helper for SuperSlab (Phase 9-2 Task 1) +// NOTE: class_idx MUST be a valid tiny class (0-7). Passing an out-of-range +// value previously went through superslab_allocate(8), which overflowed +// g_ss_ace[] and could corrupt neighboring globals, leading to missing +// registry entries and TLS SLL header corruption. SuperSlab* -sp_internal_allocate_superslab(void) +sp_internal_allocate_superslab(int class_idx) { + do { + static _Atomic uint32_t g_sp_alloc_log = 0; + uint32_t shot = atomic_fetch_add_explicit(&g_sp_alloc_log, 1, memory_order_relaxed); + if (shot < 4) { + fprintf(stderr, "[SP_INTERNAL_ALLOC] class_idx=%d\n", class_idx); + fflush(stderr); + } + } while (0); + + // Clamp to valid range to avoid out-of-bounds access inside superslab_allocate(). + if (class_idx < 0 || class_idx >= TINY_NUM_CLASSES_SS) { + class_idx = TINY_NUM_CLASSES_SS - 1; + } + // Use legacy backend to allocate a SuperSlab (malloc-based) extern SuperSlab* superslab_allocate(uint8_t size_class); - // Pass 8 as class_idx (dummy, will be overwritten) or larger - SuperSlab* ss = superslab_allocate(8); + SuperSlab* ss = superslab_allocate((uint8_t)class_idx); if (!ss) { return NULL; } @@ -596,7 +613,7 @@ shared_pool_acquire_superslab(void) { // Phase 12: Legacy wrapper? // This function seems to be a direct allocation bypass. - return sp_internal_allocate_superslab(); + return sp_internal_allocate_superslab(0); } void sp_fix_geometry_if_needed(SuperSlab* ss, int slab_idx, int class_idx) { diff --git a/core/hakmem_shared_pool_acquire.c b/core/hakmem_shared_pool_acquire.c index 020a672a..6ede497b 100644 --- a/core/hakmem_shared_pool_acquire.c +++ b/core/hakmem_shared_pool_acquire.c @@ -344,7 +344,7 @@ stage2_fallback: } pthread_mutex_unlock(&g_shared_pool.alloc_lock); - SuperSlab* allocated_ss = sp_internal_allocate_superslab(); + SuperSlab* allocated_ss = sp_internal_allocate_superslab(class_idx); // Re-acquire the alloc_lock if (g_lock_stats_enabled == 1) { diff --git a/core/hakmem_shared_pool_internal.h b/core/hakmem_shared_pool_internal.h index 0dcec158..06994c27 100644 --- a/core/hakmem_shared_pool_internal.h +++ b/core/hakmem_shared_pool_internal.h @@ -36,7 +36,7 @@ void sp_stage_stats_init(void); // Internal Helpers (Shared between acquire/release/pool) void shared_pool_ensure_capacity_unlocked(uint32_t min_capacity); -SuperSlab* sp_internal_allocate_superslab(void); +SuperSlab* sp_internal_allocate_superslab(int class_idx); // Slot & Meta Helpers int sp_slot_mark_active(SharedSSMeta* meta, int slot_idx, int class_idx); diff --git a/core/hakmem_super_registry.h b/core/hakmem_super_registry.h index 1b45a1e8..8d86f9e1 100644 --- a/core/hakmem_super_registry.h +++ b/core/hakmem_super_registry.h @@ -124,6 +124,29 @@ static inline SuperSlab* hak_super_lookup(void* ptr) { // Replaces old linear probing (50-80 cycles → 10-20 cycles) SuperSlab* ss = ss_map_lookup(&g_ss_addr_map, ptr); + // Fallback: If hash map misses (e.g., map not populated yet), probe the + // legacy registry table to avoid NULL for valid SuperSlabs. + if (__builtin_expect(ss == NULL, 0)) { + uintptr_t p = (uintptr_t)ptr; + for (int lg = SUPERSLAB_LG_MIN; lg <= SUPERSLAB_LG_MAX; lg++) { + uintptr_t base = p & ~(((uintptr_t)1 << lg) - 1); + int h = hak_super_hash(base, lg); + for (int i = 0; i < SUPER_MAX_PROBE; i++) { + SuperRegEntry* e = &g_super_reg[(h + i) & SUPER_REG_MASK]; + uintptr_t reg_base = atomic_load_explicit(&e->base, memory_order_acquire); + if (reg_base == 0) { + break; // empty slot + } + if (reg_base == base && e->lg_size == lg) { + ss = atomic_load_explicit(&e->ss, memory_order_acquire); + goto reg_probe_done; + } + } + } +reg_probe_done: + ; + } + #if !HAKMEM_BUILD_RELEASE // Debug logging (ENV-gated) static __thread int s_dbg = -1; diff --git a/core/hakmem_tiny_phase6_wrappers_box.inc b/core/hakmem_tiny_phase6_wrappers_box.inc index e29ea405..e13dd391 100644 --- a/core/hakmem_tiny_phase6_wrappers_box.inc +++ b/core/hakmem_tiny_phase6_wrappers_box.inc @@ -23,6 +23,10 @@ // Export wrapper functions for hakmem.c to call // Phase 6-1.7 Optimization: Remove diagnostic overhead, rely on LTO for inlining void* hak_tiny_alloc_fast_wrapper(size_t size) { + static _Atomic int g_alloc_fast_trace = 0; + if (atomic_fetch_add_explicit(&g_alloc_fast_trace, 1, memory_order_relaxed) < 128) { + HAK_TRACE("[tiny_alloc_fast_wrapper_enter]\n"); + } // Phase E5: Ultra fast path (8-instruction alloc, bypasses all layers) // Enable with: HAKMEM_ULTRA_FAST_PATH=1 (compile-time) #if HAKMEM_ULTRA_FAST_PATH diff --git a/core/hakmem_trace.h b/core/hakmem_trace.h index f78e70c4..5c1f34ac 100644 --- a/core/hakmem_trace.h +++ b/core/hakmem_trace.h @@ -18,5 +18,19 @@ # define HAK_TP3(name,a1,a2,a3) do{ (void)(a1); (void)(a2); (void)(a3); }while(0) #endif -#endif // HAKMEM_TRACE_H +// Lightweight printf-free tracing for early-init / SEGV triage. +// Enabled only when built with -DHAKMEM_DEBUG_INIT_TRACE=1. +#ifdef HAKMEM_DEBUG_INIT_TRACE +# include +# include +static inline void hak_trace(const char* msg) +{ + if (!msg) return; + write(2, msg, (size_t)strlen(msg)); +} +# define HAK_TRACE(msg) hak_trace(msg) +#else +# define HAK_TRACE(msg) ((void)0) +#endif +#endif // HAKMEM_TRACE_H diff --git a/core/superslab_allocate.c b/core/superslab_allocate.c index f4f03b11..8fbd5dd2 100644 --- a/core/superslab_allocate.c +++ b/core/superslab_allocate.c @@ -4,6 +4,7 @@ // Date: 2025-11-28 #include "hakmem_tiny_superslab_internal.h" +#include "box/ss_addr_map_box.h" // ============================================================================ // SuperSlab Allocation (2MB aligned) @@ -223,11 +224,25 @@ SuperSlab* superslab_allocate(uint8_t size_class) { // Phase 1: Register SuperSlab in global registry for fast lookup // CRITICAL: Register AFTER full initialization (ss structure is ready) uintptr_t base = (uintptr_t)ss; - if (!hak_super_register(base, ss)) { + int reg_ok = hak_super_register(base, ss); + if (!reg_ok) { // Registry full - this is a fatal error fprintf(stderr, "HAKMEM FATAL: SuperSlab registry full, cannot register %p\n", ss); // Still return ss to avoid memory leak, but lookups may fail } + do { + static _Atomic uint32_t g_ss_reg_log_shot = 0; + uint32_t shot = atomic_fetch_add_explicit(&g_ss_reg_log_shot, 1, memory_order_relaxed); + if (shot < 4) { + fprintf(stderr, + "[SS_REG_DEBUG] class=%u ss=%p reg_ok=%d map_count=%zu\n", + (unsigned)size_class, + (void*)ss, + reg_ok, + g_ss_addr_map.count); + fflush(stderr); + } + } while (0); return ss; } @@ -241,6 +256,19 @@ void superslab_free(SuperSlab* ss) { return; // Invalid SuperSlab } + do { + static _Atomic uint32_t g_ss_free_log = 0; + uint32_t shot = atomic_fetch_add_explicit(&g_ss_free_log, 1, memory_order_relaxed); + if (shot < 6) { + fprintf(stderr, "[SS_FREE_EARLY] ss=%p lg_size=%d active_slabs=%u map_count=%zu\n", + (void*)ss, + ss->lg_size, + ss->active_slabs, + g_ss_addr_map.count); + fflush(stderr); + } + } while (0); + // ADD DEBUG LOGGING static __thread int dbg = -1; #if HAKMEM_BUILD_RELEASE diff --git a/docs/ACE_LEARNING_LAYER.md b/docs/ACE_LEARNING_LAYER.md index 85bd2d06..29e7b25a 100644 --- a/docs/ACE_LEARNING_LAYER.md +++ b/docs/ACE_LEARNING_LAYER.md @@ -1,4 +1,7 @@ -# ACE Learning Layer - Adaptive Control Engine +# ACE Learning Layer - ACE (Agentic Context Engineering) + +> 実装上の役割としては「Adaptive Control Engine」として L1 レイヤのノブ調整を行うが、 +> ACE 自体の意味は Agentic Context Engineering(観測→意思決定→適用のエージェント型ループ)として統一する。 **目的**: 断片化・巨大WS・reallocの弱点を学習で潰して"つよつよ"にする 💪 diff --git a/docs/analysis/LEARNING_LAYER_OVERVIEW.md b/docs/analysis/LEARNING_LAYER_OVERVIEW.md new file mode 100644 index 00000000..86278e4b --- /dev/null +++ b/docs/analysis/LEARNING_LAYER_OVERVIEW.md @@ -0,0 +1,150 @@ +# Learning Layer Overview (ACE / ELO / CAP Learner) + +このドキュメントは、hakmem 内の「学習する箱」を縦に貫いて整理した総覧です。 +実装は複数のファイル・フェーズに分かれていますが、Box Theory の観点では次の 3 つの箱に分解できます。 + +--- + +## 1. Box A: ELO + Evolution (L2 / BigCache / THP) + +**範囲** +- サイズ帯: おおむね `≥ 2MB`(BigCache / THP / batch madvise が関わる領域) +- 箱の責務: + - 大きな割り当てに対する `mmap` 閾値(いつ BigCache / THP を使うか)の選択 + - 戦略候補(しきい値)間の比較と「勝ち残り」管理 + +**実装ファイル** +- `core/hakmem_elo.{c,h}` — ELO Rating Strategy Selection(複数のしきい値候補にレーティング) +- `core/hakmem_evo.h` — LEARN → FROZEN → CANARY ライフサイクル +- `core/hakmem_config.{c,h}` — `HAKMEM_MODE` と Features(`HAKMEM_FEATURE_ELO`, `HAKMEM_FEATURE_EVOLUTION`) +- `core/box/mid_large_config_box.h` — `MID_LARGE_ELO_ENABLED` マクロ(PGO/通常モード) + +**モード** +- FROZEN(デフォルト) + - `HAKMEM_MODE=balanced` / `fast` では `features.learning` に ELO は含まれるが、`evo_phase = EVO_PHASE_FROZEN`。 + - 戦略は事前に決めたしきい値を使い続け、ランタイムでのレーティング更新は行わない。 +- LEARN(開発・研究用) + - `HAKMEM_MODE=learning` / `research` で `HAKMEM_FEATURE_EVOLUTION` が有効。 + - ELO レーティングと Evolution 状態機械が動作し、しきい値を動的に調整。 + +**Box Theory 観点** +- Hot path(実際の割り当て)は「現在のしきい値」を見るだけ。 +- レーティング更新・進化は **完全にオフパス(バックグラウンド)** の箱に閉じ込める。 +- 切り戻しは: + - `HAKMEM_MODE` 変更、または `HAKMEM_DISABLE_ELO=1` で ELO を丸ごと無効化。 + +--- + +## 2. Box B: ACE Controller (L1 Mid/Large, UCB1-based Knob Tuning) + +**範囲** +- サイズ帯: 1KB〜2MB(L1 ACE レイヤ: Mid / Large Pool) +- 箱の責務: + - Mid/Large Pool の TLS capacity / drain threshold / bundle width などの「ノブ」を UCB1 で自動調整。 + - 断片化ストレスや巨大ワーキングセットに対して、オフパスでキャッシュ構成を最適化。 + +**実装ファイル** +- `core/hakmem_ace_controller.{c,h}` — ACE Controller 本体 +- `core/hakmem_ace_metrics.{c,h}` — メトリクス収集箱(throughput, llc_miss, backlog 等) +- `core/hakmem_ace_ucb1.{c,h}` — UCB1 Multi-Armed Bandit 実装 +- `core/box/hak_core_init.inc.h` — `hkm_ace_controller_init()` / `hkm_ace_controller_start()` 呼び出し + +**起動条件(ENV)** +- `HAKMEM_ACE_ENABLED=1` で有効化(デフォルト 0) +- 主な補助 ENV: + - `HAKMEM_ACE_FAST_INTERVAL_MS`(デフォルト 500ms) + - `HAKMEM_ACE_SLOW_INTERVAL_MS`(デフォルト 30000ms) + - `HAKMEM_ACE_LOG_LEVEL`(0=off,1=info,2=debug) + +**挙動** +- 有効時: + - バックグラウンドで fast-loop / slow-loop を回し、`compute_reward()` の結果を UCB1 に渡してノブを更新。 + - Tiny / Mid / Large のホットパスは「現在のノブ値」を読むだけで、学習ロジックには触れない。 +- 無効時: + - `hkm_ace_controller_init()` が早期 return し、ACE に関連するオーバーヘッドはほぼゼロ。 + +**Box Theory 観点** +- ACE は「ポリシー箱」であり、実際の割り当て/解放箱には侵入しない。 +- 境界: + - ノブの読み出しは `mid_large_config_box` 等の **1 箇所** から行う。 + - メトリクスの書き込みは `hakmem_ace_metrics` に集約(alloc/free 側は軽量カウンタ更新のみ)。 + +--- + +## 3. Box C: CAP/W_MAX Learner + Tiny ACE Observer + +**範囲** +- Mid/Large Pool: + - クラス別 CAP(ページ数 / バンドル数)と W_MAX(許容丸め率)の自動調整。 +- Tiny: + - `hak_tiny_superslab_ace_observe_all()` による Tiny Superslab 利用状況の観測(Phase 8.4)。 + +**実装ファイル** +- `core/hakmem_learner.{c,h}` — CAP/W_MAX/THP 学習スレッド +- `core/hakmem_tiny_superslab.h` — Tiny Superslab 監視用 API(ACE Observer) +- `core/box/hak_core_init.inc.h` — `hkm_learner_init()` 呼び出し + +**起動条件(ENV)** +- 学習スレッド: + - `HAKMEM_LEARN=1` で有効化(デフォルト 0)。 +- Tiny ACE Observer: + - `HAKMEM_ACE_OBSERVE=1` で Tiny Superslab の観測を ON。 + - 追加で `HAKMEM_ACE_DEBUG=1` を付けると、観測呼び出しをログ出力。 + +**挙動** +- 学習スレッドは: + - 一定間隔(`HAKMEM_LEARN_WINDOW_MS`)でヒット率をサンプリング。 + - 目標ヒット率 (`HAKMEM_TARGET_HIT_MID/LARGE`) とのズレに応じて CAP を増減。 + - オプションで W_MAX 候補を UCB1 で試す(`HAKMEM_WMAX_LEARN=1`)。 +- Tiny ACE Observer は: + - Superslab / Tiny キャッシュの利用状況をスキャンし、後続の設計/学習に使う「観測専用箱」。 + - 現時点では Tiny の動作そのものは変えず、将来の ACE-Alloc 設計のための下準備。 + +**Box Theory 観点** +- CAP/W_MAX の調整は、`hakmem_learner` 箱の中だけで完結。 +- Mid/Large のホットパスは「現在の CAP / W_MAX」を見るだけで、学習状態を知らない。 +- Tiny は「Observer に観測される側」であり、ACE が Tiny のホットパスを直接いじらない設計になっている。 + +--- + +## 4. モードと組み合わせ(どこまで学習させるか) + +**グローバルモード (`HAKMEM_MODE`)** +- `minimal`: + - ELO/ACE/CAP Learner などの学習箱はすべて OFF。 +- `fast` / `balanced`(デフォルト): + - ELO: FROZEN(学習オフ、しきい値のみ利用) + - ACE Controller: `HAKMEM_ACE_ENABLED` が 1 のときのみ動作 + - CAP Learner: `HAKMEM_LEARN` が 1 のときのみ動作 +- `learning` / `research`: + - ELO: LEARN + EVOLUTION 有効 + - その他の箱も ENV に応じて積極的に動く前提。 + +**推奨パターン(論文用 / 評価用)** +- Baseline: + - `HAKMEM_MODE=balanced`、`HAKMEM_ACE_ENABLED=0`、`HAKMEM_LEARN=0` +- ACE only: + - `HAKMEM_MODE=balanced`、`HAKMEM_ACE_ENABLED=1`、`HAKMEM_LEARN=0` +- CAP/W_MAX only: + - `HAKMEM_MODE=balanced`、`HAKMEM_ACE_ENABLED=0`、`HAKMEM_LEARN=1` +- Full learning: + - `HAKMEM_MODE=learning`、`HAKMEM_ACE_ENABLED=1`、`HAKMEM_LEARN=1` + +各パターンのベンチ結果は、`docs/benchmarks/LEARNING_AB_RESULTS.md` に逐次追記していく想定です。 + +--- + +## 5. 関連ドキュメント + +- 概要・設計: + - `docs/ACE_LEARNING_LAYER.md` + - `docs/ACE_LEARNING_LAYER_PLAN.md` + - `docs/design/ARCHITECTURE_DESIGN.md` +- 詳細分析: + - `docs/analysis/ACE_INVESTIGATION_REPORT.md` + - `docs/analysis/ACE_POOL_ARCHITECTURE_INVESTIGATION.md` + - `docs/analysis/ENV_CLEANUP_ANALYSIS.md` +- 論文ドラフト: + - `docs/paper/ACE-Alloc/main.md` + - メモ用: `docs/paper/ACE_ALLOC_NOTES.md`(今後作成・拡充予定) + diff --git a/docs/archive/ACE_AND_SUPERSLAB.md b/docs/archive/ACE_AND_SUPERSLAB.md index c1729c6e..4b58a984 100644 --- a/docs/archive/ACE_AND_SUPERSLAB.md +++ b/docs/archive/ACE_AND_SUPERSLAB.md @@ -7,7 +7,7 @@ ## 🎯 現状:完全に独立 -### ACE(Adaptive Cache Engine)の範囲 +### ACE(Agentic Context Engineering / Adaptive Cache Engine)の範囲 **対象:** Mid Pool & Large Pool diff --git a/docs/benchmarks/LEARNING_AB_RESULTS.md b/docs/benchmarks/LEARNING_AB_RESULTS.md new file mode 100644 index 00000000..d803856f --- /dev/null +++ b/docs/benchmarks/LEARNING_AB_RESULTS.md @@ -0,0 +1,48 @@ +# Learning Features A/B Benchmark Results + +学習機能(ACE Controller / ELO / CAP/W_MAX Learner)の有無による性能差をまとめるためのファイルです。 +ベンチ実行のたびに「条件 + 結果」をここに追記していき、論文や設計検証の基礎データとして利用します。 + +--- + +## 記録フォーマット(推奨) + +- 共通メタデータ: + - `git` commit: `` + - Build: 例 `make bench_random_mixed_hakmem`, `HAKMEM_TINY_HEADERLESS=1` など + - Bench: 実行コマンド(引数含む) +- 環境: + - CPU/メモリ/コア数(簡易でOK) + - `HAKMEM_MODE` / `HAKMEM_ACE_ENABLED` / `HAKMEM_LEARN` / その他主要 ENV +- 結果: + - Throughput (M ops/s) + - Page faults / RSS(わかる範囲で) + - 備考(学習の収束有無、安定までの時間など) + +例: + +```text +[Run 2025-12-03] +- git: abcdef1 +- Build: make bench_random_mixed_hakmem +- Bench: HAKMEM_MODE=balanced HAKMEM_ACE_ENABLED=0 HAKMEM_LEARN=0 ./bench_random_mixed_hakmem 256 100000 4 +- Result: 72.3 M ops/s, PF=1.2e6, RSS=512MB +- Notes: Baseline (learning OFF) +``` + +```text +[Run 2025-12-03] +- git: abcdef1 +- Build: make bench_random_mixed_hakmem +- Bench: HAKMEM_MODE=balanced HAKMEM_ACE_ENABLED=1 HAKMEM_LEARN=0 ./bench_random_mixed_hakmem 256 100000 4 +- Result: 78.1 M ops/s, PF=1.1e6, RSS=520MB +- Notes: ACE Controller ON, UCB1 収束後に +8% 前後の改善 +``` + +--- + +## 現時点のメモ + +- まだ本格的な学習 A/B データはここに集約されていません。 +- すでに存在する分析レポート(`ACE_PHASE1_TEST_RESULTS.md`, `MID_LARGE_FINAL_AB_REPORT.md` など)の結果を、順次ここにも要約していくと、論文執筆時に参照しやすくなります。 + diff --git a/docs/paper/ACE_ALLOC_NOTES.md b/docs/paper/ACE_ALLOC_NOTES.md new file mode 100644 index 00000000..c5e91d9b --- /dev/null +++ b/docs/paper/ACE_ALLOC_NOTES.md @@ -0,0 +1,25 @@ +# ACE-Alloc Paper Notes (Scratchpad) + +このファイルは、ACE / 学習機能まわりの実験メモ・アイデア・ストーリー断片を雑に書き溜めるためのスクラッチパッドです。 +後で `docs/paper/ACE-Alloc/main.md` にまとめ直す前提の「素材置き場」として使います。 + +## アイデアメモ(例) + +- Tiny Headerless + Superslab + ACE の組み合わせで: + - Headerless: free パスでの class 決定を Superslab/region に移し、per-object header を除去。 + - ACE Controller: Mid/Large の TLS CAP / drain をオフパスで学習。 + - CAP Learner: Mid/Large の CAP / W_MAX をヒット率ベースで調整。 + - → 「ヘッダレス+学習」で、密度と性能を両立できるか? + +- 学習の「層ごとの役割分担」: + - L0 Tiny: 原則固定(学習対象外)。ただし Observer だけ Tiny を見る。 + - L1 ACE: キャッシュ構成(CAP / drain / bundle)を学習。 + - L2 ELO+Evolution: しきい値・戦略の切り替えを学習。 + - → Box Theory 的には、学習そのものも「上層の箱」として Tiny/SuperSlab から分離されている。 + +## 実験ネタ候補 + +- ACE ON/OFF が Tiny Headerless の性能・安定性に与える影響。 +- HAKMEM_MODE=balanced vs learning vs research での学習挙動の違い。 +- LD_PRELOAD モードで学習機能をどこまで有効にできるか(安全性とのトレードオフ)。 + diff --git a/docs/specs/DOCS_INDEX.md b/docs/specs/DOCS_INDEX.md index 77fec64a..d1682350 100644 --- a/docs/specs/DOCS_INDEX.md +++ b/docs/specs/DOCS_INDEX.md @@ -102,6 +102,8 @@ ACE Learning Layer (Adaptive Control Engine) - User guide: `docs/ACE_LEARNING_LAYER.md` ✅ - Technical plan: `docs/ACE_LEARNING_LAYER_PLAN.md` ✅ - Progress report: `ACE_PHASE1_PROGRESS.md` ✅ + - Learning layer overview: `docs/analysis/LEARNING_LAYER_OVERVIEW.md` ✅ + - Learning A/B results: `docs/benchmarks/LEARNING_AB_RESULTS.md` (growing log) - **Phase 1 Deliverables** (COMPLETE ✅): - ✅ Metrics collection (`hakmem_ace_metrics.{c,h}`) - ✅ UCB1 learning algorithm (`hakmem_ace_ucb1.{c,h}`) diff --git a/docs/specs/ENV_VARS.md b/docs/specs/ENV_VARS.md index 85acf5b4..d512cd71 100644 --- a/docs/specs/ENV_VARS.md +++ b/docs/specs/ENV_VARS.md @@ -1,12 +1,67 @@ HAKMEM Environment Variables (Tiny focus) -Core toggles +このファイルは HAKMEM の Tiny 系機能(Tiny allocator / TLS SLL / SuperSlab)に関わる環境変数をまとめたものです。 +数が多いため、まず「よく使うもの」だけをざっと把握できるようにし、その後に詳細なカテゴリ別リストを載せています。 + +### このファイルと他ドキュメントの関係(現状整理) +- リポジトリ全体の `getenv()` 呼び出しを集計した結果は `ENV_VARIABLE_SURVEY.md` にまとまっています(変数 228 個)。 +- `ENV_VARIABLE_SURVEY.md` では各変数に対して **KEEP / CONSOLIDATE / DEPRECATE** のステータスを付けています。 + - KEEP: 本番運用・安全性・主要なチューニングで今後も使う前提の変数 + - CONSOLIDATE: 将来的に `HAKMEM_DEBUG` / `HAKMEM_TRACE` / `HAKMEM_STATS` 等のマスター系に統合する予定の変数 + - DEPRECATE: 段階的に削除予定の変数(新規利用は非推奨) +- この `ENV_VARS.md` はその中から、**Tiny / SuperSlab / TLS SLL 周りで日常的に触るべきものを中心に抜き出した実用リファレンス** です。 +- Tiny 以外を含む網羅的な説明や、個々の変数のステータス詳細が必要な場合は: + - `ENV_VARIABLE_SURVEY.md`(最新のサーベイとステータス) + - `docs/specs/ENV_VARS_COMPLETE.md`(より古いが網羅的なリファレンス) + をあわせて参照してください。 + +## Quick cheat sheet(よく使うENV) + +### コア動作トグル(常用) +- `HAKMEM_WRAP_TINY` + Tiny allocator を有効化(直リンクまたは LD_PRELOAD 時の主経路にする)。 +- `HAKMEM_TINY_USE_SUPERSLAB` + Tiny が SuperSlab バックエンドを使うかどうか(既定 ON)。 +- `HAKMEM_TINY_TLS_SLL` + Tiny TLS SLL を有効化(Headerless/Phase2 でもコア機能)。 +- `HAKMEM_SAFE_FREE` / `HAKMEM_INVALID_FREE` / `HAKMEM_INVALID_FREE_LOG` + free() 経路の安全性・invalid free 検出モード。 +- `HAKMEM_LD_SAFE` / `HAKMEM_LD_BLOCK_JEMALLOC` / `HAKMEM_FORCE_LIBC_ALLOC(_INIT)` + LD_PRELOAD 時の安全モードと jemalloc との共存制御。 + +### Tiny/SuperSlab/TLS の主要チューニング +- `HAKMEM_TINY_REFILL_MAX` / `HAKMEM_TINY_REFILL_MAX_HOT` / `HAKMEM_TINY_REFILL_MAX_C{0..7}` + Tiny TLS キャッシュのリフィル上限(全体/ホットクラス/クラス別)。 +- `HAKMEM_TINY_SS_ADOPT*` / `HAKMEM_TINY_SS_REQTRACE` + SuperSlab publish/adopt 経路と採用ゲートの挙動。 +- `HAKMEM_TINY_SLL_DRAIN_ENABLE` / `HAKMEM_TINY_SLL_DRAIN_INTERVAL` + TLS SLL → freelist drain の頻度・有効/無効。 + +### ベンチ/実験用(通常運用では OFF 推奨) +- `HAKMEM_BENCH_FAST_FRONT` / `HAKMEM_BENCH_WARMUP` / `HAKMEM_TINY_BENCH_*` + ベンチマーク専用の fast front / warmup / refill 設定。 +- `HAKMEM_TINY_ULTRA*` / `HAKMEM_TINY_BENCH_SLL_ONLY` + Ultra Tiny / SLL‑only などの実験経路。 + +### デバッグ/トレース/統計(マスター系) +- `HAKMEM_DEBUG_ALL` / `HAKMEM_DEBUG_LEVEL` / `HAKMEM_QUIET` + 全体デバッグの一括 ON/OFF と冗長度。 +- `HAKMEM_TRACE` / `HAKMEM_TRACE_LEVEL` + トレース対象(ptr/refill/free/mailbox/...)と冗長度。 +- `HAKMEM_STATS` / `HAKMEM_STATS_DUMP` + 統計モジュールの有効化と終了時ダンプ。 + +以降のセクションでは、これらを含むすべての ENV をカテゴリ別に詳しく説明します。 + +--- + +## Core toggles - HAKMEM_WRAP_TINY=1 - Tiny allocatorを有効化(直リンク) - HAKMEM_TINY_USE_SUPERSLAB=0/1 - SuperSlab経路のON/OFF(既定ON) -SFC (Super Front Cache) stats / A/B +## SFC (Super Front Cache) stats / A/B - HAKMEM_SFC_ENABLE=0/1 - Box 5‑NEW: Super Front Cache を有効化(既定OFF; A/B用)。 - HAKMEM_SFC_CAPACITY=16..256 / HAKMEM_SFC_REFILL_COUNT=8..256 @@ -15,7 +70,7 @@ SFC (Super Front Cache) stats / A/B - プロセス終了時に SFC 統計をstderrへダンプ(alloc_hits/misses, refill_calls など)。 - 使い方: make CFLAGS+=" -DHAKMEM_DEBUG_COUNTERS=1" larson_hakmem; HAKMEM_SFC_ENABLE=1 HAKMEM_SFC_STATS_DUMP=1 ./larson_hakmem … -Larson defaults (publish→mail→adopt) +## Larson defaults (publish→mail→adopt) - 忘れがちな必須変数をスクリプトで一括設定するため、`scripts/run_larson_defaults.sh` を用意しています。 - 既定で以下を export します(A/B は環境変数で上書き可能): - `HAKMEM_TINY_USE_SUPERSLAB=1` / `HAKMEM_TINY_MUST_ADOPT=1` / `HAKMEM_TINY_SS_ADOPT=1` @@ -24,7 +79,7 @@ Larson defaults (publish→mail→adopt) - `HAKMEM_TINY_MAILBOX_SLOWDISC=1` - `HAKMEM_TINY_MAILBOX_SLOWDISC_PERIOD=256` -Front Gate (A/B for boxified fast path) +## Front Gate (A/B for boxified fast path) - `HAKMEM_TINY_FRONT_GATE_BOX=1` — Use Front Gate Box implementation (SFC→SLL) for fast-path pop/push/cascade. Default 0. Safe to toggle during builds via `make EXTRA_CFLAGS+=" -DHAKMEM_TINY_FRONT_GATE_BOX=1"`. - Debug visibility(任意): `HAKMEM_TINY_RF_TRACE=1` - Force-notify(任意, デバッグ補助): `HAKMEM_TINY_RF_FORCE_NOTIFY=1` @@ -32,7 +87,7 @@ Front Gate (A/B for boxified fast path) - tput: `HAKMEM_TINY_SS_FORCE_LG=21`, `HAKMEM_TINY_SS_CACHE=0`, `HAKMEM_TINY_SS_PRECHARGE=0` - pf: `HAKMEM_TINY_SS_FORCE_LG=20`, `HAKMEM_TINY_SS_CACHE=4`, `HAKMEM_TINY_SS_PRECHARGE=1` -Ultra Tiny (SLL-only, experimental) +## Ultra Tiny (SLL-only, experimental) - HAKMEM_TINY_ULTRA=0/1 - Ultra TinyモードのON/OFF(SLL中心の最小ホットパス) - HAKMEM_TINY_ULTRA_VALIDATE=0/1 @@ -42,7 +97,7 @@ Ultra Tiny (SLL-only, experimental) - HAKMEM_TINY_ULTRA_SLL_CAP_C{0..7}=N - クラス別SLL上限上書き -SuperSlab adopt/publish(実験) +## SuperSlab adopt/publish(実験) - HAKMEM_TINY_SS_ADOPT=0/1 - SuperSlab の publish/adopt + remote drain + owner移譲を有効化(既定OFF)。 - 4T Larson など cross-thread free が多いワークロードで再利用密度を高めるための実験用スイッチ。 @@ -60,22 +115,22 @@ SuperSlab adopt/publish(実験) - remote queue がすでに非空(old!=0)でも、`slab_listed==0` の場合に publish を強制通知。 - 初回の空→非空通知を見逃した可能性をあぶり出す用途に有効(A/B 推奨)。 -Ready List(Refill最適化の箱) +## Ready List(Refill最適化の箱) - 2025-12 cleanup: Ready系ENVは廃止。Ready ringは常時有効、幅/予算は固定(width=TINY_READY_RING, budget=1)。 -Background Remote Drain(束ね箱・軽量ステップ) +## Background Remote Drain(束ね箱・軽量ステップ) - 2025-12 cleanup: BG Remote系ENV(HAKMEM_TINY_BG_REMOTE*)は廃止。BGリモート/aggregatorは固定OFF。 -Ready Aggregator(BG, 非破壊peek) +## Ready Aggregator(BG, 非破壊peek) - 2025-12 cleanup: Ready Aggregator系ENVも廃止(固定OFF)。 -Registry 窓(探索コストのA/B) +## Registry 窓(探索コストのA/B) - HAKMEM_TINY_REG_SCAN_MAX=N - Registry の“小窓”で走査する最大エントリ数(既定256)。 - 値を小さくすると superslab_refill() と mmap直前ゲートでの探索コストが減る一方、adopt 命中率が低下し OOM/新規mmap が増える可能性あり。 - Tiny‑Hotなど命中率が高い場合は 64/128 などをA/B推奨。 -Mid 向け簡素化リフィル(128–1024B向けの分岐削減) +## Mid 向け簡素化リフィル(128–1024B向けの分岐削減) - HAKMEM_TINY_MID_REFILL_SIMPLE=0/1 - クラス>=4(128B以上)で、sticky/hot/mailbox/registry/adopt の多段探索をスキップし、 1) 既存TLSのSuperSlabに未使用Slabがあれば直接初期化→bind、 @@ -224,7 +279,7 @@ New (debug isolation) - 小クラス用の小型TLSマガジン(128要素, classes 0..3)を有効化。既定0(A/B用)。 - alloc: HotMag→SLL→Magazine の順でヒットを狙う。free: SLL優先、溢れ時にHotMag→Magazine。 -USDT/tracepoints(perfのユーザ空間静的トレース) +## USDT/tracepoints(perfのユーザ空間静的トレース) - ビルド時に `CFLAGS+=-DHAKMEM_USDT=1` を付与すると、主要分岐にUSDT(DTrace互換)プローブが埋め込まれます。 - 依存: ``(Debian/Ubuntu: `sudo apt-get install systemtap-sdt-dev`)。 - プローブ名(provider=hakmem)例: @@ -242,7 +297,7 @@ USDT/tracepoints(perfのユーザ空間静的トレース) - `sudo sysctl kernel.perf_event_paranoid=1` - WSLなど一部カーネルでは UPROBE/USDT が無効な場合があります(PMUのみにフォールバック)。 -ビルドプリセット(Tiny‑Hot最短フロント) +## ビルドプリセット(Tiny‑Hot最短フロント) - コンパイル時フラグ: `-DHAKMEM_TINY_MINIMAL_FRONT=1` - 入口から UltraFront/Quick/Frontend/HotMag/SuperSlab try/BumpShadow を物理的に除去 - 残る経路: `SLL → TLS Magazine → SuperSlab →(以降のスローパス)` @@ -253,7 +308,7 @@ USDT/tracepoints(perfのユーザ空間静的トレース) - 入口で SuperSlab TLSバンプ→SuperSlab直経路を優先(ビルド除去ではなく分岐) - Tiny‑Hotでは概ね不利(命令・分岐増)なため、既定OFF。ベンチA/B用途のみ。 -Scripts +## Scripts - scripts/run_tiny_hot_triad.sh - scripts/run_tiny_benchfast_triad.sh — bench-only fast path triad - scripts/run_tiny_sllonly_triad.sh — SLL-only + warmup + PGO triad @@ -495,4 +550,3 @@ Update History: - 2025-11-29: Added benchmark env vars (BENCH_FAST_FRONT, BENCH_WARMUP, FREE_ROUTE_TRACE) - 2025-11-29: Added HAKMEM_TINY_SS_TRUST_MMAP_ZERO build flag - 2025-11-29: Marked DISABLE_MINCORE_CHECK as removed - diff --git a/hakmem.d b/hakmem.d index b66f4414..414aa4dd 100644 --- a/hakmem.d +++ b/hakmem.d @@ -23,16 +23,16 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \ core/hakmem_batch.h core/hakmem_evo.h core/hakmem_debug.h \ core/hakmem_prof.h core/hakmem_syscall.h core/hakmem_ace_controller.h \ core/hakmem_ace_metrics.h core/hakmem_ace_ucb1.h \ - core/box/bench_fast_box.h core/ptr_trace.h core/box/hak_core_init.inc.h \ - core/hakmem_phase7_config.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/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/../tiny_free_fast_v2.inc.h \ - core/box/../tiny_region_id.h core/box/../hakmem_build_flags.h \ - core/box/../hakmem_tiny_config.h core/box/../box/tls_sll_box.h \ - core/box/../box/../hakmem_internal.h \ + core/box/bench_fast_box.h core/ptr_trace.h core/box/hak_kpi_util.inc.h \ + core/box/hak_core_init.inc.h core/hakmem_phase7_config.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/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/../tiny_free_fast_v2.inc.h core/box/../tiny_region_id.h \ + core/box/../hakmem_build_flags.h core/box/../hakmem_tiny_config.h \ + core/box/../box/tls_sll_box.h core/box/../box/../hakmem_internal.h \ core/box/../box/../hakmem_tiny_config.h \ core/box/../box/../hakmem_build_flags.h \ core/box/../box/../hakmem_debug_master.h \ @@ -58,8 +58,8 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \ core/box/../box/tiny_layout_box.h core/box/front_gate_v2.h \ core/box/external_guard_box.h core/box/ss_slab_meta_box.h \ core/box/fg_tiny_gate_box.h core/box/hak_exit_debug.inc.h \ - core/box/hak_kpi_util.inc.h core/box/hak_wrappers.inc.h \ - core/box/front_gate_classifier.h core/box/../front/malloc_tiny_fast.h \ + core/box/hak_wrappers.inc.h core/box/front_gate_classifier.h \ + core/box/../front/malloc_tiny_fast.h \ core/box/../front/../hakmem_build_flags.h \ core/box/../front/../hakmem_tiny_config.h \ core/box/../front/../superslab/superslab_inline.h \ @@ -72,6 +72,7 @@ hakmem.o: core/hakmem.c core/hakmem.h core/hakmem_build_flags.h \ core/box/../front/../box/../hakmem_tiny_config.h \ core/box/../front/../box/../tiny_region_id.h \ core/box/../front/../box/../front/tiny_unified_cache.h \ + core/box/../front/../box/tiny_layout_box.h \ core/box/../front/../box/tiny_front_cold_box.h \ core/box/tiny_front_config_box.h core/box/wrapper_env_box.h \ core/box/../hakmem_internal.h core/box/../superslab/superslab_inline.h @@ -135,6 +136,7 @@ core/hakmem_ace_metrics.h: core/hakmem_ace_ucb1.h: core/box/bench_fast_box.h: core/ptr_trace.h: +core/box/hak_kpi_util.inc.h: core/box/hak_core_init.inc.h: core/hakmem_phase7_config.h: core/box/ss_hot_prewarm_box.h: @@ -191,7 +193,6 @@ core/box/external_guard_box.h: core/box/ss_slab_meta_box.h: core/box/fg_tiny_gate_box.h: core/box/hak_exit_debug.inc.h: -core/box/hak_kpi_util.inc.h: core/box/hak_wrappers.inc.h: core/box/front_gate_classifier.h: core/box/../front/malloc_tiny_fast.h: @@ -208,6 +209,7 @@ core/box/../front/../box/tiny_front_hot_box.h: core/box/../front/../box/../hakmem_tiny_config.h: core/box/../front/../box/../tiny_region_id.h: core/box/../front/../box/../front/tiny_unified_cache.h: +core/box/../front/../box/tiny_layout_box.h: core/box/../front/../box/tiny_front_cold_box.h: core/box/tiny_front_config_box.h: core/box/wrapper_env_box.h: