// tiny_near_empty_box.c - Tiny Near-Empty Slab Advisor (C2/C3) #include "tiny_near_empty_box.h" #include #include #include // Per-class near-empty events(観測用カウンタ) _Atomic uint64_t g_tiny_near_empty_events[TINY_NUM_CLASSES] = {0}; // ENV ゲート: HAKMEM_TINY_SS_PACK_C23=1 のときのみ有効。 static int g_tiny_near_empty_enabled = -1; int tiny_near_empty_enabled(void) { if (__builtin_expect(g_tiny_near_empty_enabled == -1, 0)) { const char* e = getenv("HAKMEM_TINY_SS_PACK_C23"); g_tiny_near_empty_enabled = (e && *e && *e != '0') ? 1 : 0; } return g_tiny_near_empty_enabled; } // near-empty 判定のしきい値 (%) static _Atomic int g_tiny_near_empty_pct = 0; // 0 = 未初期化 int tiny_near_empty_get_pct(void) { int pct = atomic_load_explicit(&g_tiny_near_empty_pct, memory_order_relaxed); if (pct == 0) { // ENV 初期化 pct = 25; const char* env = getenv("HAKMEM_TINY_NEAREMPTY_PCT"); if (env && *env) { int v = atoi(env); if (v >= 1 && v <= 99) { pct = v; } } atomic_store_explicit(&g_tiny_near_empty_pct, pct, memory_order_relaxed); } return pct; } void tiny_near_empty_set_pct(int pct) { if (pct < 1 || pct > 99) { return; } atomic_store_explicit(&g_tiny_near_empty_pct, pct, memory_order_relaxed); } // 内部実装: free パスから呼ばれる near-empty 判定本体。 void tiny_near_empty_on_free_impl(int class_idx, TinySlabMeta* meta) { if (class_idx < 0 || class_idx >= TINY_NUM_CLASSES) { return; } // いまは C2/C3 のみ対象 if (class_idx != 2 && class_idx != 3) { return; } if (!meta) { return; } uint16_t used = meta->used; uint16_t cap = meta->capacity; if (used == 0 || cap == 0) { return; } int pct = tiny_near_empty_get_pct(); // 使用率 <= pct% を near-empty と定義 // used * 100 <= cap * pct if ((uint32_t)used * 100u > (uint32_t)cap * (uint32_t)pct) { return; } atomic_fetch_add_explicit(&g_tiny_near_empty_events[class_idx], 1, memory_order_relaxed); } void tiny_near_empty_stats_snapshot(uint64_t events[TINY_NUM_CLASSES], int reset) { if (!events && !reset) { return; } for (int c = 0; c < TINY_NUM_CLASSES; c++) { if (events) { events[c] = atomic_load_explicit(&g_tiny_near_empty_events[c], memory_order_relaxed); } if (reset) { atomic_store_explicit(&g_tiny_near_empty_events[c], 0, memory_order_relaxed); } } } // オプション: near-empty 統計をプロセス終了時に 1 回だけダンプ(デバッグ専用) // ENV: HAKMEM_TINY_NEAREMPTY_DUMP=1 または HAKMEM_STATS=nearempty で有効化。 #if !HAKMEM_BUILD_RELEASE #include "../hakmem_stats_master.h" // Phase 4d: Master stats control static void tiny_near_empty_dump_stats(void) __attribute__((destructor)); static void tiny_near_empty_dump_stats(void) { if (!hak_stats_check("HAKMEM_TINY_NEAREMPTY_DUMP", "nearempty")) { return; } fprintf(stderr, "[TINY_NEAR_EMPTY_STATS] class events\n"); for (int c = 0; c < TINY_NUM_CLASSES; c++) { uint64_t v = atomic_load_explicit(&g_tiny_near_empty_events[c], memory_order_relaxed); if (v != 0) { fprintf(stderr, " C%d: %llu\n", c, (unsigned long long)v); } } } #endif