Files
hakmem/core/hakmem_site_rules.c

221 lines
7.0 KiB
C
Raw Normal View History

// hakmem_site_rules.c - Site-Aware Cache Routing Implementation
// Purpose: O(1) call-site → cache route direct mapping (MVP)
//
// License: MIT
// Date: 2025-10-21
#include "hakmem_site_rules.h"
#include "hakmem_pool.h" // For POOL_CLASS constants
#include <stdio.h>
#include <string.h>
#include <time.h>
// ===========================================================================
// Internal Data Structures
// ===========================================================================
// Global Site Rules table (4-probe hash table)
static struct {
SiteRule table[SITE_RULES_CAPACITY];
// Statistics
uint64_t lookups;
uint64_t hits;
uint64_t misses;
uint64_t expirations;
uint64_t adoptions; // Rules applied (passed adoption gate)
uint64_t rejections; // Rules rejected (failed adoption gate)
int initialized;
} g_site_rules;
// ===========================================================================
// Helper Functions
// ===========================================================================
// Get current time in nanoseconds
static uint64_t get_time_ns(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
}
// Hash function (FNV-1a variant)
static inline uint32_t hash_site(uintptr_t site_id) {
uint32_t hash = 2166136261u;
hash ^= (uint32_t)(site_id & 0xFFFFFFFF);
hash *= 16777619u;
hash ^= (uint32_t)(site_id >> 32);
hash *= 16777619u;
return hash;
}
// 4-probe hash table probing
static inline uint32_t probe_index(uint32_t hash, int probe) {
// Linear probing: hash + probe
return (hash + probe) & (SITE_RULES_CAPACITY - 1);
}
// Get size class from size (same as Pool size classes: 2KB/4KB/8KB/16KB/32KB)
uint8_t hak_site_rules_get_size_class(size_t size) {
if (size <= POOL_CLASS_2KB) return 0;
if (size <= POOL_CLASS_4KB) return 1;
if (size <= POOL_CLASS_8KB) return 2;
if (size <= POOL_CLASS_16KB) return 3;
if (size <= POOL_CLASS_32KB) return 4;
return 255; // Out of range
}
// Check if Site Rule should be applied (adoption gate: win_rate >= 60%)
int hak_site_rules_should_apply(SiteRule* rule) {
if (rule->hit_count == 0) return 0; // No data yet
// MVP: Always apply (skip adoption gate for initial testing)
// Future: Implement win_rate calculation
// float win_rate = (float)rule->win_count / (float)rule->hit_count;
// return win_rate >= SITE_RULES_MIN_WIN_RATE;
return 1; // MVP: Always apply
}
// ===========================================================================
// Public API
// ===========================================================================
void hak_site_rules_init(void) {
if (g_site_rules.initialized) return;
memset(&g_site_rules, 0, sizeof(g_site_rules));
g_site_rules.initialized = 1;
printf("[SiteRules] Initialized (MVP: 4-probe hash, capacity=%d)\n", SITE_RULES_CAPACITY);
}
void hak_site_rules_shutdown(void) {
if (!g_site_rules.initialized) return;
hak_site_rules_print_stats();
g_site_rules.initialized = 0;
}
RouteType hak_site_rules_lookup(uintptr_t site_id, size_t size) {
if (!g_site_rules.initialized) hak_site_rules_init();
g_site_rules.lookups++;
// Get size class
uint8_t size_class = hak_site_rules_get_size_class(size);
if (size_class == 255) {
g_site_rules.misses++;
return ROUTE_NONE; // Size out of range
}
// 4-probe hash table lookup
uint32_t hash = hash_site(site_id);
for (int probe = 0; probe < 4; probe++) {
uint32_t idx = probe_index(hash, probe);
SiteRule* rule = &g_site_rules.table[idx];
// Empty slot → miss
if (rule->site_id == 0) {
g_site_rules.misses++;
return ROUTE_NONE;
}
// Match found
if (rule->site_id == site_id && rule->size_class == size_class) {
// Fast path: avoid syscalls here. TTL/last_used is updated on insert/update only.
// Check adoption gate (win_rate >= 60%)
if (!hak_site_rules_should_apply(rule)) {
g_site_rules.rejections++;
return ROUTE_NONE; // Rule rejected
}
// Rule hit!
g_site_rules.hits++;
g_site_rules.adoptions++;
rule->hit_count++;
return rule->route;
}
}
// All 4 probes missed → miss
g_site_rules.misses++;
return ROUTE_NONE;
}
int hak_site_rules_add(uintptr_t site_id, size_t size, RouteType route) {
if (!g_site_rules.initialized) hak_site_rules_init();
if (route == ROUTE_NONE) return 0; // Invalid route
// Get size class
uint8_t size_class = hak_site_rules_get_size_class(size);
if (size_class == 255) return 0; // Size out of range
// 4-probe hash table insertion
uint32_t hash = hash_site(site_id);
uint64_t now = get_time_ns();
for (int probe = 0; probe < 4; probe++) {
uint32_t idx = probe_index(hash, probe);
SiteRule* rule = &g_site_rules.table[idx];
// Empty slot → insert here
if (rule->site_id == 0) {
rule->site_id = site_id;
rule->size_class = size_class;
rule->route = route;
rule->hit_count = 1; // MVP: Initialize with 1 to pass adoption gate
rule->win_count = 1; // MVP: Assume success for manually-added rules
rule->last_used_ns = now;
return 1; // Success
}
// Update existing rule
if (rule->site_id == site_id && rule->size_class == size_class) {
rule->route = route;
rule->last_used_ns = now;
return 1; // Success (updated)
}
}
// All 4 probes occupied → table full (collision)
fprintf(stderr, "[SiteRules] WARNING: Table full (collision), site_id=%p\n", (void*)site_id);
return 0; // Failure
}
void hak_site_rules_print_stats(void) {
if (!g_site_rules.initialized) return;
printf("\n========================================\n");
printf("Site Rules Statistics (MVP)\n");
printf("========================================\n");
printf("Lookups: %lu\n", (unsigned long)g_site_rules.lookups);
printf("Hits: %lu\n", (unsigned long)g_site_rules.hits);
printf("Misses: %lu\n", (unsigned long)g_site_rules.misses);
printf("Adoptions: %lu (rules applied)\n", (unsigned long)g_site_rules.adoptions);
printf("Rejections: %lu (failed adoption gate)\n", (unsigned long)g_site_rules.rejections);
if (g_site_rules.lookups > 0) {
double hit_rate = (double)g_site_rules.hits / (double)g_site_rules.lookups * 100.0;
printf("Hit rate: %.1f%%\n", hit_rate);
}
// Count active rules
int active_rules = 0;
for (int i = 0; i < SITE_RULES_CAPACITY; i++) {
if (g_site_rules.table[i].site_id != 0) {
active_rules++;
}
}
printf("Active rules: %d / %d\n", active_rules, SITE_RULES_CAPACITY);
printf("========================================\n");
}