Phase 9-1: O(1) SuperSlab lookup optimization - Created ss_addr_map_box: Hash table (8192 buckets) for O(1) SuperSlab lookup - Created ss_tls_hint_box: TLS caching layer for SuperSlab hints - Integrated hash table into registry (init, insert, remove, lookup) - Modified hak_super_lookup() to use new hash table - Expected: 50-80 cycles → 10-20 cycles (not verified - SuperSlab disabled by default) Phase 9-2: EMPTY slab recycling implementation - Created slab_recycling_box: SLAB_TRY_RECYCLE() macro following Box pattern - Integrated into remote drain (superslab_slab.c) - Integrated into TLS SLL drain (tls_sll_drain_box.h) with touched slab tracking - Observable: Debug tracing via HAKMEM_SLAB_RECYCLE_TRACE - Updated Makefile: Added new box objects to 3 build targets Known Issues: - SuperSlab registry exhaustion still occurs (unregistration not working) - shared_pool_release_slab() may not be removing from g_super_reg[] - Needs investigation before Phase 9-2 can be completed Expected Impact (when fixed): - Stage 1 hit rate: 0% → 80% - shared_fail events: 4 → 0 - Kernel overhead: 55% → 15% - Throughput: 16.5M → 25-30M ops/s (+50-80%) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
149 lines
5.3 KiB
C
149 lines
5.3 KiB
C
// ss_addr_map_box.h - Phase 9-1: SuperSlab Address Map Box
|
||
// Purpose: O(1) address → SuperSlab* mapping (replace linear search)
|
||
// Contract: Fast lookup with hash table (O(1) amortized, upgrade to true O(1) later)
|
||
//
|
||
// Box Pattern:
|
||
// - Single Responsibility: Address→SuperSlab mapping ONLY
|
||
// - Clear Contract: ss_map_lookup(ptr) returns SuperSlab* in O(1) amortized
|
||
// - Observable: Debug macros log all lookups in non-release builds
|
||
// - Composable: Can coexist with legacy registry during migration
|
||
//
|
||
// Performance Target:
|
||
// - Current: Linear search 50-80 cycles
|
||
// - Phase 9-1: Hash table ~10-20 cycles
|
||
// - Future: 2-tier page table ~5-10 cycles (Phase 9-2)
|
||
|
||
#ifndef HAK_BOX_SS_ADDR_MAP_H
|
||
#define HAK_BOX_SS_ADDR_MAP_H
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
#include "../hakmem_build_flags.h"
|
||
|
||
// Forward declaration
|
||
struct SuperSlab;
|
||
|
||
// ============================================================================
|
||
// Hash Table Entry (Chaining for collision resolution)
|
||
// ============================================================================
|
||
|
||
typedef struct SSMapEntry {
|
||
void* base; // SuperSlab base address (key)
|
||
struct SuperSlab* ss; // SuperSlab pointer (value)
|
||
struct SSMapEntry* next; // Chain for collisions
|
||
} SSMapEntry;
|
||
|
||
// ============================================================================
|
||
// Address Map Structure
|
||
// ============================================================================
|
||
|
||
// Hash table size: 8192 buckets (2^13)
|
||
// - Trade-off: Memory vs collision rate
|
||
// - 8K buckets × 8 bytes = 64KB (acceptable overhead)
|
||
// - Load factor target: <2 entries/bucket average
|
||
#define SS_MAP_HASH_SIZE 8192
|
||
|
||
typedef struct {
|
||
SSMapEntry* buckets[SS_MAP_HASH_SIZE]; // Hash table buckets
|
||
size_t count; // Total entries (for stats)
|
||
size_t collisions; // Collision counter (for stats)
|
||
} SSAddrMap;
|
||
|
||
// ============================================================================
|
||
// API Functions
|
||
// ============================================================================
|
||
|
||
// Initialize map (call once at startup)
|
||
void ss_map_init(SSAddrMap* map);
|
||
|
||
// Insert SuperSlab into map
|
||
// Precondition: base must be SuperSlab-aligned (512KB/1MB/2MB)
|
||
// Contract: O(1) insertion
|
||
void ss_map_insert(SSAddrMap* map, void* base, struct SuperSlab* ss);
|
||
|
||
// Lookup SuperSlab by pointer
|
||
// Contract: O(1) amortized lookup
|
||
// Returns: SuperSlab* if found, NULL if not found
|
||
struct SuperSlab* ss_map_lookup(SSAddrMap* map, void* ptr);
|
||
|
||
// Remove SuperSlab from map
|
||
// Contract: O(1) amortized removal
|
||
void ss_map_remove(SSAddrMap* map, void* base);
|
||
|
||
// Shutdown map (free all entries)
|
||
void ss_map_shutdown(SSAddrMap* map);
|
||
|
||
// ============================================================================
|
||
// Statistics (Debug builds only)
|
||
// ============================================================================
|
||
|
||
#if !HAKMEM_BUILD_RELEASE
|
||
// Print map statistics (count, collisions, load factor)
|
||
void ss_map_print_stats(SSAddrMap* map);
|
||
|
||
// Get collision rate (for performance tuning)
|
||
double ss_map_collision_rate(SSAddrMap* map);
|
||
#endif
|
||
|
||
// ============================================================================
|
||
// Debug Macros (Observable Box Pattern)
|
||
// ============================================================================
|
||
|
||
#if !HAKMEM_BUILD_RELEASE
|
||
#define SS_MAP_LOOKUP(map, ptr) \
|
||
({ \
|
||
void* _ptr = (ptr); \
|
||
struct SuperSlab* _ss = ss_map_lookup(map, _ptr); \
|
||
if (getenv("HAKMEM_SS_MAP_TRACE")) { \
|
||
fprintf(stderr, "[SS_MAP_LOOKUP] ptr=%p -> ss=%p\n", _ptr, (void*)_ss); \
|
||
} \
|
||
_ss; \
|
||
})
|
||
|
||
#define SS_MAP_INSERT(map, base, ss) \
|
||
do { \
|
||
if (getenv("HAKMEM_SS_MAP_TRACE")) { \
|
||
fprintf(stderr, "[SS_MAP_INSERT] base=%p ss=%p\n", (void*)(base), (void*)(ss)); \
|
||
} \
|
||
ss_map_insert(map, base, ss); \
|
||
} while(0)
|
||
|
||
#define SS_MAP_REMOVE(map, base) \
|
||
do { \
|
||
if (getenv("HAKMEM_SS_MAP_TRACE")) { \
|
||
fprintf(stderr, "[SS_MAP_REMOVE] base=%p\n", (void*)(base)); \
|
||
} \
|
||
ss_map_remove(map, base); \
|
||
} while(0)
|
||
#else
|
||
// Release builds: Direct function calls (no overhead)
|
||
#define SS_MAP_LOOKUP(map, ptr) ss_map_lookup(map, ptr)
|
||
#define SS_MAP_INSERT(map, base, ss) ss_map_insert(map, base, ss)
|
||
#define SS_MAP_REMOVE(map, base) ss_map_remove(map, base)
|
||
#endif
|
||
|
||
// ============================================================================
|
||
// Hash Function (Internal, exposed for testing)
|
||
// ============================================================================
|
||
|
||
// Hash pointer to bucket index
|
||
// Strategy: Use upper bits (SuperSlab-aligned, lower bits are 0)
|
||
// - ptr >> 19 (min SuperSlab size 512KB = 2^19)
|
||
// - & (SS_MAP_HASH_SIZE - 1) for modulo
|
||
static inline size_t ss_map_hash(void* ptr) {
|
||
uintptr_t addr = (uintptr_t)ptr;
|
||
// Shift by 19 bits (512KB alignment minimum)
|
||
// Then mask to table size
|
||
return (addr >> 19) & (SS_MAP_HASH_SIZE - 1);
|
||
}
|
||
|
||
// ============================================================================
|
||
// Global Instance (TLS or Global, TBD in Phase 9-1-4)
|
||
// ============================================================================
|
||
|
||
// For now: Global instance (shared across threads, needs lock)
|
||
// Phase 9-1-4: Consider TLS instance for lock-free access
|
||
extern SSAddrMap g_ss_addr_map;
|
||
|
||
#endif // HAK_BOX_SS_ADDR_MAP_H
|