Files
hakmem/core/hakmem_policy.c

152 lines
6.1 KiB
C
Raw Normal View History

#include "hakmem_policy.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
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.401.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;
}