228 lines
7.3 KiB
Markdown
228 lines
7.3 KiB
Markdown
|
|
# Phase 54: Memory-Lean Mode Implementation
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
Phase 54 implements an **opt-in Memory-Lean mode** to reduce peak RSS from ~33MB (FAST baseline) to <10MB while accepting -5% to -10% throughput degradation. This mode is **separate from the speed-first FAST profile** and does not affect Standard/OBSERVE/FAST baselines.
|
||
|
|
|
||
|
|
## Design Philosophy
|
||
|
|
|
||
|
|
- **Opt-in (default OFF)**: Memory-Lean mode is disabled by default to preserve speed-first FAST profile
|
||
|
|
- **ENV-gated A/B testing**: Same binary can toggle between FAST and LEAN modes via environment variables
|
||
|
|
- **Box Theory compliance**: Single conversion point, clear boundaries, reversible changes
|
||
|
|
- **Safety-first**: Respects DSO guard and fail-fast rules (Phase 17 lessons)
|
||
|
|
|
||
|
|
## Implementation
|
||
|
|
|
||
|
|
### Box 1: `ss_mem_lean_env_box.h` (ENV Configuration)
|
||
|
|
|
||
|
|
**Location**: `/mnt/workdisk/public_share/hakmem/core/box/ss_mem_lean_env_box.h`
|
||
|
|
|
||
|
|
**Purpose**: Parse and provide ENV configuration for Memory-Lean mode
|
||
|
|
|
||
|
|
**ENV Variables**:
|
||
|
|
- `HAKMEM_SS_MEM_LEAN=0/1` - Enable Memory-Lean mode [DEFAULT: 0]
|
||
|
|
- `HAKMEM_SS_MEM_LEAN_TARGET_MB=N` - Target peak RSS in MB [DEFAULT: 10]
|
||
|
|
- `HAKMEM_SS_MEM_LEAN_DECOMMIT=FREE|DONTNEED|OFF` - Decommit strategy [DEFAULT: FREE]
|
||
|
|
- `FREE`: Use `MADV_FREE` (lazy kernel reclaim, fast)
|
||
|
|
- `DONTNEED`: Use `MADV_DONTNEED` (eager kernel reclaim, slower)
|
||
|
|
- `OFF`: No decommit (only suppress prewarm)
|
||
|
|
|
||
|
|
**API**:
|
||
|
|
```c
|
||
|
|
int ss_mem_lean_enabled(void); // Check if lean mode enabled
|
||
|
|
int ss_mem_lean_target_mb(void); // Get target RSS in MB
|
||
|
|
ss_mem_lean_decommit_mode_t ss_mem_lean_decommit_mode(void); // Get decommit strategy
|
||
|
|
```
|
||
|
|
|
||
|
|
**Design**:
|
||
|
|
- Header-only with inline functions for zero overhead when disabled
|
||
|
|
- Lazy initialization with double-check pattern
|
||
|
|
- No dependencies (pure ENV parsing)
|
||
|
|
|
||
|
|
### Box 2: `ss_release_policy_box.h/c` (Release Policy)
|
||
|
|
|
||
|
|
**Location**: `/mnt/workdisk/public_share/hakmem/core/box/ss_release_policy_box.{h,c}`
|
||
|
|
|
||
|
|
**Purpose**: Single conversion point for superslab lifecycle decisions
|
||
|
|
|
||
|
|
**API**:
|
||
|
|
```c
|
||
|
|
bool ss_should_keep_superslab(SuperSlab* ss, int class_idx); // Keep or release decision
|
||
|
|
int ss_maybe_decommit_superslab(void* ptr, size_t size); // Decommit memory (reduce RSS)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Design**:
|
||
|
|
- In **FAST mode** (default): Returns `true` (keep all superslabs, persistent backend)
|
||
|
|
- In **LEAN mode** (opt-in): Returns `false` (allow release of empty superslabs)
|
||
|
|
- Decommit logic:
|
||
|
|
- Uses DSO-guarded `madvise()` (respects Phase 17 safety rules)
|
||
|
|
- Selects `MADV_FREE` or `MADV_DONTNEED` based on ENV
|
||
|
|
- Updates `lean_decommit` counter on success
|
||
|
|
- Falls back to `munmap` on failure
|
||
|
|
|
||
|
|
**Boundary**: All decommit operations flow through `ss_os_madvise_guarded()` (Superslab OS Box)
|
||
|
|
|
||
|
|
### Patch 1: Prewarm Suppression
|
||
|
|
|
||
|
|
**File**: `/mnt/workdisk/public_share/hakmem/core/box/ss_hot_prewarm_box.c`
|
||
|
|
|
||
|
|
**Change**: Added lean mode check in `box_ss_hot_prewarm_all()`
|
||
|
|
|
||
|
|
```c
|
||
|
|
int box_ss_hot_prewarm_all(void) {
|
||
|
|
// Phase 54: Memory-Lean mode suppresses prewarm (reduce RSS)
|
||
|
|
if (ss_mem_lean_enabled()) {
|
||
|
|
return 0; // No prewarm in lean mode
|
||
|
|
}
|
||
|
|
// ... existing prewarm logic ...
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Impact**: Prevents initial allocation of persistent superslabs (C0-C7 prewarm targets)
|
||
|
|
|
||
|
|
### Patch 2: Decommit Logic
|
||
|
|
|
||
|
|
**File**: `/mnt/workdisk/public_share/hakmem/core/box/ss_allocation_box.c`
|
||
|
|
|
||
|
|
**Change**: Added decommit path in `superslab_free()` before `munmap`
|
||
|
|
|
||
|
|
```c
|
||
|
|
void superslab_free(SuperSlab* ss) {
|
||
|
|
// ... existing cache logic ...
|
||
|
|
|
||
|
|
// Both caches full - try decommit before munmap
|
||
|
|
if (ss_mem_lean_enabled()) {
|
||
|
|
int decommit_ret = ss_maybe_decommit_superslab((void*)ss, ss_size);
|
||
|
|
if (decommit_ret == 0) {
|
||
|
|
// Decommit succeeded - record lean_retire and skip munmap
|
||
|
|
// SuperSlab VMA is kept but pages are released to kernel
|
||
|
|
ss_os_stats_record_lean_retire();
|
||
|
|
ss->magic = 0; // Clear magic to prevent use-after-free
|
||
|
|
// Update statistics...
|
||
|
|
return; // Skip munmap, pages are decommitted
|
||
|
|
}
|
||
|
|
// Decommit failed (DSO overlap, madvise error) - fall through to munmap
|
||
|
|
}
|
||
|
|
|
||
|
|
// ... existing munmap logic ...
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Impact**: Empty superslabs are decommitted (RSS reduced) instead of munmap'd (VMA kept)
|
||
|
|
|
||
|
|
### Patch 3: Stats Counters
|
||
|
|
|
||
|
|
**Files**:
|
||
|
|
- `/mnt/workdisk/public_share/hakmem/core/box/ss_os_acquire_box.h`
|
||
|
|
- `/mnt/workdisk/public_share/hakmem/core/superslab_stats.c`
|
||
|
|
|
||
|
|
**Change**: Added `lean_decommit` and `lean_retire` counters
|
||
|
|
|
||
|
|
```c
|
||
|
|
extern _Atomic uint64_t g_ss_lean_decommit_calls; // Decommit operations
|
||
|
|
extern _Atomic uint64_t g_ss_lean_retire_calls; // Superslabs retired (decommit instead of munmap)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Reporting**: Counters reported in `SS_OS_STATS` destructor output
|
||
|
|
|
||
|
|
### Makefile Integration
|
||
|
|
|
||
|
|
**File**: `/mnt/workdisk/public_share/hakmem/Makefile`
|
||
|
|
|
||
|
|
**Change**: Added `core/box/ss_release_policy_box.o` to all build targets
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
### Enable Memory-Lean Mode
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Default decommit strategy (MADV_FREE, fast)
|
||
|
|
export HAKMEM_SS_MEM_LEAN=1
|
||
|
|
./bench_random_mixed_hakmem
|
||
|
|
|
||
|
|
# Eager decommit (MADV_DONTNEED, slower but universal)
|
||
|
|
export HAKMEM_SS_MEM_LEAN=1
|
||
|
|
export HAKMEM_SS_MEM_LEAN_DECOMMIT=DONTNEED
|
||
|
|
./bench_random_mixed_hakmem
|
||
|
|
|
||
|
|
# Suppress prewarm only (no decommit)
|
||
|
|
export HAKMEM_SS_MEM_LEAN=1
|
||
|
|
export HAKMEM_SS_MEM_LEAN_DECOMMIT=OFF
|
||
|
|
./bench_random_mixed_hakmem
|
||
|
|
|
||
|
|
# Monitor stats
|
||
|
|
export HAKMEM_SS_OS_STATS=1
|
||
|
|
export HAKMEM_SS_MEM_LEAN=1
|
||
|
|
./bench_random_mixed_hakmem
|
||
|
|
```
|
||
|
|
|
||
|
|
### Disable Memory-Lean Mode (FAST baseline)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Explicit disable
|
||
|
|
export HAKMEM_SS_MEM_LEAN=0
|
||
|
|
./bench_random_mixed_hakmem
|
||
|
|
|
||
|
|
# Or unset (default is OFF)
|
||
|
|
unset HAKMEM_SS_MEM_LEAN
|
||
|
|
./bench_random_mixed_hakmem
|
||
|
|
```
|
||
|
|
|
||
|
|
## Safety Guarantees
|
||
|
|
|
||
|
|
### DSO Guard (Phase 17 Lesson)
|
||
|
|
|
||
|
|
- All `madvise()` calls flow through `ss_os_madvise_guarded()`
|
||
|
|
- DSO addresses are skipped (prevents .fini_array corruption)
|
||
|
|
- Fail-fast on `ENOMEM` (disables future madvise calls)
|
||
|
|
|
||
|
|
### Fail-Fast Rules
|
||
|
|
|
||
|
|
- Decommit failure → fall back to `munmap` (no silent errors)
|
||
|
|
- DSO overlap → skip decommit, use `munmap`
|
||
|
|
- `ENOMEM` → disable madvise globally, use `munmap`
|
||
|
|
|
||
|
|
### Magic Number Protection
|
||
|
|
|
||
|
|
- SuperSlab magic is cleared after decommit/munmap
|
||
|
|
- Prevents use-after-free (same as FAST mode)
|
||
|
|
|
||
|
|
## Trade-offs
|
||
|
|
|
||
|
|
| Metric | FAST (baseline) | LEAN (target) | Change |
|
||
|
|
|--------|----------------|---------------|--------|
|
||
|
|
| Peak RSS | ~33 MB | <10 MB | **-70%** |
|
||
|
|
| Throughput | 60M ops/s | 54-57M ops/s | **-5% to -10%** |
|
||
|
|
| Syscalls | 9e-8/op | Higher (acceptable) | **+X%** |
|
||
|
|
| Drift | 0% | 0% (required) | **No change** |
|
||
|
|
|
||
|
|
## Dependencies
|
||
|
|
|
||
|
|
- `ss_mem_lean_env_box.h` (ENV configuration)
|
||
|
|
- `ss_release_policy_box.h/c` (release policy logic)
|
||
|
|
- `madvise_guard_box.h` (DSO-safe madvise wrapper)
|
||
|
|
- `ss_os_acquire_box.h` (stats counters)
|
||
|
|
|
||
|
|
## Testing
|
||
|
|
|
||
|
|
- **A/B test**: Same binary, ENV toggle (`HAKMEM_SS_MEM_LEAN=0` vs `HAKMEM_SS_MEM_LEAN=1`)
|
||
|
|
- **Baseline**: Phase 48 rebase (FAST mode, lean disabled)
|
||
|
|
- **Treatment**: Memory-Lean mode (lean enabled)
|
||
|
|
- **Metrics**: RSS/throughput/syscalls/drift (5-30 min soak tests)
|
||
|
|
|
||
|
|
## Box Theory Compliance
|
||
|
|
|
||
|
|
- ✅ **Single conversion point**: All decommit operations flow through `ss_maybe_decommit_superslab()`
|
||
|
|
- ✅ **Clear boundaries**: ENV gate, release policy box, OS box (3 layers)
|
||
|
|
- ✅ **Reversible**: ENV toggle (A/B testing)
|
||
|
|
- ✅ **Minimal visualization**: Stats counters only (no new debug logs)
|
||
|
|
- ✅ **Safety-first**: DSO guard, fail-fast rules, magic number protection
|
||
|
|
|
||
|
|
## License
|
||
|
|
|
||
|
|
MIT
|
||
|
|
|
||
|
|
## Date
|
||
|
|
|
||
|
|
2025-12-17
|