#include "hakmem_policy.h" #include #include #include static _Atomic(FrozenPolicy*) g_frozen_pol = NULL; void hkm_policy_init(void) { FrozenPolicy* pol = (FrozenPolicy*)calloc(1, sizeof(FrozenPolicy)); if (!pol) return; // Defaults aligned with current implementation // Tiny caps: keep placeholders (not enforced in hot path yet) pol->tiny_cap[0] = 2048; pol->tiny_cap[1] = 1024; pol->tiny_cap[2] = 768; pol->tiny_cap[3] = 512; pol->tiny_cap[4] = 256; pol->tiny_cap[5] = 256; pol->tiny_cap[6] = 128; pol->tiny_cap[7] = 64; // ======================================================================== // CAP初期値の設計思想: // ======================================================================== // 現在の値は「保守的」設定(メモリフットプリント優先): // - Mid: {64, 64, 64, 32, 16} → 合計 15.0 MB (64KB/page) // - Large: {8, 8, 4, 2, 1} → 合計 4.5 MB // // パフォーマンス優先設定(推奨): // - Mid: {256, 256, 256, 128, 64} → 合計 60.0 MB (4倍化) // - Large: {32, 32, 16, 8, 4} → 合計 18.0 MB (4倍化) // // トレードオフ: // - CAP大: ヒット率↑、フットプリント↑ // - CAP小: ヒット率↓、フットプリント↓ // // 環境変数で変更可能: // HAKMEM_CAP_MID=256,256,256,128,64 // HAKMEM_CAP_LARGE=32,32,16,8,4 // ======================================================================== // L1: Mid/Large caps – Phase 6.21: Revert to conservative + Bridge classes // Phase 2: Mid={256,256,256,128,64} Large={32,32,16,8,4} (4x, 78MB total) // Phase 6.21: Mid={64,64,64,32,16,32,32} Large={8,8,4,2,1} (1x + bridges, ~22MB total) // Bridge classes (40KB, 52KB) now hardcoded in g_class_sizes[], CAP=32 each uint16_t mid_defaults[7] = { 64, 64, 64, 32, 16, 32, 32 }; // Added slots 5,6 for Bridge uint16_t large_defaults[5] = { 8, 8, 4, 2, 1 }; // Reverted to 1x memcpy(pol->mid_cap, mid_defaults, sizeof(mid_defaults)); memcpy(pol->large_cap, large_defaults, sizeof(large_defaults)); // Phase 6.21: Disable DYN1/DYN2 (replaced by hardcoded Bridge classes) pol->mid_dyn1_bytes = 0; // Disabled (Bridge classes now hardcoded) pol->mid_cap_dyn1 = 0; pol->mid_dyn2_bytes = 0; // Disabled pol->mid_cap_dyn2 = 0; // ======================================================================== // W_MAX (切り上げ許容倍率) の設計思想: // ======================================================================== // W_MAX = 要求サイズの何倍までのクラスを許容するか // // 現在の値: // - w_max_mid = 1.40 (40%切り上げ許容) - やや保守的 // - w_max_large = 1.30 (30%切り上げ許容) - 保守的 **問題あり** // // 問題点: // w_max_large=1.30だと、32-64KBギャップで多くの要求が弾かれる // 例: 35KB要求 → 64KB使用は 1.83倍 > 1.30 → NG → malloc fallback // // 推奨値: // - w_max_mid = 1.40~1.60 (40-60%許容) // - w_max_large = 1.60 (60%許容) ⭐⭐⭐ 即効改善 // // トレードオフ: // - W_MAX大: ヒット率↑、内部断片化↑ // - W_MAX小: ヒット率↓、内部断片化↓ // ======================================================================== // shard/policy maps default to 0 (noop) pol->w_max_mid = 1.60f; // Phase 6.25: Looser for MidPool performance (was 1.40) pol->w_max_large = 1.30f; // Phase 6.21: Revert to 1.30 (Bridge classes now cover 32-64KB gap) pol->w_max = 1.6f; // legacy aggregate (unused by ACE) pol->thp_threshold = 2 * 1024 * 1024; // 2MiB pol->generation = 1; // Optional env overrides for quick experiments const char* e_mid = getenv("HAKMEM_WMAX_MID"); if (e_mid) { float v = (float)atof(e_mid); if (v >= 1.0f && v <= 2.0f) pol->w_max_mid = v; } const char* e_large = getenv("HAKMEM_WMAX_LARGE"); if (e_large) { float v = (float)atof(e_large); if (v >= 1.0f && v <= 2.0f) pol->w_max_large = v; } // Optional CAP overrides: comma-separated integers per class const char* cap_mid = getenv("HAKMEM_CAP_MID"); if (cap_mid) { char buf[256]; strncpy(buf, cap_mid, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; char* save = NULL; char* tok = strtok_r(buf, ",", &save); int i=0; while (tok && i < 5) { pol->mid_cap[i++] = (uint16_t)atoi(tok); tok = strtok_r(NULL, ",", &save); } } const char* cap_lg = getenv("HAKMEM_CAP_LARGE"); if (cap_lg) { char buf[256]; strncpy(buf, cap_lg, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; char* save = NULL; char* tok = strtok_r(buf, ",", &save); int i=0; while (tok && i < 5) { pol->large_cap[i++] = (uint16_t)atoi(tok); tok = strtok_r(NULL, ",", &save); } } // Optional dynamic Mid class from env (bytes) const char* dyn1 = getenv("HAKMEM_MID_DYN1"); if (dyn1) { long v = atol(dyn1); if (v >= 2048 && v <= 32768) pol->mid_dyn1_bytes = (uint32_t)v; } const char* cap_dyn1 = getenv("HAKMEM_CAP_MID_DYN1"); if (cap_dyn1) { int v = atoi(cap_dyn1); if (v >= 0 && v < 65535) pol->mid_cap_dyn1 = (uint16_t)v; } const char* dyn2 = getenv("HAKMEM_MID_DYN2"); if (dyn2) { long v = atol(dyn2); if (v >= 2048 && v <= 32768) pol->mid_dyn2_bytes = (uint32_t)v; } const char* cap_dyn2 = getenv("HAKMEM_CAP_MID_DYN2"); if (cap_dyn2) { int v = atoi(cap_dyn2); if (v >= 0 && v < 65535) pol->mid_cap_dyn2 = (uint16_t)v; } atomic_store(&g_frozen_pol, pol); } void hkm_policy_publish(FrozenPolicy* new_pol) { if (!new_pol) return; FrozenPolicy* old = atomic_exchange(&g_frozen_pol, new_pol); // NOTE: In a real RCU scheme we would wait for a grace period. // For now, free the old snapshot immediately. free(old); } const FrozenPolicy* hkm_policy_get(void) { FrozenPolicy* pol = atomic_load(&g_frozen_pol); return pol; }