2025-11-05 12:31:14 +09:00
// hakmem_elo.c - ELO Rating Strategy Selection Implementation
//
// Multi-objective optimization using ELO rating system
// Composite score: 40% CPU + 30% PageFaults + 30% Memory
# include "hakmem_elo.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <time.h>
// Global state
static EloStrategyCandidate g_strategies [ ELO_MAX_STRATEGIES ] ;
static int g_num_strategies = 0 ;
static int g_initialized = 0 ;
static int g_current_strategy = 0 ;
static uint64_t g_total_selections = 0 ;
// Strategy threshold presets (geometric progression from 512KB to 8MB)
static const size_t STRATEGY_THRESHOLDS [ ] = {
524288 , // 512KB
786432 , // 768KB
1048576 , // 1MB
1572864 , // 1.5MB
2097152 , // 2MB
3145728 , // 3MB
4194304 , // 4MB
6291456 , // 6MB
8388608 , // 8MB
12582912 , // 12MB
16777216 , // 16MB
33554432 // 32MB
} ;
// Fast random (for epsilon-greedy)
static uint64_t g_rng_state = 123456789 ;
static uint64_t fast_random ( void ) {
g_rng_state ^ = g_rng_state < < 13 ;
g_rng_state ^ = g_rng_state > > 7 ;
g_rng_state ^ = g_rng_state < < 17 ;
return g_rng_state ;
}
// Initialize ELO system
void hak_elo_init ( void ) {
if ( g_initialized ) return ;
// Initialize random seed
g_rng_state = ( uint64_t ) time ( NULL ) ;
// Create strategy candidates
g_num_strategies = sizeof ( STRATEGY_THRESHOLDS ) / sizeof ( STRATEGY_THRESHOLDS [ 0 ] ) ;
if ( g_num_strategies > ELO_MAX_STRATEGIES ) {
g_num_strategies = ELO_MAX_STRATEGIES ;
}
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
g_strategies [ i ] . strategy_id = i ;
g_strategies [ i ] . elo_rating = ELO_INITIAL_RATING ;
g_strategies [ i ] . wins = 0 ;
g_strategies [ i ] . losses = 0 ;
g_strategies [ i ] . draws = 0 ;
g_strategies [ i ] . samples = 0 ;
g_strategies [ i ] . threshold_bytes = STRATEGY_THRESHOLDS [ i ] ;
g_strategies [ i ] . active = 1 ;
}
// Select initial strategy (middle of the pack)
g_current_strategy = g_num_strategies / 2 ;
g_initialized = 1 ;
2025-11-11 01:47:06 +09:00
# if !HAKMEM_BUILD_RELEASE
fprintf ( stderr , " [ELO] Initialized %d strategies (thresholds: 512KB-32MB) \n " , g_num_strategies ) ;
# endif
2025-11-05 12:31:14 +09:00
}
// Shutdown ELO system
void hak_elo_shutdown ( void ) {
if ( ! g_initialized ) return ;
hak_elo_print_leaderboard ( ) ;
g_initialized = 0 ;
}
// Epsilon-greedy strategy selection
int hak_elo_select_strategy ( void ) {
if ( ! g_initialized ) hak_elo_init ( ) ;
g_total_selections + + ;
// Epsilon-greedy: 10% exploration, 90% exploitation
double rand_val = ( double ) ( fast_random ( ) % 1000 ) / 1000.0 ;
if ( rand_val < ELO_EPSILON ) {
// Exploration: random active strategy
int active_count = 0 ;
int active_indices [ ELO_MAX_STRATEGIES ] ;
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
if ( g_strategies [ i ] . active ) {
active_indices [ active_count + + ] = i ;
}
}
if ( active_count > 0 ) {
int idx = fast_random ( ) % active_count ;
g_current_strategy = active_indices [ idx ] ;
}
} else {
// Exploitation: highest ELO rating
double best_rating = - 1e9 ;
int best_idx = 0 ;
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
if ( g_strategies [ i ] . active & & g_strategies [ i ] . elo_rating > best_rating ) {
best_rating = g_strategies [ i ] . elo_rating ;
best_idx = i ;
}
}
g_current_strategy = best_idx ;
}
return g_current_strategy ;
}
// Get threshold for strategy
size_t hak_elo_get_threshold ( int strategy_id ) {
if ( ! g_initialized ) hak_elo_init ( ) ;
if ( strategy_id < 0 | | strategy_id > = g_num_strategies ) {
return STRATEGY_THRESHOLDS [ g_num_strategies / 2 ] ;
}
return g_strategies [ strategy_id ] . threshold_bytes ;
}
// Record allocation result
void hak_elo_record_alloc ( int strategy_id , size_t size , uint64_t duration_ns ) {
if ( ! g_initialized ) return ;
if ( strategy_id < 0 | | strategy_id > = g_num_strategies ) return ;
EloStrategyCandidate * strategy = & g_strategies [ strategy_id ] ;
strategy - > samples + + ;
// Simple tracking (real implementation would track full stats)
( void ) size ;
( void ) duration_ns ;
}
// Compute composite score (normalized 0-1)
double hak_elo_compute_score ( const EloAllocStats * stats ) {
// Normalize each metric (lower is better, so invert)
// For now, use simple heuristics
const double MAX_CPU_NS = 100000.0 ; // 100 microseconds
const double MAX_PAGE_FAULTS = 1000.0 ;
const double MAX_BYTES_LIVE = 100000000.0 ; // 100MB
double cpu_score = 1.0 - fmin ( stats - > cpu_ns / MAX_CPU_NS , 1.0 ) ;
double pf_score = 1.0 - fmin ( stats - > page_faults / MAX_PAGE_FAULTS , 1.0 ) ;
double mem_score = 1.0 - fmin ( stats - > bytes_live / MAX_BYTES_LIVE , 1.0 ) ;
// Weighted combination: 40% CPU, 30% PageFaults, 30% Memory
return 0.4 * cpu_score + 0.3 * pf_score + 0.3 * mem_score ;
}
// Update ELO ratings (standard ELO formula)
void hak_elo_update_ratings ( EloStrategyCandidate * a , EloStrategyCandidate * b , double score_diff ) {
// Expected probability of A winning
double expected_a = 1.0 / ( 1.0 + pow ( 10.0 , ( b - > elo_rating - a - > elo_rating ) / 400.0 ) ) ;
// Actual result: 1.0 = A wins, 0.0 = B wins, 0.5 = draw
double actual_a ;
if ( score_diff > 0.01 ) {
actual_a = 1.0 ; // A wins
a - > wins + + ;
b - > losses + + ;
} else if ( score_diff < - 0.01 ) {
actual_a = 0.0 ; // B wins
a - > losses + + ;
b - > wins + + ;
} else {
actual_a = 0.5 ; // Draw
a - > draws + + ;
b - > draws + + ;
}
// Update ratings
a - > elo_rating + = ELO_K_FACTOR * ( actual_a - expected_a ) ;
b - > elo_rating + = ELO_K_FACTOR * ( ( 1.0 - actual_a ) - ( 1.0 - expected_a ) ) ;
}
// Trigger ELO evolution (pairwise comparison)
void hak_elo_trigger_evolution ( void ) {
if ( ! g_initialized ) return ;
2025-11-11 01:47:06 +09:00
# if !HAKMEM_BUILD_RELEASE
fprintf ( stderr , " [ELO] Triggering evolution (pairwise comparison)... \n " ) ;
# endif
2025-11-05 12:31:14 +09:00
// Count active strategies with enough samples
int eligible [ ELO_MAX_STRATEGIES ] ;
int eligible_count = 0 ;
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
if ( g_strategies [ i ] . active & & g_strategies [ i ] . samples > = ELO_MIN_SAMPLES ) {
eligible [ eligible_count + + ] = i ;
}
}
if ( eligible_count < 2 ) {
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " [ELO] Not enough eligible strategies (need 2, have %d) \n " , eligible_count ) ; }
return ;
}
// Perform pairwise comparisons (all pairs)
int comparisons = 0 ;
for ( int i = 0 ; i < eligible_count ; i + + ) {
for ( int j = i + 1 ; j < eligible_count ; j + + ) {
EloStrategyCandidate * a = & g_strategies [ eligible [ i ] ] ;
EloStrategyCandidate * b = & g_strategies [ eligible [ j ] ] ;
// Mock comparison (in real implementation, would run N samples)
// For now, simulate based on threshold proximity to 2MB (optimal)
size_t optimal = 2097152 ; // 2MB
double score_a = 1.0 / ( 1.0 + fabs ( ( double ) a - > threshold_bytes - ( double ) optimal ) / ( double ) optimal ) ;
double score_b = 1.0 / ( 1.0 + fabs ( ( double ) b - > threshold_bytes - ( double ) optimal ) / ( double ) optimal ) ;
double score_diff = score_a - score_b ;
hak_elo_update_ratings ( a , b , score_diff ) ;
comparisons + + ;
}
}
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " [ELO] Completed %d pairwise comparisons \n " , comparisons ) ; }
// Survival: keep top-M strategies
if ( eligible_count > ELO_SURVIVAL_COUNT ) {
// Sort by ELO rating
int sorted_indices [ ELO_MAX_STRATEGIES ] ;
for ( int i = 0 ; i < eligible_count ; i + + ) {
sorted_indices [ i ] = eligible [ i ] ;
}
// Simple bubble sort (good enough for 12 strategies)
for ( int i = 0 ; i < eligible_count - 1 ; i + + ) {
for ( int j = 0 ; j < eligible_count - i - 1 ; j + + ) {
if ( g_strategies [ sorted_indices [ j ] ] . elo_rating <
g_strategies [ sorted_indices [ j + 1 ] ] . elo_rating ) {
int temp = sorted_indices [ j ] ;
sorted_indices [ j ] = sorted_indices [ j + 1 ] ;
sorted_indices [ j + 1 ] = temp ;
}
}
}
// Deactivate bottom strategies
for ( int i = ELO_SURVIVAL_COUNT ; i < eligible_count ; i + + ) {
int idx = sorted_indices [ i ] ;
g_strategies [ idx ] . active = 0 ;
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " [ELO] Strategy %d (%.0fKB) eliminated (rating: %.1f) \n " ,
idx , g_strategies [ idx ] . threshold_bytes / 1024.0 , g_strategies [ idx ] . elo_rating ) ; }
}
}
hak_elo_print_leaderboard ( ) ;
}
// Print statistics
void hak_elo_print_stats ( void ) {
if ( ! g_initialized ) return ;
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " \n [ELO] Statistics: \n " ) ; }
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " Total selections: %lu \n " , g_total_selections ) ; }
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " Active strategies: " ) ; }
int active_count = 0 ;
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
if ( g_strategies [ i ] . active ) active_count + + ;
}
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " %d/%d \n " , active_count , g_num_strategies ) ; }
}
// Print leaderboard
void hak_elo_print_leaderboard ( void ) {
if ( ! g_initialized ) return ;
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) {
fprintf ( stderr , " \n [ELO] Leaderboard: \n " ) ;
fprintf ( stderr , " Rank | ID | Threshold | ELO Rating | W/L/D | Samples | Status \n " ) ;
fprintf ( stderr , " -----|----|-----------+------------+-------+---------+-------- \n " ) ;
} }
// Sort by ELO rating
int sorted_indices [ ELO_MAX_STRATEGIES ] ;
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
sorted_indices [ i ] = i ;
}
for ( int i = 0 ; i < g_num_strategies - 1 ; i + + ) {
for ( int j = 0 ; j < g_num_strategies - i - 1 ; j + + ) {
if ( g_strategies [ sorted_indices [ j ] ] . elo_rating <
g_strategies [ sorted_indices [ j + 1 ] ] . elo_rating ) {
int temp = sorted_indices [ j ] ;
sorted_indices [ j ] = sorted_indices [ j + 1 ] ;
sorted_indices [ j + 1 ] = temp ;
}
}
}
for ( int i = 0 ; i < g_num_strategies ; i + + ) {
int idx = sorted_indices [ i ] ;
EloStrategyCandidate * s = & g_strategies [ idx ] ;
{ const char * q = getenv ( " HAKMEM_QUIET " ) ; if ( ! ( q & & strcmp ( q , " 1 " ) = = 0 ) ) fprintf ( stderr , " %4d | %2d | %7.0fKB | %10.1f | %lu/%lu/%lu | %7lu | %s \n " ,
i + 1 , s - > strategy_id , s - > threshold_bytes / 1024.0 , s - > elo_rating ,
s - > wins , s - > losses , s - > draws , s - > samples ,
s - > active ? " ACTIVE " : " eliminated " ) ; }
}
}
2025-11-11 01:47:06 +09:00
// Release-silent logging
# include "hakmem_internal.h"