83 lines
3.1 KiB
C
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
|