// 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 #include #include #include "hakmem_internal.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; #if !HAKMEM_BUILD_RELEASE fprintf(stderr, "[SiteRules] Initialized (MVP: 4-probe hash, capacity=%d)\n", SITE_RULES_CAPACITY); #endif } 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"); }