188 lines
5.2 KiB
Markdown
188 lines
5.2 KiB
Markdown
|
|
# Phase 2b: Adaptive TLS Cache Sizing - Quick Start
|
||
|
|
|
||
|
|
**Status**: ✅ **IMPLEMENTED** (2025-11-08)
|
||
|
|
**Expected Impact**: +3-10% performance, -30-50% memory
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## What Was Implemented
|
||
|
|
|
||
|
|
**Adaptive TLS cache sizing** that automatically grows/shrinks per-class cache based on usage:
|
||
|
|
- **Hot classes** (high usage) → grow to 2048 slots
|
||
|
|
- **Cold classes** (low usage) → shrink to 16 slots
|
||
|
|
- **Initial capacity**: 64 slots (down from 256)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Files Created
|
||
|
|
|
||
|
|
1. **`core/tiny_adaptive_sizing.h`** - Header with API and inline helpers
|
||
|
|
2. **`core/tiny_adaptive_sizing.c`** - Implementation of grow/shrink/adapt logic
|
||
|
|
|
||
|
|
## Files Modified
|
||
|
|
|
||
|
|
1. **`core/tiny_alloc_fast.inc.h`** - Capacity check, refill clamping, tracking
|
||
|
|
2. **`core/hakmem_tiny_init.inc`** - Init call
|
||
|
|
3. **`core/hakmem_tiny.c`** - Header include
|
||
|
|
4. **`Makefile`** - Add `tiny_adaptive_sizing.o` to all build targets
|
||
|
|
|
||
|
|
**Total**: 319 new lines + 19 modified lines = **338 lines**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## How To Use
|
||
|
|
|
||
|
|
### Build
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Full rebuild (recommended after pulling changes)
|
||
|
|
make clean && make larson_hakmem
|
||
|
|
|
||
|
|
# Or just rebuild adaptive sizing module
|
||
|
|
make tiny_adaptive_sizing.o
|
||
|
|
```
|
||
|
|
|
||
|
|
### Run
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Default: Adaptive sizing enabled with logging
|
||
|
|
./larson_hakmem 10 8 128 1024 1 12345 4
|
||
|
|
|
||
|
|
# Disable adaptive sizing (use fixed 64 slots)
|
||
|
|
HAKMEM_ADAPTIVE_SIZING=0 ./larson_hakmem 10 8 128 1024 1 12345 4
|
||
|
|
|
||
|
|
# Enable adaptive sizing but suppress logs
|
||
|
|
HAKMEM_ADAPTIVE_LOG=0 ./larson_hakmem 10 8 128 1024 1 12345 4
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Expected Logs
|
||
|
|
|
||
|
|
```
|
||
|
|
[ADAPTIVE] Adaptive sizing initialized (initial_cap=64, min=16, max=2048)
|
||
|
|
[TLS_CACHE] Grow class 4: 64 → 128 slots (grow_count=1)
|
||
|
|
[TLS_CACHE] Grow class 4: 128 → 256 slots (grow_count=2)
|
||
|
|
[TLS_CACHE] Grow class 4: 256 → 512 slots (grow_count=3)
|
||
|
|
[TLS_CACHE] Keep class 1 at 64 slots (usage=45.2%)
|
||
|
|
[TLS_CACHE] Shrink class 0: 64 → 32 slots (shrink_count=1)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Interpretation**:
|
||
|
|
- **Class 4 grows**: High allocation rate → needs more cache
|
||
|
|
- **Class 1 stable**: Moderate usage → keep current size
|
||
|
|
- **Class 0 shrinks**: Low usage → reclaim memory
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## How It Works
|
||
|
|
|
||
|
|
### 1. Initialization
|
||
|
|
- All classes start at 64 slots (reduced from 256)
|
||
|
|
- Stats reset: `high_water_mark=0`, `refill_count=0`
|
||
|
|
|
||
|
|
### 2. Tracking (on every refill)
|
||
|
|
- Update `high_water_mark` if current count > previous peak
|
||
|
|
- Increment `refill_count`
|
||
|
|
|
||
|
|
### 3. Adaptation (every 10 refills or 1 second)
|
||
|
|
- Calculate usage ratio: `high_water_mark / capacity`
|
||
|
|
- **If usage > 80%**: Grow (capacity *= 2, max 2048)
|
||
|
|
- **If usage < 20%**: Shrink (capacity /= 2, min 16)
|
||
|
|
- **Else**: Keep current size (log usage %)
|
||
|
|
|
||
|
|
### 4. Enforcement
|
||
|
|
- Before refill: Check `available_capacity = capacity - current_count`
|
||
|
|
- If full: Skip refill (return 0)
|
||
|
|
- Else: Clamp `refill_count = min(wanted, available)`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Environment Variables
|
||
|
|
|
||
|
|
| Variable | Default | Description |
|
||
|
|
|----------|---------|-------------|
|
||
|
|
| `HAKMEM_ADAPTIVE_SIZING` | 1 | Enable/disable adaptive sizing (1=on, 0=off) |
|
||
|
|
| `HAKMEM_ADAPTIVE_LOG` | 1 | Enable/disable adaptation logs (1=on, 0=off) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Testing Checklist
|
||
|
|
|
||
|
|
- [x] Code compiles successfully (`tiny_adaptive_sizing.o`)
|
||
|
|
- [x] Integration compiles (`hakmem_tiny.o`)
|
||
|
|
- [ ] Full build works (`larson_hakmem`) - **Blocked by L25 pool error (unrelated)**
|
||
|
|
- [ ] Logs show adaptive behavior (grow/shrink based on usage)
|
||
|
|
- [ ] Hot class (e.g., 4) grows to 512+ slots
|
||
|
|
- [ ] Cold class (e.g., 0) shrinks to 16-32 slots
|
||
|
|
- [ ] Performance improvement measured (+3-10% expected)
|
||
|
|
- [ ] Memory reduction measured (-30-50% expected)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Known Issues
|
||
|
|
|
||
|
|
### ⚠️ L25 Pool Build Error (Unrelated)
|
||
|
|
|
||
|
|
**Error**: `hakmem_l25_pool.c:1097:36: error: 'struct <anonymous>' has no member named 'freelist'`
|
||
|
|
**Impact**: Blocks full `larson_hakmem` build
|
||
|
|
**Cause**: L25 pool struct mismatch (NOT caused by Phase 2b)
|
||
|
|
**Workaround**: Fix L25 pool separately OR use simpler benchmarks
|
||
|
|
|
||
|
|
### Alternatives for Testing
|
||
|
|
|
||
|
|
1. **Build only adaptive sizing module**:
|
||
|
|
```bash
|
||
|
|
make tiny_adaptive_sizing.o hakmem_tiny.o
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Use simpler benchmarks** (if available):
|
||
|
|
```bash
|
||
|
|
make bench_tiny
|
||
|
|
./bench_tiny
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Create minimal test** (100-line standalone):
|
||
|
|
```c
|
||
|
|
#include "core/tiny_adaptive_sizing.h"
|
||
|
|
// ... simple alloc/free loop to trigger adaptation
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Next Steps
|
||
|
|
|
||
|
|
1. **Fix L25 pool error** (separate task)
|
||
|
|
2. **Run Larson benchmark** to verify behavior
|
||
|
|
3. **Measure performance** (+3-10% expected)
|
||
|
|
4. **Measure memory** (-30-50% expected)
|
||
|
|
5. **Implement Phase 2b.1**: SuperSlab integration for block return
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Quick Reference
|
||
|
|
|
||
|
|
### Key Functions
|
||
|
|
|
||
|
|
- `adaptive_sizing_init()` - Initialize all classes to 64 slots
|
||
|
|
- `grow_tls_cache(class_idx)` - Double capacity (max 2048)
|
||
|
|
- `shrink_tls_cache(class_idx)` - Halve capacity (min 16)
|
||
|
|
- `adapt_tls_cache_size(class_idx)` - Decide grow/shrink/keep
|
||
|
|
- `update_high_water_mark(class_idx)` - Track peak usage
|
||
|
|
- `track_refill_for_adaptation(class_idx)` - Called after every refill
|
||
|
|
|
||
|
|
### Key Constants
|
||
|
|
|
||
|
|
- `TLS_CACHE_INITIAL_CAPACITY = 64` (was 256)
|
||
|
|
- `TLS_CACHE_MIN_CAPACITY = 16`
|
||
|
|
- `TLS_CACHE_MAX_CAPACITY = 2048`
|
||
|
|
- `GROW_THRESHOLD = 0.8` (80%)
|
||
|
|
- `SHRINK_THRESHOLD = 0.2` (20%)
|
||
|
|
- `ADAPT_REFILL_THRESHOLD = 10` refills
|
||
|
|
- `ADAPT_TIME_THRESHOLD_NS = 1s`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Full Report**: See `/mnt/workdisk/public_share/hakmem/PHASE2B_IMPLEMENTATION_REPORT.md`
|
||
|
|
**Spec**: See `/mnt/workdisk/public_share/hakmem/PHASE2B_TLS_ADAPTIVE_SIZING.md`
|