diff --git a/core/box/hak_alloc_api.inc.h b/core/box/hak_alloc_api.inc.h index 35e9d8d5..e525f6ac 100644 --- a/core/box/hak_alloc_api.inc.h +++ b/core/box/hak_alloc_api.inc.h @@ -9,6 +9,8 @@ #include "../pool_tls.h" #endif +#include "mid_large_config_box.h" // Phase 5-Step3: Compile-time config for Mid/Large + // Centralized OS mapping boundary to keep syscalls in one place static inline void* hak_os_map_boundary(size_t size, uintptr_t site_id) { #if HAKMEM_DEBUG_TIMING @@ -140,15 +142,16 @@ inline void* hak_alloc_at(size_t size, hak_callsite_t site) { } #endif + // Phase 5-Step3: Use Mid/Large Config Box (compile-time constant in PGO mode) size_t threshold; - if (HAK_ENABLED_LEARNING(HAKMEM_FEATURE_ELO)) { + if (MID_LARGE_ELO_ENABLED) { int strategy_id = atomic_load(&g_cached_strategy_id); threshold = hak_elo_get_threshold(strategy_id); } else { threshold = 2097152; } - if (HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && size >= threshold) { + if (MID_LARGE_BIGCACHE_ENABLED && size >= threshold) { void* cached_ptr = NULL; #if HAKMEM_DEBUG_TIMING HKM_TIME_START(t_bc); diff --git a/core/box/hak_free_api.inc.h b/core/box/hak_free_api.inc.h index f0f061f0..656ed317 100644 --- a/core/box/hak_free_api.inc.h +++ b/core/box/hak_free_api.inc.h @@ -14,6 +14,8 @@ #include "../pool_tls.h" #endif +#include "mid_large_config_box.h" // Phase 5-Step3: Compile-time config for Mid/Large + // Optional route trace: print first N classification lines when enabled by env #if !HAKMEM_BUILD_RELEASE static inline int hak_free_route_trace_on(void) { @@ -284,12 +286,13 @@ void hak_free_at(void* ptr, size_t size, hak_callsite_t site) { goto done; } } - if (HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && hdr->class_bytes >= 2097152) { + // Phase 5-Step3: Use Mid/Large Config Box (compile-time constant in PGO mode) + if (MID_LARGE_BIGCACHE_ENABLED && hdr->class_bytes >= 2097152) { if (hak_bigcache_put(ptr, hdr->size, hdr->alloc_site)) goto done; } { static int g_bc_l25_en_free = -1; if (g_bc_l25_en_free == -1) { const char* e = getenv("HAKMEM_BIGCACHE_L25"); g_bc_l25_en_free = (e && atoi(e) != 0) ? 1 : 0; } - if (g_bc_l25_en_free && HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && hdr->size >= 524288 && hdr->size < 2097152) { + if (g_bc_l25_en_free && MID_LARGE_BIGCACHE_ENABLED && hdr->size >= 524288 && hdr->size < 2097152) { if (hak_bigcache_put(ptr, hdr->size, hdr->alloc_site)) goto done; } } diff --git a/core/box/mid_large_config_box.h b/core/box/mid_large_config_box.h new file mode 100644 index 00000000..19ef02e8 --- /dev/null +++ b/core/box/mid_large_config_box.h @@ -0,0 +1,217 @@ +/** + * mid_large_config_box.h - Phase 5-Step3: Mid/Large Config Box + * + * Box: Mid/Large Configuration Management + * Responsibility: Compile-time configuration for dead code elimination in Mid/Large paths + * Contract: Dual-mode (compile-time constants vs runtime ENV checks) + * + * Design Principles (Box Pattern): + * 1. Single Responsibility: Configuration management ONLY + * 2. Clear Contract: PGO mode = compile-time constants, Normal mode = runtime checks + * 3. Observable: Config report function (debug builds) + * 4. Safe: Backward compatible (default runtime mode) + * 5. Testable: Easy A/B comparison (PGO vs normal builds) + * + * Problem: + * - Hot path has 5-8 runtime ENV checks (BigCache, ELO, ACE, etc.) + * - Each check: getenv() + lazy init + branch misprediction + * - Result: 2-4% overhead in allocation path + * + * Solution: + * - PGO mode: Replace runtime checks with compile-time constants + * - Compiler constant folding eliminates dead branches + * - Example: if (MID_LARGE_BIGCACHE_ENABLED) { ... } → if (1) { ... } → always executes + * + * Performance Impact: + * - Target: +2-4% improvement via dead code elimination + * - Based on Phase 4-Step3 results (+2.7-4.9% for Tiny) + * + * Usage: + * Normal build (runtime config, backward compatible): + * make bench_random_mixed_hakmem + * + * PGO build (compile-time config, maximum performance): + * make EXTRA_CFLAGS="-DHAKMEM_MID_LARGE_PGO=1" bench_random_mixed_hakmem + * + * Created: 2025-11-29 (Phase 5-Step3) + */ + +#ifndef MID_LARGE_CONFIG_BOX_H +#define MID_LARGE_CONFIG_BOX_H + +#include +#include "../hakmem_build_flags.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================================ +// Build Flag Check (must be defined in hakmem_build_flags.h) +// ============================================================================ + +#ifndef HAKMEM_MID_LARGE_PGO +# define HAKMEM_MID_LARGE_PGO 0 +#endif + +// ============================================================================ +// PGO Mode: Fixed Configuration (Compile-Time Constants) +// ============================================================================ + +#if HAKMEM_MID_LARGE_PGO + +// PGO-optimized build: All runtime checks become compile-time constants +// Compiler constant folding eliminates dead branches: +// if (MID_LARGE_BIGCACHE_ENABLED) { ... } // 1 → always executes, no branch +// if (MID_LARGE_ELO_ENABLED) { ... } // 1 → always executes, no branch + +#define MID_LARGE_BIGCACHE_ENABLED 1 // Enabled (BigCache for large allocs) +#define MID_LARGE_ELO_ENABLED 1 // Enabled (ELO learning/threshold) +#define MID_LARGE_ACE_ENABLED 1 // Enabled (ACE allocator, 1KB-2MB) +#define MID_LARGE_POOL_TLS_ENABLED 0 // Disabled (Pool TLS, legacy) +#define MID_LARGE_SMALLMID_ENABLED 0 // Disabled (SmallMid, legacy) +#define MID_LARGE_EVOLUTION_ENABLED 1 // Enabled (Evolution sampling) + +// Expected code reduction: +// - BigCache check: 1 branch removed (hot path) +// - ELO check: 1 branch removed (hot path) +// - ACE check: 1 branch removed (hot path) +// - Pool TLS check: 1 branch removed (free path) +// - SmallMid check: 1 branch removed (alloc path) +// Total: 5+ branches eliminated in hot paths + +#else + +// ============================================================================ +// Normal Mode: Runtime Configuration (Backward Compatible) +// ============================================================================ + +// Normal build: Checks ENV variables or global config state +// Preserves backward compatibility with existing ENV variable interface +// +// NOTE: The actual runtime config functions are defined in their respective modules: +// - HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) → core/hakmem_config.h +// - HAK_ENABLED_LEARNING(HAKMEM_FEATURE_ELO) → core/hakmem_config.h +// - etc. +// +// This box does NOT define these functions, only provides macros that call them. + +#include "../hakmem_config.h" // For HAK_ENABLED_* macros +#include "../hakmem_features.h" // For HAKMEM_FEATURE_* constants + +// Runtime config checks (function calls, ENV variable lookups) +#define MID_LARGE_BIGCACHE_ENABLED HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) +#define MID_LARGE_ELO_ENABLED HAK_ENABLED_LEARNING(HAKMEM_FEATURE_ELO) +#define MID_LARGE_ACE_ENABLED 1 // ACE is always attempted (fallback to mmap if disabled) +#define MID_LARGE_POOL_TLS_ENABLED 0 // Pool TLS deprecated, always disabled +#define MID_LARGE_SMALLMID_ENABLED 0 // SmallMid deprecated, always disabled +#define MID_LARGE_EVOLUTION_ENABLED (g_evo_sample_mask > 0) // Check evolution sampling + +#endif // HAKMEM_MID_LARGE_PGO + +// ============================================================================ +// Box Observability (Debug/Profiling) +// ============================================================================ + +/** + * mid_large_is_pgo_build - Check if this is a PGO build + * + * @return 1 if PGO mode (compile-time config), 0 if normal mode (runtime config) + * + * Useful for debugging to verify build mode + */ +static inline int mid_large_is_pgo_build(void) { + return HAKMEM_MID_LARGE_PGO; +} + +#if !HAKMEM_BUILD_RELEASE +/** + * mid_large_config_report - Print current configuration (debug builds only) + * + * Prints: + * - Build mode (PGO vs Normal) + * - All config flags and their values + * - Config source (compile-time vs runtime) + * + * Only available in debug builds (HAKMEM_BUILD_RELEASE=0) + */ +static inline void mid_large_config_report(void) { + fprintf(stderr, "[MID_LARGE_CONFIG] Build mode: %s\n", + HAKMEM_MID_LARGE_PGO ? "PGO (compile-time)" : "Normal (runtime)"); + fprintf(stderr, "[MID_LARGE_CONFIG] BigCache: %d\n", MID_LARGE_BIGCACHE_ENABLED ? 1 : 0); + fprintf(stderr, "[MID_LARGE_CONFIG] ELO: %d\n", MID_LARGE_ELO_ENABLED ? 1 : 0); + fprintf(stderr, "[MID_LARGE_CONFIG] ACE: %d\n", MID_LARGE_ACE_ENABLED ? 1 : 0); + fprintf(stderr, "[MID_LARGE_CONFIG] Pool TLS: %d\n", MID_LARGE_POOL_TLS_ENABLED ? 1 : 0); + fprintf(stderr, "[MID_LARGE_CONFIG] SmallMid: %d\n", MID_LARGE_SMALLMID_ENABLED ? 1 : 0); + fprintf(stderr, "[MID_LARGE_CONFIG] Evolution: %d\n", MID_LARGE_EVOLUTION_ENABLED ? 1 : 0); +} +#endif // !HAKMEM_BUILD_RELEASE + +// ============================================================================ +// Box Usage Examples +// ============================================================================ + +/* + * Example 1: Replace HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) + * + * Before (Phase 4): + * if (HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && size >= threshold) { + * void* cached_ptr = NULL; + * if (hak_bigcache_try_get(size, site_id, &cached_ptr)) { + * return cached_ptr; + * } + * } + * + * After (Phase 5-Step3): + * if (MID_LARGE_BIGCACHE_ENABLED && size >= threshold) { + * void* cached_ptr = NULL; + * if (hak_bigcache_try_get(size, site_id, &cached_ptr)) { + * return cached_ptr; + * } + * } + * + * PGO mode (HAKMEM_MID_LARGE_PGO=1): + * if (1 && size >= threshold) { ... } + * → Compiler optimizes: if (size >= threshold) { ... } (no BigCache check!) + * + * Normal mode (HAKMEM_MID_LARGE_PGO=0): + * if (HAK_ENABLED_CACHE(HAKMEM_FEATURE_BIGCACHE) && size >= threshold) { ... } + * → Runtime ENV check (backward compatible) + */ + +/* + * Example 2: Replace HAK_ENABLED_LEARNING(HAKMEM_FEATURE_ELO) + * + * Before (Phase 4): + * size_t threshold; + * if (HAK_ENABLED_LEARNING(HAKMEM_FEATURE_ELO)) { + * int strategy_id = atomic_load(&g_cached_strategy_id); + * threshold = hak_elo_get_threshold(strategy_id); + * } else { + * threshold = 2097152; + * } + * + * After (Phase 5-Step3): + * size_t threshold; + * if (MID_LARGE_ELO_ENABLED) { + * int strategy_id = atomic_load(&g_cached_strategy_id); + * threshold = hak_elo_get_threshold(strategy_id); + * } else { + * threshold = 2097152; + * } + * + * PGO mode: + * if (1) { ... } else { ... } + * → Compiler optimizes: { threshold = hak_elo_get_threshold(...); } + * → else branch completely removed! + * + * Normal mode: + * if (HAK_ENABLED_LEARNING(HAKMEM_FEATURE_ELO)) { ... } else { ... } + * → Runtime ENV check (backward compatible) + */ + +#ifdef __cplusplus +} +#endif + +#endif // MID_LARGE_CONFIG_BOX_H diff --git a/core/hakmem_build_flags.h b/core/hakmem_build_flags.h index 1b4a7ea8..f019b86c 100644 --- a/core/hakmem_build_flags.h +++ b/core/hakmem_build_flags.h @@ -131,6 +131,20 @@ # define HAKMEM_TINY_FRONT_PGO 0 #endif +// Phase 5-Step3: Mid/Large PGO Config Box +// ------------------------------------------------------------ +// HAKMEM_MID_LARGE_PGO: +// 0 = Normal build with runtime configuration (default, backward compatible) +// Configuration checked via ENV variables at runtime (flexible) +// 1 = PGO-optimized build with compile-time configuration (performance) +// Configuration fixed at compile time (dead code elimination) +// Eliminates runtime branches for Mid/Large allocation paths. +// Use with: make EXTRA_CFLAGS="-DHAKMEM_MID_LARGE_PGO=1" bench_random_mixed_hakmem +// Expected benefit: +2-4% improvement via dead code elimination +#ifndef HAKMEM_MID_LARGE_PGO +# define HAKMEM_MID_LARGE_PGO 0 +#endif + // Route fingerprint (compile-time gate; runtime ENV still required) #ifndef HAKMEM_ROUTE # define HAKMEM_ROUTE 0