Files
hakmem/core/front/tiny_first_page_cache.h
Moe Charm (CI) deecda7336 Phase 3 C2: Slab Metadata Cache Optimization (3 patches) - NEUTRAL
Patch 1: Policy Hot Cache
- Add TinyPolicyHot struct (route_kind[8] cached in TLS)
- Eliminate policy_snapshot() calls (~2 memory ops saved)
- Safety: disabled when learner v7 active
- Files: tiny_metadata_cache_env_box.h, tiny_metadata_cache_hot_box.{h,c}
- Integration: malloc_tiny_fast.h route selection

Patch 2: First Page Inline Cache
- Cache current slab page pointer in TLS per-class
- Avoid superslab metadata lookup (1-2 memory ops)
- Fast-path in tiny_legacy_fallback_free_base()
- Files: tiny_first_page_cache.h, tiny_unified_cache.c
- Integration: tiny_legacy_fallback_box.h

Patch 3: Bounds Check Compile-out
- Hardcode unified_cache capacity as MACRO constant
- Eliminate modulo operation (constant fold)
- Macros: TINY_UNIFIED_CACHE_CAPACITY_POW2=11, CAPACITY=2048, MASK=2047
- File: tiny_unified_cache.h

A/B Test Results (Mixed, 10-run):
- Baseline (C2=0): 40.43M ops/s (avg), 40.72M ops/s (median)
- Optimized (C2=1): 40.25M ops/s (avg), 40.29M ops/s (median)
- Improvement: -0.45% (avg), -1.06% (median)
- DECISION: NEUTRAL (within ±1.0% threshold)
- Action: Keep as research box (ENV gate OFF by default)

Cumulative Gain (Phase 2-3):
- B3 (Routing shape): +2.89%
- B4 (Wrapper split): +1.47%
- C3 (Static routing): +2.20%
- C2 (Metadata cache): -0.45%
- Total: ~6.1% (from baseline 37.5M → 39.8M ops/s)

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2025-12-13 19:19:42 +09:00

83 lines
3.1 KiB
C

// tiny_first_page_cache.h
// Phase 3 C2 Patch 2: First Page Inline Cache
//
// Purpose: Cache current slab page pointer in TLS to avoid superslab metadata lookup
//
// Design:
// - TinyFirstPageCache struct: first_page_base + first_page_free_count
// - Per-class cache (C0-C7)
// - Fast-path check in free path (before superslab lookup)
// - Auto-invalidate on refill/retire
//
// Integration:
// - tiny_legacy_fallback_free_base(): Check cache hit before superslab lookup
// - Refill/retire: Update cache with new page info
#ifndef HAK_FRONT_TINY_FIRST_PAGE_CACHE_H
#define HAK_FRONT_TINY_FIRST_PAGE_CACHE_H
#include <stdint.h>
#include <stdbool.h>
#include "../hakmem_tiny_config.h" // For TINY_NUM_CLASSES
// ============================================================================
// First Page Cache Structure
// ============================================================================
typedef struct {
void* first_page_base; // Current page base pointer (avoid superslab lookup)
uint16_t first_page_free_count; // Free slots in current page (hint only)
} TinyFirstPageCache;
// ============================================================================
// External TLS Variable
// ============================================================================
extern __thread TinyFirstPageCache g_first_page_cache[TINY_NUM_CLASSES];
// ============================================================================
// First Page Cache API
// ============================================================================
/// Check if ptr is in cached first page (fast path hint)
/// @param class_idx: Size class (0-7)
/// @param ptr: Pointer to check (BASE pointer)
/// @param page_size: Page size for this class
/// @return: true if ptr is in cached page, false otherwise
__attribute__((always_inline))
static inline bool tiny_first_page_cache_hit(uint32_t class_idx, void* ptr, size_t page_size) {
if (class_idx >= TINY_NUM_CLASSES) return false;
void* base = g_first_page_cache[class_idx].first_page_base;
if (base == NULL) return false;
// Check if ptr is within [base, base + page_size)
uintptr_t ptr_addr = (uintptr_t)ptr;
uintptr_t base_addr = (uintptr_t)base;
return (ptr_addr >= base_addr) && (ptr_addr < base_addr + page_size);
}
/// Update first page cache (on refill)
/// @param class_idx: Size class (0-7)
/// @param base: New page base pointer
/// @param count: Free slots in page
__attribute__((always_inline))
static inline void tiny_first_page_cache_update(uint32_t class_idx, void* base, uint16_t count) {
if (class_idx >= TINY_NUM_CLASSES) return;
g_first_page_cache[class_idx].first_page_base = base;
g_first_page_cache[class_idx].first_page_free_count = count;
}
/// Invalidate first page cache (on retire or page full)
/// @param class_idx: Size class (0-7)
__attribute__((always_inline))
static inline void tiny_first_page_cache_invalidate(uint32_t class_idx) {
if (class_idx >= TINY_NUM_CLASSES) return;
g_first_page_cache[class_idx].first_page_base = NULL;
g_first_page_cache[class_idx].first_page_free_count = 0;
}
#endif // HAK_FRONT_TINY_FIRST_PAGE_CACHE_H