321 lines
9.8 KiB
Markdown
321 lines
9.8 KiB
Markdown
|
|
# Phase 69-0: Refill Frequency × Fixed Tax Reduction — Design Memo
|
|||
|
|
|
|||
|
|
**Status**: 🟡 DESIGN (Phase 69-0)
|
|||
|
|
|
|||
|
|
**Objective**: Reduce "refill count × fixed overhead" by tuning batch sizes and cache capacities to minimize refill frequency. Target: **+3〜6%** (shortest path to M2: 55%).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Executive Summary
|
|||
|
|
|
|||
|
|
**Current Performance**: 61.614M ops/s = 50.93% of mimalloc (Phase 68 PGO baseline)
|
|||
|
|
|
|||
|
|
**M2 Target**: 66.54M ops/s = 55% of mimalloc (Gap: **+4.9M ops/s = +7.96%**)
|
|||
|
|
|
|||
|
|
**Strategy**: Reduce refill frequency by tuning batch sizes and cache capacities. Every refill incurs fixed overhead (SuperSlab lookup, metadata access, chain splicing). Reducing refill count directly improves throughput without micro-optimization risks.
|
|||
|
|
|
|||
|
|
**Why This Approach**:
|
|||
|
|
- ✅ **High reproducibility**: Unlike branch/inline tuning, batch tuning has low layout tax risk
|
|||
|
|
- ✅ **Box-compliant**: No structural changes, only parameter tuning
|
|||
|
|
- ✅ **Measurable**: refill count is directly observable via counters
|
|||
|
|
- ✅ **Reversible**: All changes are config-only (ENV variables or compile-time constants)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Current State Analysis
|
|||
|
|
|
|||
|
|
### 1.1 Refill Path Hierarchy
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
malloc() → Unified Cache (C2/C3: 2048 slots, C5-C7: 128 slots)
|
|||
|
|
↓ MISS
|
|||
|
|
unified_cache_refill()
|
|||
|
|
↓
|
|||
|
|
Warm Pool (12 SuperSlabs per class)
|
|||
|
|
↓ MISS
|
|||
|
|
sll_refill_batch_from_ss(class_idx, max_take=16)
|
|||
|
|
↓
|
|||
|
|
trc_pop_from_freelist() OR trc_linear_carve()
|
|||
|
|
↓
|
|||
|
|
trc_splice_to_sll()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 1.2 Key Parameters (Current)
|
|||
|
|
|
|||
|
|
| Component | Parameter | Current Value | Location |
|
|||
|
|
|-----------|-----------|---------------|----------|
|
|||
|
|
| **Refill Batch Size** | `TINY_REFILL_BATCH_SIZE` | 16 | `core/hakmem_tiny_config.h:87` |
|
|||
|
|
| **Unified Cache C2/C3** | `unified_capacity(2/3)` | 2048 slots | `core/front/tiny_unified_cache.h:129` |
|
|||
|
|
| **Unified Cache C5-C7** | `unified_capacity(5-7)` | 128 slots | `core/front/tiny_unified_cache.h:131` |
|
|||
|
|
| **Unified Cache Others** | `unified_capacity(0/1/4)` | 64 slots | `core/front/tiny_unified_cache.h:128` |
|
|||
|
|
| **Warm Pool Size** | `TINY_WARM_POOL_MAX_PER_CLASS` | 12 | `core/front/tiny_warm_pool.h:46` |
|
|||
|
|
| **Drain Batch Size** | `TINY_DRAIN_BATCH_SIZE` | 16 | `core/hakmem_tiny_config.h:90` |
|
|||
|
|
|
|||
|
|
### 1.3 Refill Overhead Breakdown
|
|||
|
|
|
|||
|
|
**Fixed Overhead per refill** (~50-100 cycles):
|
|||
|
|
- SuperSlab lookup (warm pool pop or registry scan)
|
|||
|
|
- SlabMeta load (freelist, used, carved, capacity)
|
|||
|
|
- Chain building (header writes, next pointer linking)
|
|||
|
|
- TLS SLL splice (update head/count atomically)
|
|||
|
|
|
|||
|
|
**Cost Formula**:
|
|||
|
|
```
|
|||
|
|
Total Refill Cost = (refill_count × fixed_overhead) + (blocks_carved × per_block_cost)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Optimization Strategy**:
|
|||
|
|
- ↑ Batch size → ↓ refill_count → ↓ Total Cost (up to cache capacity limit)
|
|||
|
|
- ↑ Cache capacity → ↓ miss rate → ↓ refill_count
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Tunable Parameters (Phase 69 Sweep Plan)
|
|||
|
|
|
|||
|
|
### 2.1 Refill Batch Size Sweep
|
|||
|
|
|
|||
|
|
**Parameter**: `TINY_REFILL_BATCH_SIZE` (global default for all classes)
|
|||
|
|
|
|||
|
|
**Current**: 16 (conservative, optimized for RSS)
|
|||
|
|
|
|||
|
|
**Sweep Range**: [16, 32, 64, 128]
|
|||
|
|
|
|||
|
|
**Rationale**:
|
|||
|
|
- 16 → 32: Expected +1-2% (fewer refill calls)
|
|||
|
|
- 32 → 64: Expected +1-2% (diminishing returns, cache pressure increases)
|
|||
|
|
- 64 → 128: Expected +0-1% (likely NO-GO due to cache thrashing)
|
|||
|
|
|
|||
|
|
**A/B Test Method**:
|
|||
|
|
```bash
|
|||
|
|
# Baseline (16)
|
|||
|
|
make clean && make bench_random_mixed_hakmem_minimal_pgo
|
|||
|
|
ITERS=20000000 WS=400 RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
|
|||
|
|
# Treatment (32)
|
|||
|
|
sed -i 's/TINY_REFILL_BATCH_SIZE 16/TINY_REFILL_BATCH_SIZE 32/' core/hakmem_tiny_config.h
|
|||
|
|
make clean && make pgo-fast-full
|
|||
|
|
ITERS=20000000 WS=400 RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
|
|||
|
|
# Compare results
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Expected Winner**: 32 (balance between refill frequency and cache locality)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2.2 Unified Cache Capacity Sweep (C5-C7 Focus)
|
|||
|
|
|
|||
|
|
**Parameter**: `unified_capacity(class_idx)` for C5-C7 (129B-1024B, Mixed workload)
|
|||
|
|
|
|||
|
|
**Current**: 128 slots (C5-C7)
|
|||
|
|
|
|||
|
|
**Rationale**: C5-C7 handle 129B-1024B range (mid-size allocations in Mixed benchmark). Increasing capacity reduces miss rate.
|
|||
|
|
|
|||
|
|
**Sweep Range**: [128, 256, 512]
|
|||
|
|
|
|||
|
|
**ENV Control**:
|
|||
|
|
```bash
|
|||
|
|
# Baseline (128)
|
|||
|
|
HAKMEM_TINY_UNIFIED_C5=128 HAKMEM_TINY_UNIFIED_C6=128 HAKMEM_TINY_UNIFIED_C7=128
|
|||
|
|
|
|||
|
|
# Treatment 1 (256)
|
|||
|
|
HAKMEM_TINY_UNIFIED_C5=256 HAKMEM_TINY_UNIFIED_C6=256 HAKMEM_TINY_UNIFIED_C7=256
|
|||
|
|
|
|||
|
|
# Treatment 2 (512)
|
|||
|
|
HAKMEM_TINY_UNIFIED_C5=512 HAKMEM_TINY_UNIFIED_C6=512 HAKMEM_TINY_UNIFIED_C7=512
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Expected Winner**: 256 (balance between working set and RSS)
|
|||
|
|
|
|||
|
|
**Why Not C2/C3**:
|
|||
|
|
- C2/C3 already have 2048 slots (very high capacity)
|
|||
|
|
- Further increase unlikely to improve (already low miss rate)
|
|||
|
|
- Focus on under-optimized classes (C5-C7)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2.3 Warm Pool Size Sweep
|
|||
|
|
|
|||
|
|
**Parameter**: `TINY_WARM_POOL_MAX_PER_CLASS`
|
|||
|
|
|
|||
|
|
**Current**: 12 SuperSlabs per class
|
|||
|
|
|
|||
|
|
**Rationale**: Warm pool caches hot SuperSlabs to avoid registry scan. Larger pool → lower registry scan frequency.
|
|||
|
|
|
|||
|
|
**Sweep Range**: [12, 16, 24]
|
|||
|
|
|
|||
|
|
**ENV Control**:
|
|||
|
|
```bash
|
|||
|
|
HAKMEM_WARM_POOL_SIZE=16 # Treatment 1
|
|||
|
|
HAKMEM_WARM_POOL_SIZE=24 # Treatment 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Expected Winner**: 16 (diminishing returns beyond this)
|
|||
|
|
|
|||
|
|
**Caveat**: Memory overhead = pool_size × sizeof(SuperSlab*) × TINY_NUM_CLASSES = 16 × 8 × 8 = 1KB per thread (negligible)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Implementation Strategy
|
|||
|
|
|
|||
|
|
### 3.1 Phase 69-1: Single-Parameter Sweeps (Isolation)
|
|||
|
|
|
|||
|
|
**Goal**: Measure each parameter's individual impact to avoid confounding effects.
|
|||
|
|
|
|||
|
|
**Order** (easiest to hardest):
|
|||
|
|
|
|||
|
|
1. **Warm Pool Size** (ENV-only, no recompile):
|
|||
|
|
```bash
|
|||
|
|
for SIZE in 12 16 24; do
|
|||
|
|
HAKMEM_WARM_POOL_SIZE=$SIZE RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
done
|
|||
|
|
```
|
|||
|
|
- Expected: +0.5-1.0% (registry scan reduction)
|
|||
|
|
- Risk: Low (ENV-only change)
|
|||
|
|
|
|||
|
|
2. **Unified Cache C5-C7** (ENV-only, no recompile):
|
|||
|
|
```bash
|
|||
|
|
for CAP in 128 256 512; do
|
|||
|
|
HAKMEM_TINY_UNIFIED_C5=$CAP HAKMEM_TINY_UNIFIED_C6=$CAP HAKMEM_TINY_UNIFIED_C7=$CAP \
|
|||
|
|
RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
done
|
|||
|
|
```
|
|||
|
|
- Expected: +1-2% (miss rate reduction for mid-size allocations)
|
|||
|
|
- Risk: Low (ENV-only change)
|
|||
|
|
|
|||
|
|
3. **Refill Batch Size** (requires recompile + PGO):
|
|||
|
|
```bash
|
|||
|
|
for BATCH in 16 32 64; do
|
|||
|
|
sed -i "s/TINY_REFILL_BATCH_SIZE .*/TINY_REFILL_BATCH_SIZE $BATCH/" core/hakmem_tiny_config.h
|
|||
|
|
make pgo-fast-full
|
|||
|
|
RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
done
|
|||
|
|
```
|
|||
|
|
- Expected: +1-3% (refill frequency reduction)
|
|||
|
|
- Risk: Medium (requires PGO rebuild, potential layout tax)
|
|||
|
|
|
|||
|
|
### 3.2 Phase 69-2: Combined Optimization (Best Settings)
|
|||
|
|
|
|||
|
|
After identifying winners from Phase 69-1, combine them:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Example: batch=32, C5-C7=256, warm_pool=16
|
|||
|
|
HAKMEM_WARM_POOL_SIZE=16 \
|
|||
|
|
HAKMEM_TINY_UNIFIED_C5=256 HAKMEM_TINY_UNIFIED_C6=256 HAKMEM_TINY_UNIFIED_C7=256 \
|
|||
|
|
make pgo-fast-full # with TINY_REFILL_BATCH_SIZE=32
|
|||
|
|
|
|||
|
|
RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Expected Combined Gain**: +3-6% (additive if parameters are orthogonal)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Measurement & Validation
|
|||
|
|
|
|||
|
|
### 4.1 Primary Metric: Throughput
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
RUNS=10 scripts/run_mixed_10_cleanenv.sh
|
|||
|
|
# Extract: Mean, Median, CV
|
|||
|
|
# Decision: GO (+1%), Strong GO (+3%)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 Secondary Metrics (Observability)
|
|||
|
|
|
|||
|
|
**Unified Cache Hit Rate**:
|
|||
|
|
```bash
|
|||
|
|
HAKMEM_MEASURE_UNIFIED_CACHE=1 ./bench_random_mixed_hakmem_minimal_pgo
|
|||
|
|
# Output: g_unified_cache_hits_global / (hits + misses)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Refill Count** (requires instrumentation):
|
|||
|
|
```c
|
|||
|
|
// Add to unified_cache_refill():
|
|||
|
|
static _Atomic uint64_t g_refill_count_total = 0;
|
|||
|
|
atomic_fetch_add(&g_refill_count_total, 1, memory_order_relaxed);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Warm Pool Hit Rate**:
|
|||
|
|
```bash
|
|||
|
|
# Already exists in g_warm_pool_stats[class_idx].hits / misses
|
|||
|
|
# Print at shutdown via tiny_warm_pool_print_stats()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 Layout Tax Check (If NO-GO)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Run forensics on regression
|
|||
|
|
./scripts/box/layout_tax_forensics_box.sh \
|
|||
|
|
./bench_random_mixed_hakmem_minimal_pgo \
|
|||
|
|
./bench_random_mixed_hakmem_minimal_pgo_phase69
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Risk Assessment
|
|||
|
|
|
|||
|
|
| Risk | Mitigation |
|
|||
|
|
|------|------------|
|
|||
|
|
| **Layout Tax** (batch size change) | Use `layout_tax_forensics_box.sh` to diagnose. Revert if IPC drops >3%. |
|
|||
|
|
| **Cache Thrashing** (capacity too high) | Monitor LLC-misses via perf stat. Limit C5-C7 capacity to 512 max. |
|
|||
|
|
| **RSS Increase** (larger batches/caches) | Measure RSS before/after. Acceptable if <+5% for +3% throughput. |
|
|||
|
|
| **PGO Mismatch** (batch change) | Re-run PGO training after batch size change (included in `pgo-fast-full`). |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Decision Criteria
|
|||
|
|
|
|||
|
|
### GO Thresholds
|
|||
|
|
|
|||
|
|
- **GO**: +1.0% (additive improvement, worth merging)
|
|||
|
|
- **Strong GO**: +3.0% (M2-worthy, promote to baseline)
|
|||
|
|
- **NEUTRAL**: ±1.0% (no regression, but no clear win)
|
|||
|
|
- **NO-GO**: <-1.0% (regression, investigate layout tax)
|
|||
|
|
|
|||
|
|
### Promotion Strategy
|
|||
|
|
|
|||
|
|
- **Single-parameter GO**: Merge immediately if +1%+
|
|||
|
|
- **Combined GO**: Require +3%+ to justify complexity
|
|||
|
|
- **Strong GO**: Update PGO baseline + PERFORMANCE_TARGETS_SCORECARD
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Next Steps
|
|||
|
|
|
|||
|
|
### Immediate (Phase 69-1)
|
|||
|
|
|
|||
|
|
1. **ENV Sweeps** (no recompile):
|
|||
|
|
- Warm pool size: 12 → 16 → 24
|
|||
|
|
- Unified cache C5-C7: 128 → 256 → 512
|
|||
|
|
|
|||
|
|
2. **Batch Size Sweep** (requires PGO rebuild):
|
|||
|
|
- TINY_REFILL_BATCH_SIZE: 16 → 32 → 64
|
|||
|
|
|
|||
|
|
### Follow-Up (Phase 69-2)
|
|||
|
|
|
|||
|
|
3. **Combined Optimization**:
|
|||
|
|
- Apply winning parameters from Phase 69-1
|
|||
|
|
- Verify additive gains (+3-6% target)
|
|||
|
|
|
|||
|
|
4. **Baseline Promotion** (if Strong GO):
|
|||
|
|
- Update `pgo_fast_profile_config.sh` with winning ENV vars
|
|||
|
|
- Update `core/hakmem_tiny_config.h` with winning batch size
|
|||
|
|
- Re-run `make pgo-fast-full` to bake optimizations into baseline
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Artifacts
|
|||
|
|
|
|||
|
|
- **This design memo**: `docs/analysis/PHASE69_REFILL_TUNING_0_DESIGN.md`
|
|||
|
|
- **Sweep script** (TODO): `scripts/box/phase69_refill_sweep.sh`
|
|||
|
|
- **Results log** (TODO): `docs/analysis/PHASE69_REFILL_TUNING_1_RESULTS.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**Status**: 🟢 READY FOR SWEEP (Phase 69-1)
|
|||
|
|
|
|||
|
|
**Estimated Time**: 2-3 hours (ENV sweeps) + 4-6 hours (batch sweep with PGO)
|
|||
|
|
|
|||
|
|
**Expected Outcome**: +3-6% combined gain → M2 射程 (55% target)
|