Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
15 KiB
15 KiB
Phase 6.11: 動的閾値学習 - ELO による閾値最適化
Date: 2025-10-21 Status: 設計完了(実装待機) 発案者: tomoaki(ユーザー) 詳細設計: ChatGPT Pro
🎯 コンセプト
tomoaki の発想:
「ELO なんだから、キャッシュの固定値その物を学習して動かせばいいんじゃにゃい?」
ChatGPT の詳細化:
- 全部を常時動かすのはNG
- 3〜5個の効きが大きい閾値だけを対象
- CANARY 窓で小さく試してから FROZEN に焼く
📊 学習対象の閾値(効果順)
★★★ 最優先(効果大/副作用小)
1. W_MAX(切り上げ許容率)
// 上位クラス流用の許容度
// 例: 20KB 要求 → 32KB クラスを使う(32/20 = 1.6)
W_MAX ∈ {1.25, 1.5, 1.75, 2.0}
役割:
- 20KB → 32KB のような上位クラス流用の"どこまで許すか"
効きどころ:
- 中粒(2〜32KiB)のプールヒット率 ↑
- mir/mixed の p99 改善
具体例:
W_MAX = 1.25(厳しめ):
- 20KB 要求 → 25KB 以下のクラスのみ使用
- ヒット率: 低い
- メモリ効率: 高い(無駄少ない)
W_MAX = 1.75(緩め):
- 20KB 要求 → 35KB 以下のクラスまで使用
- ヒット率: 高い
- メモリ効率: やや低い(無駄増える)
→ ELO が最適値を学習
2. Hot/Warm/Cold の境界(ms)
// 再利用間隔に基づく Free policy 切り替え
hot_ms ∈ {50, 100, 200} // Hot: < 100ms → KEEP
warm_ms ∈ {500, 800, 1200} // Warm: 100-800ms → FREE (MADV_FREE)
// Cold: >= 800ms → DONTNEED (batch)
効きどころ:
- minor-faults と RSS のバランス最適化
- 頻繁な再利用を KEEP で高速化
具体例:
hot_ms = 50(厳しめ):
- 50ms 以内の再利用のみ KEEP
- minor-faults: 多い
- RSS: 少ない
hot_ms = 200(緩め):
- 200ms 以内の再利用を KEEP
- minor-faults: 少ない
- RSS: 多い
→ ELO がワークロードに最適な境界を学習
3. BATCH_THRESHOLD の基準レンジ(下限/上限)
// madvise バッチ処理の対象範囲
BATCH_RANGE ∈ {(64KiB, 2MiB), (128KiB, 4MiB), (256KiB, 8MiB)}
効きどころ:
- madvise 呼びすぎ/返さなさすぎの両極端を回避
- syscall 頻度と RSS のバランス
★★ 次優先(環境依存)
4. THP gate(HugePage 適用最小サイズ)
THP_THRESHOLD ∈ {1MB, 2MB, 4MB}
効きどころ:
- vm(大塊)の TLB/fault 最適化
- 環境依存なので慎重に
5. mmap_cutover(mmap に切替えるサイズ)
MMAP_CUTOVER ∈ {512KB, 768KB, 1MB, 2MB}
効きどころ:
- 巨大側の syscall 頻度・断片化最適化
🔧 学習方法(軽量バンディット)
基本方針
FROZEN:
- 閾値は固定(読み取りのみ、オーバーヘッドゼロ)
CANARY 窓(30〜60秒):
- 候補閾値を試す
- 報酬を集計
- 勝者を採択
FROZEN(採用後):
- 新しい閾値で凍結
- 一定時間(dwell time)は変更禁止
候補数の最適解: 3候補(ChatGPT Pro 推奨)
理由:
- 3候補: 探索空間を抑えつつ十分なバリエーション
- 2候補では選択肢が少なすぎる
- 4候補以上では収束が遅い(CANARY 窓数が増える)
- ε-greedy (ε=0.1): 10%探索、90%最良選択で効率的
- CANARY window: 30秒で新候補テスト可能
- Hysteresis: ±1 step のみ変更で安定性確保
初期値の選び方:
- 中間値を初期値とする(例: W_MAX は 1.5)
- 理由: 両方向に探索可能(上下に候補あり)
1. 候補集合の離散化
// W_MAX の候補
const double W_MAX_CANDIDATES[] = {1.25, 1.5, 1.75};
const int W_MAX_NUM_CANDIDATES = 3;
// hot_ms の候補
const int HOT_MS_CANDIDATES[] = {50, 100, 200};
const int HOT_MS_NUM_CANDIDATES = 3;
// warm_ms の候補(順序制約: hot_ms < warm_ms)
const int WARM_MS_CANDIDATES[] = {500, 800, 1200};
const int WARM_MS_NUM_CANDIDATES = 3;
// BATCH_RANGE の候補
typedef struct {
size_t min;
size_t max;
} BatchRange;
const BatchRange BATCH_RANGE_CANDIDATES[] = {
{64 * 1024, 2 * 1024 * 1024},
{128 * 1024, 4 * 1024 * 1024},
{256 * 1024, 8 * 1024 * 1024}
};
const int BATCH_RANGE_NUM_CANDIDATES = 3;
2. 報酬(reward)の定義
// 窓ごとに報酬を計算
typedef struct {
double p99; // レイテンシ P99
uint64_t minor_faults; // minor page faults
uint64_t syscalls; // syscall 回数
uint64_t rss_kb; // RSS (KB)
} Metrics;
// 改善率の計算
static inline double improv(double current, double baseline) {
if (baseline == 0) return 0.0;
return (baseline - current) / baseline;
}
// RSS ペナルティ(増えすぎたらマイナス)
static inline double rss_penalty(uint64_t rss, uint64_t baseline_rss) {
if (rss <= baseline_rss * 1.1) return 0.0; // 10% までは許容
return (double)(rss - baseline_rss * 1.1) / (double)baseline_rss;
}
// 総合報酬(重み付き和)
double calculate_reward(Metrics m, Metrics baseline) {
const double wL = 0.5; // latency 重み
const double wF = 0.3; // faults 重み
const double wS = 0.1; // syscalls 重み
const double wR = 0.1; // RSS penalty 重み
return wL * improv(m.p99, baseline.p99)
+ wF * improv(m.minor_faults, baseline.minor_faults)
+ wS * improv(m.syscalls, baseline.syscalls)
- wR * rss_penalty(m.rss_kb, baseline.rss_kb);
}
3. 探索(ε-greedy)
// Arm(候補)の状態
typedef struct {
double avg_reward; // 平均報酬
int count; // 試行回数
} Arm;
// W_MAX の Arm(3候補)
static Arm g_arms_wmax[3] = {{0.0, 0}, {0.0, 0}, {0.0, 0}};
static int g_current_wmax_idx = 1; // 初期値: 1.5
// ε-greedy 選択
#define EPSILON 0.1 // 10% の確率でランダム探索
static int select_arm_epsilon_greedy(Arm* arms, int num_arms, int current_idx) {
// 10% の確率でランダム
if ((rand() % 100) < (EPSILON * 100)) {
return rand() % num_arms;
}
// 90% の確率で最良 Arm
int best_idx = 0;
double best_avg = arms[0].avg_reward;
for (int i = 1; i < num_arms; i++) {
if (arms[i].avg_reward > best_avg) {
best_avg = arms[i].avg_reward;
best_idx = i;
}
}
return best_idx;
}
4. 採択ゲート(勝者判定)
// 採択条件
#define MIN_SAMPLES 10 // 最低試行回数
#define CONFIDENCE_LEVEL 1.96 // 95% 信頼区間
// 95% 信頼区間の上限
static double upper_confidence_bound(Arm* arm) {
if (arm->count == 0) return 0.0;
// 標準誤差(簡易版:分散を 1 と仮定)
double se = 1.0 / sqrt(arm->count);
return arm->avg_reward + CONFIDENCE_LEVEL * se;
}
// 勝者判定(現在の設定より有意に良いか?)
static int is_improvement_significant(Arm* candidate, Arm* current) {
if (candidate->count < MIN_SAMPLES) return 0;
if (current->count < MIN_SAMPLES) return 1; // 現在が未学習なら即採用
// 候補の下限 > 現在の上限 → 有意な改善
double candidate_lower = candidate->avg_reward - CONFIDENCE_LEVEL / sqrt(candidate->count);
double current_upper = current->avg_reward + CONFIDENCE_LEVEL / sqrt(current->count);
return candidate_lower > current_upper;
}
5. ヒステリシス(揺れ防止)
// 1回の採用で ±1 ステップまで
#define MAX_STEP 1
// Dwell time(採用後の変更禁止期間)
#define DWELL_TIME_SEC 600 // 10分
static time_t g_last_adoption_time = 0;
static int clamp_step(int current_idx, int new_idx, int max_step) {
int diff = new_idx - current_idx;
if (diff > max_step) return current_idx + max_step;
if (diff < -max_step) return current_idx - max_step;
return new_idx;
}
static int can_adopt(void) {
time_t now = time(NULL);
return (now - g_last_adoption_time) >= DWELL_TIME_SEC;
}
6. CANARY 窓終端での更新
// CANARY 窓終端(30〜60秒ごと)に呼ばれる
void canary_window_end(Metrics m, Metrics baseline) {
if (!can_adopt()) return; // Dwell time 中は何もしない
// 今回試した候補の報酬を記録
double reward = calculate_reward(m, baseline);
int cur_arm = g_current_wmax_idx; // 今回使った Arm
g_arms_wmax[cur_arm].avg_reward =
(g_arms_wmax[cur_arm].avg_reward * g_arms_wmax[cur_arm].count + reward)
/ (g_arms_wmax[cur_arm].count + 1);
g_arms_wmax[cur_arm].count++;
// 十分なサンプルが溜まったら勝者を判定
if (g_arms_wmax[cur_arm].count >= MIN_SAMPLES) {
int best = select_arm_epsilon_greedy(g_arms_wmax, W_MAX_NUM_CANDIDATES, cur_arm);
if (is_improvement_significant(&g_arms_wmax[best], &g_arms_wmax[cur_arm])) {
// ヒステリシス(±1 ステップまで)
int new_idx = clamp_step(g_current_wmax_idx, best, MAX_STEP);
if (new_idx != g_current_wmax_idx) {
// 採用!
g_current_wmax_idx = new_idx;
g_frozen_policy.W_MAX = W_MAX_CANDIDATES[new_idx];
printf("[ELO] W_MAX adopted: %.2f (arm %d)\n",
g_frozen_policy.W_MAX, new_idx);
g_last_adoption_time = time(NULL);
// Arm をリセット(次の CANARY まで)
for (int i = 0; i < W_MAX_NUM_CANDIDATES; i++) {
g_arms_wmax[i].avg_reward *= 0.9; // 減衰
g_arms_wmax[i].count = (int)(g_arms_wmax[i].count * 0.9);
}
}
}
}
}
🎯 Site Rules との併用
優先順位
[入力] (size, pc/site)
┌─ Step 1: Site Rules ルックアップ(O(1))
│ hit? → route/shard を即適用
│ miss? → Step 2 へ
│
└─ Step 2: FrozenPolicy(閾値学習の結果を使用)
- W_MAX で上位クラス流用判定
- hot_ms/warm_ms で Free policy 決定
- BATCH_RANGE で batch 対象判定
ポイント:
- Site Rule で route 固定している
(site, class)には閾値学習は影響しない - 閾値学習は "既定"側を更新(Site Rule がない場合のフォールバック)
- 局所は Site Rule、全体は閾値学習できれいに分業
📈 期待される効果
W_MAX 学習
現状(固定 W_MAX = 1.5):
- 20KB 要求 → 32KB クラス(1.6 > 1.5 なので不可)
- Pool ミス → malloc へフォールバック
学習後(W_MAX = 1.75):
- 20KB 要求 → 32KB クラス(1.6 < 1.75 なので可)
- Pool ヒット!
効果:
- L2 Pool ヒット率: +15〜35%
- mir/mixed の p99: -10〜25%
Hot/Warm/Cold 境界学習
現状(固定 hot_ms = 100, warm_ms = 800):
- 150ms で再利用 → Warm 扱い(MADV_FREE)
- minor-faults 発生
学習後(hot_ms = 200, warm_ms = 1200):
- 150ms で再利用 → Hot 扱い(KEEP)
- minor-faults 削減
効果:
- minor-faults/sec: -30〜70%(Warm 厚めが効く)
BATCH_RANGE 学習
現状(固定 64KiB〜2MiB):
- 3MiB 要求 → batch 対象外(即時 munmap)
- syscall 多い
学習後(128KiB〜4MiB):
- 3MiB 要求 → batch 対象(遅延 munmap)
- syscall 削減
効果:
- madvise/sec: -20〜40%
- RSS 変動のスパイク抑制
⚠️ ガードレール(必須制約)
1. 順序制約
// hot_ms < warm_ms を常に保証
if (new_hot_ms >= current_warm_ms) {
return; // 不正な組み合わせは拒否
}
// BATCH_MIN ≤ BATCH_MAX を保証
if (new_batch_min > new_batch_max) {
return; // 不正な組み合わせは拒否
}
// W_MAX ≥ 1.0 を保証
if (new_wmax < 1.0) {
return; // 不正な値は拒否
}
2. Dwell time(変更禁止期間)
// 採用直後は 10 分間変更禁止
#define DWELL_TIME_SEC 600
// 揺れ防止
if (!can_adopt()) {
return; // まだ変更できない
}
3. ±1 ステップ制限
// 1回の採用で ±1 ステップまで
// (大ジャンプ禁止)
int new_idx = clamp_step(current_idx, best_idx, 1);
4. 安全弁固定(頻繁に動かさない)
// これらは月次/週次レベルでのみ調整
// - mmap_cutover(影響が大きい)
// - THP gate(環境依存)
🚀 最小セット(すぐ始めるなら)
Phase 6.11.1: W_MAX 学習のみ
// 候補
W_MAX ∈ {1.25, 1.5, 1.75}
// CANARY 窓
30〜60秒
// 報酬
wL=0.5 (p99), wF=0.3 (faults), wS=0.1 (syscalls), wR=0.1 (RSS)
// 探索
ε-greedy (ε=0.1)
// 採択
±1 ステップ、dwell time 10分
期待効果:
- L2 Pool ヒット率: +20%
- mir/mixed の p99: -15%
Phase 6.11.2: Hot/Warm/Cold 境界追加
// 候補(格子探索)
hot_ms ∈ {50, 100, 200}
warm_ms ∈ {600, 900, 1200}
// 順序制約
hot_ms < warm_ms を常に保証
期待効果:
- minor-faults/sec: -40%
Phase 6.11.3: BATCH_RANGE 追加
// 候補
BATCH_RANGE ∈ {(64K, 2M), (128K, 4M), (256K, 8M)}
期待効果:
- madvise/sec: -30%
- RSS スパイク抑制
📊 オーバーヘッド
FROZEN 時(通常)
オーバーヘッド: ゼロ
- 閾値は固定値を読み取るだけ
- per-op コストなし
CANARY 窓(30〜60秒ごと)
オーバーヘッド: O(1) 集計のみ
- 窓終端での報酬計算
- Arm 更新
- 勝者判定
所要時間: < 1ms(無視できる)
🎯 まとめ
✅ ユーザーの洞察は完璧
「ELO なんだから、キャッシュの固定値その物を学習して動かせばいい」
→ その通り!閾値自体を ELO で最適化すべき
🚀 実装プラン
Phase 6.11.1: W_MAX 学習
- 候補: {1.25, 1.5, 1.75}
- ε-greedy 探索
- CANARY 窓で採択
Phase 6.11.2: Hot/Warm/Cold 境界
- 候補: hot_ms ∈ {50, 100, 200}, warm_ms ∈ {600, 900, 1200}
- 格子探索
Phase 6.11.3: BATCH_RANGE
- 候補: {(64K, 2M), (128K, 4M), (256K, 8M)}
期待効果:
- L2 Pool ヒット率: +20%
- minor-faults/sec: -40%
- madvise/sec: -30%
- オーバーヘッド: ゼロ(FROZEN 時)
ChatGPT の助言:
- 対象を 3〜5 個に絞る(全部動かさない)
- CANARY 窓で小さく試す(30〜60秒)
- ±1 ステップ制限(大ジャンプ禁止)
- Dwell time 10分(揺れ防止)
これで mimalloc の "adaptive size classes" を ELO で自動化!😺✨
Generated: 2025-10-21 発案者: tomoaki(ユーザー) 詳細設計: ChatGPT Pro 実装: Phase 6.11.1 から段階的に開始予定 システム名: SACS (Site-Aware Adaptive Cache System) の一部