Files
hakmem/core/hakmem_env_cache.h

378 lines
17 KiB
C
Raw Normal View History

// hakmem_env_cache.h - ENV Variable Cache Box (Phase Priority-2 Refactoring)
// 箱理論: ENV Caching Layer - Parse all ENV variables once at startup
//
// Purpose: Eliminate ~2000 syscalls/second from hot malloc/free paths
// Problem: getenv() in hot path causes kernel trap (>100 cycles per call)
// Solution: Parse all ENV variables at process start, cache in TLS/globals
//
// Architecture:
// - Single init entry point: hakmem_env_cache_init() (called from hakmem_init)
// - All ENV variables parsed once, cached in static storage
// - Hot path code uses cached values (1-2 cycle lookup vs 100+ cycle syscall)
//
// Design: Box Pattern (stateless inline header with single responsibility)
#ifndef HAKMEM_ENV_CACHE_H
#define HAKMEM_ENV_CACHE_H
#include <stdlib.h> // getenv()
2025-12-05 20:43:14 +09:00
#include <stdio.h> // fprintf, stderr
#include <string.h> // strcmp()
// ============================================================================
// ENV Cache Structure
// ============================================================================
// Global ENV cache (parsed once at init, read-only thereafter)
typedef struct {
// ===== Hot Path: Tiny Alloc Fast (7 variables) =====
int tiny_active_track; // HAKMEM_TINY_ACTIVE_TRACK (default: 0)
int tiny_alloc_1024_metric; // HAKMEM_TINY_ALLOC_1024_METRIC (default: 0)
int tiny_profile; // HAKMEM_TINY_PROFILE (default: 0)
int tiny_heap_v2_stats; // HAKMEM_TINY_HEAP_V2_STATS (default: 0)
int tiny_front_slim; // HAKMEM_TINY_FRONT_SLIM (default: 0)
int sfc_cascade_pct; // HAKMEM_SFC_CASCADE_PCT (default: 50)
int tiny_sfc_cascade; // HAKMEM_TINY_SFC_CASCADE (default: 0)
// ===== Hot Path: Tiny Free Fast (3 variables) =====
int tiny_no_class_map; // HAKMEM_TINY_NO_CLASS_MAP (default: 0)
int tiny_larson_fix; // HAKMEM_TINY_LARSON_FIX (default: 0)
// ===== Hot Path: SuperSlab Alloc (1 variable) =====
int tiny_alloc_remote_relax; // HAKMEM_TINY_ALLOC_REMOTE_RELAX (default: 0)
// ===== Hot Path: SuperSlab Free (5 variables) =====
int tiny_sll_diag; // HAKMEM_TINY_SLL_DIAG (default: 0)
int tiny_route_free; // HAKMEM_TINY_ROUTE_FREE (default: 0)
int tiny_free_to_ss; // HAKMEM_TINY_FREE_TO_SS (default: 0)
int ss_free_debug; // HAKMEM_SS_FREE_DEBUG (default: 0)
// ===== Warm Path: Lazy Init (1 variable) =====
int ss_map_trace; // HAKMEM_SS_MAP_TRACE (default: 0)
// ===== Warm Path: FastCache (9 variables) =====
int tiny_fast_debug; // HAKMEM_TINY_FAST_DEBUG (default: 0)
int tiny_fast_debug_max; // HAKMEM_TINY_FAST_DEBUG_MAX (default: 0)
int tiny_front_direct; // HAKMEM_TINY_FRONT_DIRECT (default: 0)
int tiny_fast_stats; // HAKMEM_TINY_FAST_STATS (default: 0)
int tiny_unified_cache; // HAKMEM_TINY_UNIFIED_CACHE (default: 1)
int sfc_debug; // HAKMEM_SFC_DEBUG (default: 0)
int sfc_enable; // HAKMEM_SFC_ENABLE (default: 1)
int sfc_capacity; // HAKMEM_SFC_CAPACITY (default: 128)
int sfc_refill_count; // HAKMEM_SFC_REFILL_COUNT (default: 16)
// ===== Cold Path: Headers/Debug (12 variables) =====
int tiny_restore_header; // HAKMEM_TINY_RESTORE_HEADER (default: 0)
int super_lookup_debug; // HAKMEM_SUPER_LOOKUP_DEBUG (default: 0)
int quiet; // HAKMEM_QUIET (default: 0)
int allow_malloc_fallback; // HAKMEM_ALLOW_MALLOC_FALLBACK (default: 1)
unsigned long tiny_freelist_mask; // HAKMEM_TINY_FREELIST_MASK (default: 0)
int super_reg_debug; // HAKMEM_SUPER_REG_DEBUG (default: 0)
int superslab_max_cached; // HAKMEM_SUPERSLAB_MAX_CACHED (default: 8)
int superslab_max_memory_mb; // HAKMEM_SUPERSLAB_MAX_MEMORY_MB (default: 256)
int superslab_ttl_sec; // HAKMEM_SUPERSLAB_TTL_SEC (default: 60)
int ss_lru_debug; // HAKMEM_SS_LRU_DEBUG (default: 0)
int ss_prewarm_debug; // HAKMEM_SS_PREWARM_DEBUG (default: 0)
int prewarm_superslabs; // HAKMEM_PREWARM_SUPERSLABS (default: 0)
// ===== Warm Path: Shared Pool Acquire (5 variables) =====
int ss_empty_reuse; // HAKMEM_SS_EMPTY_REUSE (default: 1)
int ss_empty_scan_limit; // HAKMEM_SS_EMPTY_SCAN_LIMIT (default: 32)
int ss_acquire_debug; // HAKMEM_SS_ACQUIRE_DEBUG (default: 0)
int tiny_tension_drain_enable; // HAKMEM_TINY_TENSION_DRAIN_ENABLE (default: 1)
int tiny_tension_drain_threshold; // HAKMEM_TINY_TENSION_DRAIN_THRESHOLD (default: 1024)
// ===== Warm Path: SmallMid (1 variable) =====
int smallmid_enable; // HAKMEM_SMALLMID_ENABLE (default: 0)
// ===== Cold Path: Debug/Timing (1 variable) =====
int timing_enabled; // HAKMEM_TIMING (default: 0)
// ===== Cold Path: Batch (1 variable) =====
int batch_bg; // HAKMEM_BATCH_BG (default: 0)
// ===== Cold Path: Superslab Madvise (1 variable) =====
int ss_madvise_strict; // HAKMEM_SS_MADVISE_STRICT (default: 1)
} HakEnvCache;
// Global cache instance (initialized once at startup)
extern HakEnvCache g_hak_env_cache;
// ============================================================================
// Init Function (called once at process start)
// ============================================================================
static inline void hakmem_env_cache_init(void) {
// Zero-init the cache (all defaults to 0)
memset(&g_hak_env_cache, 0, sizeof(HakEnvCache));
// ===== Hot Path: Tiny Alloc Fast =====
{
const char* e;
e = getenv("HAKMEM_TINY_ACTIVE_TRACK");
g_hak_env_cache.tiny_active_track = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_ALLOC_1024_METRIC");
g_hak_env_cache.tiny_alloc_1024_metric = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_PROFILE");
g_hak_env_cache.tiny_profile = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_HEAP_V2_STATS");
g_hak_env_cache.tiny_heap_v2_stats = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_FRONT_SLIM");
g_hak_env_cache.tiny_front_slim = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SFC_CASCADE_PCT");
if (e && *e) {
int v = atoi(e);
if (v < 0) v = 0;
if (v > 100) v = 100;
g_hak_env_cache.sfc_cascade_pct = v;
} else {
g_hak_env_cache.sfc_cascade_pct = 50; // default: 50%
}
e = getenv("HAKMEM_TINY_SFC_CASCADE");
g_hak_env_cache.tiny_sfc_cascade = (e && *e && *e != '0') ? 1 : 0;
}
// ===== Hot Path: Tiny Free Fast =====
{
const char* e;
e = getenv("HAKMEM_TINY_NO_CLASS_MAP");
g_hak_env_cache.tiny_no_class_map = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_LARSON_FIX");
g_hak_env_cache.tiny_larson_fix = (e && *e && *e != '0') ? 1 : 0;
}
// ===== Hot Path: SuperSlab Alloc =====
{
const char* e = getenv("HAKMEM_TINY_ALLOC_REMOTE_RELAX");
g_hak_env_cache.tiny_alloc_remote_relax = (e && *e && *e != '0') ? 1 : 0;
}
// ===== Hot Path: SuperSlab Free =====
{
const char* e;
e = getenv("HAKMEM_TINY_SLL_DIAG");
g_hak_env_cache.tiny_sll_diag = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_ROUTE_FREE");
g_hak_env_cache.tiny_route_free = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_FREE_TO_SS");
g_hak_env_cache.tiny_free_to_ss = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SS_FREE_DEBUG");
g_hak_env_cache.ss_free_debug = (e && *e && *e != '0') ? 1 : 0;
}
// ===== Warm Path: Lazy Init =====
{
const char* e = getenv("HAKMEM_SS_MAP_TRACE");
g_hak_env_cache.ss_map_trace = (e && *e) ? 1 : 0;
}
// ===== Warm Path: FastCache =====
{
const char* e;
e = getenv("HAKMEM_TINY_FAST_DEBUG");
g_hak_env_cache.tiny_fast_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_FAST_DEBUG_MAX");
g_hak_env_cache.tiny_fast_debug_max = (e && *e) ? atoi(e) : 0;
e = getenv("HAKMEM_TINY_FRONT_DIRECT");
g_hak_env_cache.tiny_front_direct = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_FAST_STATS");
g_hak_env_cache.tiny_fast_stats = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_UNIFIED_CACHE");
// Default: 1 (enabled), set HAKMEM_TINY_UNIFIED_CACHE=0 to disable
g_hak_env_cache.tiny_unified_cache = (e && *e && *e == '0') ? 0 : 1;
e = getenv("HAKMEM_SFC_DEBUG");
g_hak_env_cache.sfc_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SFC_ENABLE");
g_hak_env_cache.sfc_enable = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SFC_CAPACITY");
g_hak_env_cache.sfc_capacity = (e && *e) ? atoi(e) : 128;
e = getenv("HAKMEM_SFC_REFILL_COUNT");
g_hak_env_cache.sfc_refill_count = (e && *e) ? atoi(e) : 16;
}
// ===== Cold Path: Headers/Debug =====
{
const char* e;
e = getenv("HAKMEM_TINY_RESTORE_HEADER");
g_hak_env_cache.tiny_restore_header = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SUPER_LOOKUP_DEBUG");
g_hak_env_cache.super_lookup_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_QUIET");
g_hak_env_cache.quiet = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_ALLOW_MALLOC_FALLBACK");
// Default: 1 (allow fallback), set HAKMEM_ALLOW_MALLOC_FALLBACK=0 to disable
g_hak_env_cache.allow_malloc_fallback = (e && *e && *e == '0') ? 0 : 1;
e = getenv("HAKMEM_TINY_FREELIST_MASK");
g_hak_env_cache.tiny_freelist_mask = (e && *e) ? strtoul(e, NULL, 16) : 0;
e = getenv("HAKMEM_SUPER_REG_DEBUG");
g_hak_env_cache.super_reg_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SUPERSLAB_MAX_CACHED");
g_hak_env_cache.superslab_max_cached = (e && *e) ? atoi(e) : 8;
e = getenv("HAKMEM_SUPERSLAB_MAX_MEMORY_MB");
g_hak_env_cache.superslab_max_memory_mb = (e && *e) ? atoi(e) : 256;
e = getenv("HAKMEM_SUPERSLAB_TTL_SEC");
g_hak_env_cache.superslab_ttl_sec = (e && *e) ? atoi(e) : 60;
e = getenv("HAKMEM_SS_LRU_DEBUG");
g_hak_env_cache.ss_lru_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_SS_PREWARM_DEBUG");
g_hak_env_cache.ss_prewarm_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_PREWARM_SUPERSLABS");
g_hak_env_cache.prewarm_superslabs = (e && *e) ? atoi(e) : 0;
}
// ===== Warm Path: Shared Pool Acquire =====
{
const char* e;
e = getenv("HAKMEM_SS_EMPTY_REUSE");
g_hak_env_cache.ss_empty_reuse = (e && *e && *e == '0') ? 0 : 1; // default: 1 (ON)
e = getenv("HAKMEM_SS_EMPTY_SCAN_LIMIT");
g_hak_env_cache.ss_empty_scan_limit = (e && *e) ? atoi(e) : 32; // default: 32
e = getenv("HAKMEM_SS_ACQUIRE_DEBUG");
g_hak_env_cache.ss_acquire_debug = (e && *e && *e != '0') ? 1 : 0;
e = getenv("HAKMEM_TINY_TENSION_DRAIN_ENABLE");
g_hak_env_cache.tiny_tension_drain_enable = (e == NULL || atoi(e) != 0) ? 1 : 0; // default: 1 (ON)
e = getenv("HAKMEM_TINY_TENSION_DRAIN_THRESHOLD");
g_hak_env_cache.tiny_tension_drain_threshold = (e && *e) ? atoi(e) : 1024; // default: 1024
if (g_hak_env_cache.tiny_tension_drain_threshold < 64) g_hak_env_cache.tiny_tension_drain_threshold = 64;
if (g_hak_env_cache.tiny_tension_drain_threshold > 65536) g_hak_env_cache.tiny_tension_drain_threshold = 65536;
}
// ===== Warm Path: SmallMid =====
{
const char* e;
e = getenv("HAKMEM_SMALLMID_ENABLE");
g_hak_env_cache.smallmid_enable = (e && atoi(e) == 1) ? 1 : 0; // default: 0 (OFF)
}
// ===== Cold Path: Debug/Timing =====
{
const char* e;
e = getenv("HAKMEM_TIMING");
g_hak_env_cache.timing_enabled = (e && strcmp(e, "1") == 0) ? 1 : 0; // default: 0 (OFF)
}
// ===== Cold Path: Batch =====
{
const char* e;
e = getenv("HAKMEM_BATCH_BG");
g_hak_env_cache.batch_bg = (e && atoi(e) != 0) ? 1 : 0; // default: 0 (OFF)
}
// ===== Cold Path: Superslab Madvise =====
{
const char* e = getenv("HAKMEM_SS_MADVISE_STRICT");
// Default: 1 (STRICT), set HAKMEM_SS_MADVISE_STRICT=0 to relax
g_hak_env_cache.ss_madvise_strict = (e && *e && *e == '0') ? 0 : 1;
}
#if !HAKMEM_BUILD_RELEASE
// Debug: Print cache summary (stderr only)
if (!g_hak_env_cache.quiet) {
fprintf(stderr, "[ENV_CACHE_INIT] Parsed %d ENV variables at startup\n", 50);
fprintf(stderr, "[ENV_CACHE_INIT] Hot path syscalls eliminated: ~2000/sec → 0/sec\n");
fflush(stderr);
}
#endif
}
// ============================================================================
// Accessor Macros (inline, zero-cost)
// ============================================================================
// Hot path accessors (use global cache, 1-2 cycle read)
#define HAK_ENV_TINY_ACTIVE_TRACK() (g_hak_env_cache.tiny_active_track)
#define HAK_ENV_TINY_ALLOC_1024_METRIC() (g_hak_env_cache.tiny_alloc_1024_metric)
#define HAK_ENV_TINY_PROFILE() (g_hak_env_cache.tiny_profile)
#define HAK_ENV_TINY_HEAP_V2_STATS() (g_hak_env_cache.tiny_heap_v2_stats)
#define HAK_ENV_TINY_FRONT_SLIM() (g_hak_env_cache.tiny_front_slim)
#define HAK_ENV_SFC_CASCADE_PCT() (g_hak_env_cache.sfc_cascade_pct)
#define HAK_ENV_TINY_SFC_CASCADE() (g_hak_env_cache.tiny_sfc_cascade)
#define HAK_ENV_TINY_NO_CLASS_MAP() (g_hak_env_cache.tiny_no_class_map)
#define HAK_ENV_TINY_LARSON_FIX() (g_hak_env_cache.tiny_larson_fix)
#define HAK_ENV_TINY_ALLOC_REMOTE_RELAX() (g_hak_env_cache.tiny_alloc_remote_relax)
#define HAK_ENV_TINY_SLL_DIAG() (g_hak_env_cache.tiny_sll_diag)
#define HAK_ENV_TINY_ROUTE_FREE() (g_hak_env_cache.tiny_route_free)
#define HAK_ENV_TINY_FREE_TO_SS() (g_hak_env_cache.tiny_free_to_ss)
#define HAK_ENV_SS_FREE_DEBUG() (g_hak_env_cache.ss_free_debug)
// Warm path accessors
#define HAK_ENV_SS_MAP_TRACE() (g_hak_env_cache.ss_map_trace)
#define HAK_ENV_TINY_FAST_DEBUG() (g_hak_env_cache.tiny_fast_debug)
#define HAK_ENV_TINY_FAST_DEBUG_MAX() (g_hak_env_cache.tiny_fast_debug_max)
#define HAK_ENV_TINY_FRONT_DIRECT() (g_hak_env_cache.tiny_front_direct)
#define HAK_ENV_TINY_FAST_STATS() (g_hak_env_cache.tiny_fast_stats)
#define HAK_ENV_TINY_UNIFIED_CACHE() (g_hak_env_cache.tiny_unified_cache)
#define HAK_ENV_SFC_DEBUG() (g_hak_env_cache.sfc_debug)
#define HAK_ENV_SFC_ENABLE() (g_hak_env_cache.sfc_enable)
#define HAK_ENV_SFC_CAPACITY() (g_hak_env_cache.sfc_capacity)
#define HAK_ENV_SFC_REFILL_COUNT() (g_hak_env_cache.sfc_refill_count)
// Cold path accessors
#define HAK_ENV_TINY_RESTORE_HEADER() (g_hak_env_cache.tiny_restore_header)
#define HAK_ENV_SUPER_LOOKUP_DEBUG() (g_hak_env_cache.super_lookup_debug)
#define HAK_ENV_QUIET() (g_hak_env_cache.quiet)
#define HAK_ENV_ALLOW_MALLOC_FALLBACK() (g_hak_env_cache.allow_malloc_fallback)
#define HAK_ENV_TINY_FREELIST_MASK() (g_hak_env_cache.tiny_freelist_mask)
#define HAK_ENV_SUPER_REG_DEBUG() (g_hak_env_cache.super_reg_debug)
#define HAK_ENV_SUPERSLAB_MAX_CACHED() (g_hak_env_cache.superslab_max_cached)
#define HAK_ENV_SUPERSLAB_MAX_MEMORY_MB() (g_hak_env_cache.superslab_max_memory_mb)
#define HAK_ENV_SUPERSLAB_TTL_SEC() (g_hak_env_cache.superslab_ttl_sec)
#define HAK_ENV_SS_LRU_DEBUG() (g_hak_env_cache.ss_lru_debug)
#define HAK_ENV_SS_PREWARM_DEBUG() (g_hak_env_cache.ss_prewarm_debug)
#define HAK_ENV_PREWARM_SUPERSLABS() (g_hak_env_cache.prewarm_superslabs)
// Warm path: Shared Pool Acquire
#define HAK_ENV_SS_EMPTY_REUSE() (g_hak_env_cache.ss_empty_reuse)
#define HAK_ENV_SS_EMPTY_SCAN_LIMIT() (g_hak_env_cache.ss_empty_scan_limit)
#define HAK_ENV_SS_ACQUIRE_DEBUG() (g_hak_env_cache.ss_acquire_debug)
#define HAK_ENV_TINY_TENSION_DRAIN_ENABLE() (g_hak_env_cache.tiny_tension_drain_enable)
#define HAK_ENV_TINY_TENSION_DRAIN_THRESHOLD() (g_hak_env_cache.tiny_tension_drain_threshold)
// Warm path: SmallMid
#define HAK_ENV_SMALLMID_ENABLE() (g_hak_env_cache.smallmid_enable)
// Cold path: Debug/Timing
#define HAK_ENV_TIMING_ENABLED() (g_hak_env_cache.timing_enabled)
// Cold path: Batch
#define HAK_ENV_BATCH_BG() (g_hak_env_cache.batch_bg)
// Cold path: Superslab Madvise
#define HAK_ENV_SS_MADVISE_STRICT() (g_hak_env_cache.ss_madvise_strict)
#endif // HAKMEM_ENV_CACHE_H