Files
hakmem/core/box/ss_prefault_box.h
Moe Charm (CI) cba6f785a1 Add SuperSlab Prefault Box with 4MB MAP_POPULATE bug fix
New Feature: ss_prefault_box.h
- Box for controlling SuperSlab page prefaulting policy
- ENV: HAKMEM_SS_PREFAULT (0=OFF, 1=POPULATE, 2=TOUCH)
- Default: OFF (safe mode until further optimization)

Bug Fix: 4MB MAP_POPULATE regression
- Problem: Fallback path allocated 4MB (2x size for alignment) with MAP_POPULATE
  causing 52x slower mmap (0.585ms → 30.6ms) and 35% throughput regression
- Solution: Remove MAP_POPULATE from 4MB allocation, apply madvise(MADV_WILLNEED)
  only to the aligned 2MB region after trimming prefix/suffix

Changes:
- core/box/ss_prefault_box.h: New prefault policy box (header-only)
- core/box/ss_allocation_box.c: Integrate prefault box, call ss_prefault_region()
- core/superslab_cache.c: Fix fallback path - no MAP_POPULATE on 4MB,
  always munmap prefix/suffix, use MADV_WILLNEED for 2MB only
- docs/specs/ENV_VARS*.md: Document HAKMEM_SS_PREFAULT

Performance:
- bench_random_mixed: 4.32M ops/s (regression fixed, slight improvement)
- bench_tiny_hot: 157M ops/s with prefault=1 (no crash)

Box Theory:
- OS layer (ss_os_acquire): "how to mmap"
- Prefault Box: "when to page-in"
- Allocation Box: "when to call prefault"

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 20:11:24 +09:00

81 lines
2.9 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.

// ss_prefault_box.h - Box: SuperSlab Page Prefaulting Policy
// Purpose: Control SuperSlab prefault strategy (MAP_POPULATE / manual touch)
// Box Theory:
// - This box owns「いつ / どの程度 pf を前倒しするか」というポリシーだけを担当。
// - 実際の mmap は ss_os_acquire_box下層、Superslab 初期化は ss_allocation_box上層が担当。
//
// Responsibilities:
// - HAKMEM_SS_PREFAULT の値から prefault ポリシーを決定
// - 必要に応じて SuperSlab 全域を 1 回だけ touch して page-in する
//
// ENV:
// HAKMEM_SS_PREFAULT=0 Off 既存動作に近い。g_ss_populate_once のワンショットのみ)
// HAKMEM_SS_PREFAULT=1 POPULATE MAP_POPULATE のみ使用)
// HAKMEM_SS_PREFAULT=2 TOUCH MAP_POPULATE + 手動4KB touch
// HAKMEM_SS_PREFAULT=3 ASYNC (予約値。現状は TOUCH と同等に扱う)
//
// Default:
// - 未指定時は 1 (POPULATE) とし、SuperSlab 取得時の page fault を大きく削減する。
#ifndef HAKMEM_SS_PREFAULT_BOX_H
#define HAKMEM_SS_PREFAULT_BOX_H
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
typedef enum {
SS_PREFAULT_OFF = 0, // No prefault (legacy: g_ss_populate_once のみ)
SS_PREFAULT_POPULATE = 1, // MAP_POPULATE only
SS_PREFAULT_TOUCH = 2, // MAP_POPULATE + manual page touch
SS_PREFAULT_ASYNC = 3 // Reserved for future background prefault
} SSPrefaultPolicy;
// Return current prefault policy (parsed once from HAKMEM_SS_PREFAULT).
static inline SSPrefaultPolicy ss_prefault_policy(void)
{
static int cached = -1;
if (cached != -1) {
return (SSPrefaultPolicy)cached;
}
// 一時的な安全デフォルト: OFF
// 4MB MAP_POPULATE 問題の影響を避けつつ、必要なときだけ明示的に ON にする)
int policy = SS_PREFAULT_OFF;
const char* env = getenv("HAKMEM_SS_PREFAULT");
if (env && *env) {
int v = atoi(env);
if (v < 0) v = 0;
if (v > 3) v = 3;
policy = v;
}
cached = policy;
return (SSPrefaultPolicy)policy;
}
// Prefault a contiguous SuperSlab region by touching one byte per page.
// Caller is expected to call this「mmap直後」に 1 回だけ実行する。
static inline void ss_prefault_region(void* addr, size_t size)
{
SSPrefaultPolicy policy = ss_prefault_policy();
if (policy < SS_PREFAULT_TOUCH) {
// POPULATE または OFF の場合は手動 touch は行わない。
return;
}
if (!addr || size == 0) {
return;
}
long ps = sysconf(_SC_PAGESIZE);
size_t page = (ps > 0) ? (size_t)ps : (size_t)4096;
volatile char* p = (volatile char*)addr;
for (size_t off = 0; off < size; off += page) {
(void)p[off];
}
// Ensure last byte is also touched (covers exact multiples).
(void)p[size - 1];
}
#endif // HAKMEM_SS_PREFAULT_BOX_H