Files
hakmem/core/hakmem_policy.c
2025-12-01 22:06:10 +09:00

152 lines
6.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.

#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 = 2.00 (100%切り上げ許容) - Mid全域カバー重視
// - 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.602.00 (60-100%許容) — Mid MT を切った場合はこちら
// - w_max_large = 1.60 (60%許容) ⭐⭐⭐ 即効改善
//
// トレードオフ:
// - W_MAX大: ヒット率↑、内部断片化↑
// - W_MAX小: ヒット率↓、内部断片化↓
// ========================================================================
// shard/policy maps default to 0 (noop)
pol->w_max_mid = 2.00f; // Phase 7: Mid MT off → W_MAX緩和でMidクラス全域をカバー
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;
}