- Implemented TLS fastlist logic for C6 in smallobject_hotbox_v4.c (alloc/free).
- Added SmallC6FastState struct and g_small_c6_fast TLS variable.
- Gated the fastlist logic with HAKMEM_SMALL_HEAP_V4_FASTLIST (default OFF) due to observed instability in mixed workloads.
- Fixed a memory leak in small_heap_free_fast_v4 fallback path by calling hak_pool_free.
- Updated CURRENT_TASK.md with phase report.
Implementation:
- SmallObject HotBox v4 (core/smallobject_hotbox_v4.c) now fully implements C6-only allocations and frees, including current/partial management and freelist operations.
- Cold Iface (tiny_heap based) for page refill/retire is integrated.
- Stats instrumentation (v4-mid-5) added to small_heap_alloc_fast_v4 and small_heap_free_fast_v4, with a new header file core/box/smallobject_hotbox_v4_stats_box.h and atexit dump function.
Updates:
- CURRENT_TASK.md has been condensed and updated with summaries of Phase v4-mid-2 (C6-only v4), Phase v4-mid-3 (C5-only v4 pilot), and the stats implementation (v4-mid-5).
- docs/analysis/SMALLOBJECT_V4_BOX_DESIGN.md updated with A/B results and conclusions for C6-only and C5-only v4 implementations.
- The previous CURRENT_TASK.md content has been archived to CURRENT_TASK_ARCHIVE_20251210.md.
- Update environment profile presets and visibility analysis
- Enhance small object and tiny segment v4 box implementations
- Refine C7 ultra and C6 heavy allocation strategies
- Add comprehensive performance metrics and design documentation
🤖 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Redefine TinyHotHeap v2 as per-thread Hot Box with clear boundaries
- Add comprehensive OS statistics tracking for SS allocations
- Implement route-based free handling for TinyHeap v2
- Add C6/C7 debugging and statistics improvements
- Update documentation with implementation guidelines and analysis
- Add new box headers for stats, routing, and front-end management
- Added experimental path in unified_cache_refill to test ss_tls_bind_one for C7 class.
- Guarded by HAKMEM_WARM_TLS_BIND_C7 env var and debug build.
- Updated Page Box comments to clarify future TLS Bind Box integration.
- Created core/box/ss_tls_bind_box.h containing ss_tls_bind_one().
- Refactored superslab_refill() to use the new box.
- Updated signatures to avoid circular dependencies (tiny_self_u32).
- Added future integration points for Warm Pool and Page Box.
- Implement tiny_page_box.c/h: per-thread page cache between UC and Shared Pool
- Integrate Page Box into Unified Cache refill path
- Remove legacy SuperSlab implementation (merged into smallmid)
- Add HAKMEM_TINY_PAGE_BOX_CLASSES env var for selective class enabling
- Update bench_random_mixed.c with Page Box statistics
Current status: Implementation safe, no regressions.
Page Box ON/OFF shows minimal difference - pool strategy needs tuning.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Key findings from 2025-12-05 session:
1. HAKMEM vs mimalloc: 27x slower (4.5M vs 122M ops/s)
2. Root cause investigation: madvise 1081 calls vs mimalloc 0 calls
3. madvise disable test: -15% performance (worse, not better!)
4. Conclusion: MADV_POPULATE_WRITE is actually helping, not hurting
5. ChatGPT was right: time to move to user-space optimization phase
Reports added:
- WORKLOAD_COMPARISON_20251205.md
- PARTIAL_RELEASE_INVESTIGATION_REPORT_20251205.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Key Changes:
- Reduced static capacity from 16 to 12 SuperSlabs per class
- Fixed prefill threshold from hardcoded 4 to match capacity (12)
- Updated environment variable clamping to [1,12]
- This allows warm pool to actually utilize its full capacity
Performance:
- Baseline (post-unified-cache-opt): 4.76M ops/s
- After Phase 1: 4.84M ops/s
- Improvement: +1.6% (expected +15-20%)
Note: Actual improvement lower than expected because the warm pool
bottleneck is only part of the overall allocation path. Unified cache
optimization (+14.9%) already addressed much of the registry scan overhead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add support for MADV_POPULATE_WRITE (Linux 5.14+) to force page population
AFTER munmap trimming in SuperSlab fallback path.
Changes:
1. core/box/ss_os_acquire_box.c (lines 171-201):
- Apply MADV_POPULATE_WRITE after munmap prefix/suffix trim
- Fallback to explicit page touch for kernels < 5.14
- Always cleanup suffix region (remove MADV_DONTNEED path)
2. core/superslab_cache.c (lines 111-121):
- Use MADV_POPULATE_WRITE instead of memset for efficiency
- Fallback to memset if madvise fails
Testing Results:
- Page faults: Unchanged (~145K per 1M ops)
- Throughput: -2% (4.18M → 4.10M ops/s with HAKMEM_SS_PREFAULT=1)
- Root cause: 97.6% of page faults are from libc memset in initialization,
not from SuperSlab memory access
Conclusion: MADV_POPULATE_WRITE is effective for SuperSlab memory,
but overall page fault bottleneck comes from TLS/shared pool initialization.
Startup warmup remains the most effective solution (already implemented
in bench_random_mixed.c with +9.5% improvement).
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Problem: Warm pool had 0% hit rate (only 1 hit per 3976 misses) despite being
implemented, causing all cache misses to go through expensive superslab_refill
registry scans.
Root Cause Analysis:
- Warm pool was initialized once and pushed a single slab after each refill
- When that slab was exhausted, it was discarded (not pushed back)
- Next refill would push another single slab, which was immediately exhausted
- Pool would oscillate between 0 and 1 items, yielding 0% hit rate
Solution: Secondary Prefill on Cache Miss
When warm pool becomes empty, we now do multiple superslab_refills and prefill
the pool with 3 additional HOT superlslabs before attempting to carve. This
builds a working set of slabs that can sustain allocation pressure.
Implementation Details:
- Modified unified_cache_refill() cold path to detect empty pool
- Added prefill loop: when pool count == 0, load 3 extra superlslabs
- Store extra slabs in warm pool, keep 1 in TLS for immediate carving
- Track prefill events in g_warm_pool_stats[].prefilled counter
Results (1M Random Mixed 256B allocations):
- Before: C7 hits=1, misses=3976, hit_rate=0.0%
- After: C7 hits=3929, misses=3143, hit_rate=55.6%
- Throughput: 4.055M ops/s (maintained vs 4.07M baseline)
- Stability: Consistent 55.6% hit rate at 5M allocations (4.102M ops/s)
Performance Impact:
- No regression: throughput remained stable at ~4.1M ops/s
- Registry scan avoided in 55.6% of cache misses (significant savings)
- Warm pool now functioning as intended with strong locality
Configuration:
- TINY_WARM_POOL_MAX_PER_CLASS increased from 4 to 16 to support prefill
- Prefill budget hardcoded to 3 (tunable via env var if needed later)
- All statistics always compiled, ENV-gated printing via HAKMEM_WARM_POOL_STATS=1
Next Steps:
- Monitor for further optimization opportunities (prefill budget tuning)
- Consider adaptive prefill budget based on class-specific hit rates
- Validate at larger allocation counts (10M+ pending registry size fix)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Implementation
- Added MADV_DONTNEED when SuperSlab enters LRU cache
- Environment variable: HAKMEM_SS_LAZY_ZERO (default: 1)
- Low-risk, zero-overhead when disabled
## Results: NO MEASURABLE IMPROVEMENT
- Cycles: 70.4M (baseline) vs 70.8M (optimized) = -0.5% (worse!)
- Page faults: 7,674 (no change)
- L1 misses: 717K vs 714K (negligible)
## Key Discovery
The 11.65% clear_page_erms overhead is **kernel-level**, not allocator-level:
- Happens during page faults, not during free
- Can't be selectively deferred for SuperSlab pages
- MADV_DONTNEED syscall overhead cancels benefit
- Result: Zero improvement despite profiling showing 11.65%
## Why Profiling Was Misleading
- Page zeroing shown in profile but not controllable
- Happens globally across all allocators
- Can't isolate which faults are from our code
- Not all profile % are equally optimizable
## Conclusion
Random Mixed 1.06M ops/s appears to be near the practical limit:
- THP: no effect (already tested)
- PREFAULT: +2.6% (measurement noise)
- Lazy zeroing: 0% (syscall overhead cancels benefit)
- Realistic cap: ~1.10-1.15M ops/s (10-15% max possible)
Tiny Hot (89M ops/s) is not comparable - it's an architectural difference.
🐱 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>