Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
221 lines
7.0 KiB
C
221 lines
7.0 KiB
C
// 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");
|
|
}
|