152 lines
6.2 KiB
C
152 lines
6.2 KiB
C
#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.60~2.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;
|
||
}
|