Files
hakmem/core/hakmem_tiny_background.inc
Moe Charm (CI) acc64f2438 Phase ML1: Pool v1 memset 89.73% overhead 軽量化 (+15.34% improvement)
## Summary
- ChatGPT により bench_profile.h の setenv segfault を修正(RTLD_NEXT 経由に切り替え)
- core/box/pool_zero_mode_box.h 新設:ENV キャッシュ経由で ZERO_MODE を統一管理
- core/hakmem_pool.c で zero mode に応じた memset 制御(FULL/header/off)
- A/B テスト結果:ZERO_MODE=header で +15.34% improvement(1M iterations, C6-heavy)

## Files Modified
- core/box/pool_api.inc.h: pool_zero_mode_box.h include
- core/bench_profile.h: glibc setenv → malloc+putenv(segfault 回避)
- core/hakmem_pool.c: zero mode 参照・制御ロジック
- core/box/pool_zero_mode_box.h (新設): enum/getter
- CURRENT_TASK.md: Phase ML1 結果記載

## Test Results
| Iterations | ZERO_MODE=full | ZERO_MODE=header | Improvement |
|-----------|----------------|-----------------|------------|
| 10K       | 3.06 M ops/s   | 3.17 M ops/s    | +3.65%     |
| 1M        | 23.71 M ops/s  | 27.34 M ops/s   | **+15.34%** |

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-10 09:08:18 +09:00

172 lines
8.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Background Refill Bin (per-class lock-free SLL) — fills in background so the
// front path only does a single CAS pop when both slots/bump are empty.
static int g_bg_bin_enable = 0; // ENV toggle removed (fixed OFF)
static _Atomic uintptr_t g_bg_bin_head[TINY_NUM_CLASSES];
// Inline helpers
#include "hakmem_tiny_bg_bin.inc.h"
// ============================================================================
// EXTRACTED TO hakmem_tiny_remote_target.c (Phase 2C-1)
// ============================================================================
// Targeted remote-drain queue moved to separate module
// Functions: remote_target_enqueue(), remote_target_pop()
// Variables: g_remote_target_head, g_remote_target_len
// NOTE: g_bg_remote_enable, g_bg_remote_batch REMOVED (dead code cleanup 2025-11-27)
// ============================================================================
// EXTRACTED TO hakmem_tiny_bg_spill.c/.h (Phase 2C-2)
// ============================================================================
// Background spill/drain queue for SuperSlab freelist returns
// Functions: bg_spill_push_one(), bg_spill_push_chain(), bg_spill_drain_class(), bg_spill_init()
// Variables: g_bg_spill_enable, g_bg_spill_target, g_bg_spill_max_batch, g_bg_spill_head[], g_bg_spill_len[]
static inline void eventq_push(int class_idx, uint32_t size) {
eventq_push_ex(class_idx, size, HAK_TIER_FRONT, 0, 0, 0);
}
static __attribute__((unused)) void* intelligence_engine_main(void* arg) {
(void)arg;
const int sleep_us = 100000; // 100ms
int hist[TINY_NUM_CLASSES] = {0};
int cnt[TINY_NUM_CLASSES] = {0};
// Tiny の学習は既定でOFF実アプリは後段で学習
// HAKMEM_INT_ADAPT_REFILL=1 / HAKMEM_INT_ADAPT_CAPS=1 を明示設定した場合のみON
int adapt_refill = 0; // default OFF for Tiny
int adapt_caps = 0; // default OFF for Tiny (env can enable)
char* arf = getenv("HAKMEM_INT_ADAPT_REFILL");
if (arf) adapt_refill = (atoi(arf) != 0);
char* acp = getenv("HAKMEM_INT_ADAPT_CAPS");
if (acp) adapt_caps = (atoi(acp) != 0);
const int REFILL_MIN = 32, REFILL_MAX = 256;
const int REFILL_HOT_MIN = 96, REFILL_HOT_MAX = 320;
// Tiny diet (memory-tight) knobs
{
char* rb = getenv("HAKMEM_TINY_RSS_BUDGET_KB");
if (rb) { int v = atoi(rb); if (v > 0) g_tiny_rss_budget_kb = v; }
char* st = getenv("HAKMEM_TINY_DIET_STEP");
if (st) { int v = atoi(st); if (v > 0 && v < 256) g_tiny_diet_step = v; }
char* tt = getenv("HAKMEM_TINY_INT_TIGHT");
if (tt) g_tiny_int_tight = (atoi(tt) != 0);
for (int k = 0; k < TINY_NUM_CLASSES; k++) {
char var[64]; snprintf(var, sizeof(var), "HAKMEM_TINY_CAP_FLOOR_C%d", k);
char* vf = getenv(var);
if (vf) { int v = atoi(vf); if (v > 0 && v < TINY_TLS_MAG_CAP) g_tiny_cap_floor[k] = v; }
}
}
// Idle trim knob
int idle_trim_ms = 0;
int idle_flush = 0; // flush magazines on idle tick (optional)
{
char* it = getenv("HAKMEM_TINY_IDLE_TRIM_MS");
if (it) { int v = atoi(it); if (v > 0) idle_trim_ms = v; }
char* iff = getenv("HAKMEM_TINY_IDLE_FLUSH");
if (iff) idle_flush = (atoi(iff) != 0);
}
int idle_trim_ticks = (idle_trim_ms > 0) ? (idle_trim_ms * 1000 / sleep_us) : 0;
int idle_tick = 0;
while (!g_int_stop) {
// Drain events
uint32_t h = atomic_load_explicit(&g_ev_head, memory_order_relaxed);
uint32_t t = atomic_load_explicit(&g_ev_tail, memory_order_acquire);
while (h != t) {
AllocEvent ev = g_ev_ring[h & EVENTQ_MASK];
if (ev.class_idx < TINY_NUM_CLASSES) {
hist[ev.class_idx]++;
// TODO: use ev.tier_hit/flags/site_id for richer adaptations
}
h++;
}
atomic_store_explicit(&g_ev_head, h, memory_order_release);
// Snapshot counts for this window
for (int k = 0; k < TINY_NUM_CLASSES; k++) { cnt[k] = hist[k]; }
// Simple adaptive rule: if class seen a lot, increase fill target; else reduce
for (int k = 0; k < TINY_NUM_CLASSES; k++) {
int count = cnt[k];
hist[k] = 0; // reset for next window
int cur = atomic_load_explicit(&g_frontend_fill_target[k], memory_order_relaxed);
if (count > 1000) {
int nv = cur + 32; if (nv > 256) nv = 256; // cap
atomic_store_explicit(&g_frontend_fill_target[k], nv, memory_order_relaxed);
} else if (count < 200) {
int nv = cur - 16; if (nv < 0) nv = 0;
atomic_store_explicit(&g_frontend_fill_target[k], nv, memory_order_relaxed);
}
}
// Stage 1: adjust refill batch bounds by class grouping (hot tiny vs others)
if (adapt_refill) {
int hot_sum = 0, other_sum = 0;
for (int k = 0; k < TINY_NUM_CLASSES; k++) {
int cur = atomic_load_explicit(&g_frontend_fill_target[k], memory_order_relaxed);
if (k <= 3) hot_sum += cur; else other_sum += cur;
}
if (hot_sum > 512) {
int nv = g_tiny_refill_max_hot + 16; if (nv > REFILL_HOT_MAX) nv = REFILL_HOT_MAX; g_tiny_refill_max_hot = nv;
} else if (hot_sum < 64) {
int nv = g_tiny_refill_max_hot - 16; if (nv < REFILL_HOT_MIN) nv = REFILL_HOT_MIN; g_tiny_refill_max_hot = nv;
}
if (other_sum > 256) {
int nv = g_tiny_refill_max + 16; if (nv > REFILL_MAX) nv = REFILL_MAX; g_tiny_refill_max = nv;
} else if (other_sum < 32) {
int nv = g_tiny_refill_max - 16; if (nv < REFILL_MIN) nv = REFILL_MIN; g_tiny_refill_max = nv;
}
}
// Adapt per-class MAG caps (light-touch; protects hot classes)
if (adapt_caps) {
for (int k = 0; k < TINY_NUM_CLASSES; k++) {
int hot = (k <= 3);
// Heuristic thresholds per window
// Hot classes raise caps more aggressively
int up_th = hot ? 800 : 1000;
int dn_th = hot ? 120 : 200;
if (g_tiny_int_tight) { dn_th = hot ? 200 : 300; }
// MAG cap override: move toward [min..max] within guard rails
int mag = g_mag_cap_override[k];
int mag_min;
switch (k) {
case 0: case 1: case 2: mag_min = 128; break; // 8/16/32B
case 3: mag_min = 256; break; // 64B (allow larger later)
case 4: mag_min = 128; break; // 128B
default: mag_min = 64; break;
}
int mag_max = 512; // soft ceiling; global hard ceiling is TINY_TLS_MAG_CAP
if (k == 3) mag_max = 1024;
if (mag <= 0) mag = mag_min; // start from baseline
if (cnt[k] > up_th) { mag += 16; if (mag > mag_max) mag = mag_max; }
else if (cnt[k] < dn_th) { mag -= 16; if (mag < mag_min) mag = mag_min; }
g_mag_cap_override[k] = mag;
}
}
// Enforce Tiny RSS budget (if enabled): when over budget, shrink per-class caps by step
if (g_tiny_rss_budget_kb > 0) {
int rss = get_rss_kb_self();
if (rss > g_tiny_rss_budget_kb) {
for (int k = 0; k < TINY_NUM_CLASSES; k++) {
int floor = g_tiny_cap_floor[k]; if (floor <= 0) floor = 64;
int mag = g_mag_cap_override[k]; if (mag <= 0) mag = tiny_effective_cap(k);
mag -= g_tiny_diet_step; if (mag < floor) mag = floor; g_mag_cap_override[k] = mag;
}
}
}
// Optional periodic idle trim (try to keep overhead small)
if (idle_trim_ticks > 0) {
idle_tick++;
if (idle_tick >= idle_trim_ticks) {
idle_tick = 0;
// Optional bounded flush of magazines to enable SS empty detection
if (idle_flush) hak_tiny_magazine_flush_all();
// Bounded trim: uses per-class locks briefly; acceptable in background
hak_tiny_trim();
}
}
usleep(sleep_us);
}
return NULL;
}