106 lines
4.2 KiB
C
106 lines
4.2 KiB
C
|
|
// hakmem_pool.h - L2 Hybrid Pool (2-32KiB Mid-Size Allocations)
|
|||
|
|
// Purpose: Per-thread pool with site-based sharding for mid-size fast-path
|
|||
|
|
//
|
|||
|
|
// Design Philosophy:
|
|||
|
|
// - **5 size classes**: 2KiB, 4KiB, 8KiB, 16KiB, 32KiB
|
|||
|
|
// - **64KiB pool pages**: 32 blocks (2KiB), 16 blocks (4KiB), 8 blocks (8KiB), etc.
|
|||
|
|
// - **per-thread freelist**: Lock-free allocation (mimalloc strategy)
|
|||
|
|
// - **O(1) site→shard mapping**: `shard = (pc >> 4) & (SHARDS-1)`
|
|||
|
|
// - **MPSC queue**: Remote-free handling (cross-thread deallocation)
|
|||
|
|
//
|
|||
|
|
// Target Workloads:
|
|||
|
|
// - mir (medium): 2-32KiB allocations → +52% → target +10-20%
|
|||
|
|
// - mixed: combination → +66% → target +10-25%
|
|||
|
|
//
|
|||
|
|
// Integration: Called by hakmem.c between malloc (< 2KiB) and BigCache (>= 1MB)
|
|||
|
|
//
|
|||
|
|
// License: MIT
|
|||
|
|
// Date: 2025-10-21
|
|||
|
|
|
|||
|
|
#ifndef HAKMEM_POOL_H
|
|||
|
|
#define HAKMEM_POOL_H
|
|||
|
|
|
|||
|
|
#include <stddef.h>
|
|||
|
|
#include <stdint.h>
|
|||
|
|
|
|||
|
|
// ===========================================================================
|
|||
|
|
// Configuration Constants
|
|||
|
|
// ===========================================================================
|
|||
|
|
|
|||
|
|
#define POOL_NUM_CLASSES 7 // 2KiB, 4KiB, 8KiB, 16KiB, 32KiB, DYN1, DYN2 (optional)
|
|||
|
|
#define POOL_PAGE_SIZE (64 * 1024) // 64KiB per pool page
|
|||
|
|
#define POOL_NUM_SHARDS 64 // Site-based sharding (power of 2)
|
|||
|
|
|
|||
|
|
// Size class boundaries (in bytes)
|
|||
|
|
#define POOL_CLASS_2KB (2 * 1024)
|
|||
|
|
#define POOL_CLASS_4KB (4 * 1024)
|
|||
|
|
#define POOL_CLASS_8KB (8 * 1024)
|
|||
|
|
#define POOL_CLASS_16KB (16 * 1024)
|
|||
|
|
#define POOL_CLASS_32KB (32 * 1024)
|
|||
|
|
#define POOL_CLASS_40KB (40 * 1024) // Phase 6.21: Bridge class 0
|
|||
|
|
#define POOL_CLASS_52KB (52 * 1024) // Phase 6.21: Bridge class 1
|
|||
|
|
|
|||
|
|
// Minimum/maximum size handled by pool
|
|||
|
|
#define POOL_MIN_SIZE POOL_CLASS_2KB // 2KiB minimum
|
|||
|
|
#define POOL_MAX_SIZE POOL_CLASS_52KB // 52KiB maximum (Phase 6.21: expanded for Bridge classes)
|
|||
|
|
|
|||
|
|
// Remote-free drain threshold
|
|||
|
|
#define POOL_REMOTE_DRAIN_THRESHOLD 16 // Drain every N allocs
|
|||
|
|
|
|||
|
|
// ===========================================================================
|
|||
|
|
// Public API
|
|||
|
|
// ===========================================================================
|
|||
|
|
|
|||
|
|
// Initialize pool system (called by hak_init)
|
|||
|
|
void hak_pool_init(void);
|
|||
|
|
|
|||
|
|
// Shutdown pool system and release all pages
|
|||
|
|
void hak_pool_shutdown(void);
|
|||
|
|
|
|||
|
|
// Try to allocate from pool (returns NULL if size not in range)
|
|||
|
|
// Args: size - requested allocation size (2-32KiB)
|
|||
|
|
// site_id - call-site address (for shard selection)
|
|||
|
|
// Returns: Pointer to allocated block, or NULL if pool unavailable
|
|||
|
|
void* hak_pool_try_alloc(size_t size, uintptr_t site_id);
|
|||
|
|
|
|||
|
|
// Free block back to pool
|
|||
|
|
// Args: ptr - pointer to block (from hak_pool_try_alloc)
|
|||
|
|
// size - original allocation size (for class determination)
|
|||
|
|
// site_id - call-site address (for shard routing)
|
|||
|
|
void hak_pool_free(void* ptr, size_t size, uintptr_t site_id);
|
|||
|
|
|
|||
|
|
// Mid fast-path helpers (headerless route)
|
|||
|
|
// Returns 1 if ptr belongs to Mid pool (1–32KiB). When out_size is non-NULL,
|
|||
|
|
// fills the class size in bytes.
|
|||
|
|
int hak_pool_mid_lookup(void* ptr, size_t* out_size);
|
|||
|
|
|
|||
|
|
// Free using Mid page descriptors (no header read). Safe when HDR_LIGHT=2.
|
|||
|
|
void hak_pool_free_fast(void* ptr, uintptr_t site_id);
|
|||
|
|
|
|||
|
|
// Print pool statistics (called by hak_shutdown)
|
|||
|
|
void hak_pool_print_stats(void);
|
|||
|
|
|
|||
|
|
// Stats snapshot (per-class counters). Arrays must have length POOL_NUM_CLASSES.
|
|||
|
|
void hak_pool_stats_snapshot(uint64_t hits[], uint64_t misses[], uint64_t refills[], uint64_t frees[]);
|
|||
|
|
|
|||
|
|
// Extra metrics snapshot for learner logging (monotonic counters)
|
|||
|
|
// Outputs: trylock_attempts, trylock_success, ring_underflow (may be NULL if not needed)
|
|||
|
|
void hak_pool_extra_metrics_snapshot(uint64_t* trylock_attempts, uint64_t* trylock_success, uint64_t* ring_underflow);
|
|||
|
|
|
|||
|
|
// ===========================================================================
|
|||
|
|
// Internal Helpers (for testing/debugging)
|
|||
|
|
// ===========================================================================
|
|||
|
|
|
|||
|
|
// Phase 6.10.1: hak_pool_get_class_index() is now static inline (hakmem_pool.c:70)
|
|||
|
|
// Removed from public API (no longer needed in header)
|
|||
|
|
|
|||
|
|
// Get shard index from site_id (0-63)
|
|||
|
|
int hak_pool_get_shard_index(uintptr_t site_id);
|
|||
|
|
|
|||
|
|
// Check if size is poolable (2-32KiB range)
|
|||
|
|
static inline int hak_pool_is_poolable(size_t size) {
|
|||
|
|
return size >= POOL_MIN_SIZE && size <= POOL_MAX_SIZE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif // HAKMEM_POOL_H
|