From eaa68f4005fb29ca01c32888d864004446f384ff Mon Sep 17 00:00:00 2001 From: cdhdt Date: Mon, 20 Jul 2026 23:35:55 +0200 Subject: [PATCH] =?UTF-8?q?pilot:=20LFRU-aware=20eviction=20guard=20?= =?UTF-8?q?=E2=80=94=20never=20evict=20a=20warm=20demand=20expert=20for=20?= =?UTF-8?q?a=20speculation=20(#441)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The measured failure mode of speculative prefetch (the controlled 2x2 A/B on #441): a pilot load picks the plain-LRU slot and can evict an expert that was just demand-loaded and is still hot, which then gets re-read (thrash: +9-18% bytes for +0.5-0.7pt hit rate). Fix: a speculative load may evict a RESIDENT expert only if the predicted expert is historically hotter than the victim, by the same LFRU hysteresis tier_pick_lfru already uses (25% + 4 freq counts); otherwise it drops the speculation rather than displace a warm slot. Applied to both the blocking (pilot_realload) and io_uring (pilot_uring_batch) victim selections. Cache placement only -> output byte-identical (the moe() barrier still fences every layer; a dropped speculation is just demand-loaded later, same value). Default ON for the opt-in PILOT_REAL path; PILOT_EVICT_GUARD=0 restores plain-LRU for a single-binary A/B. Reuses the existing tier_lfru_score (tier.h). make check 111/111. Perf A/B needs a drive with idle bandwidth (this host is a QLC/DRAM-less lower bound); byte-identical, so it cannot regress output. Companion to the negative multi-worker result on #441. Co-Authored-By: Claude Opus 4.8 --- c/colibri.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/c/colibri.c b/c/colibri.c index 4524c10..97ae721 100644 --- a/c/colibri.c +++ b/c/colibri.c @@ -733,6 +733,11 @@ static int g_pilot_real=0;/* PILOT_REAL=1: il pilota fa LOAD VERI cross-layer de static int g_pilot_two=0; /* PILOT_TWO=1: two-step prefetch — before running L+1's router, * approximate MoE(L) using only the shared expert (resident, no disk) * and add it to the state. Trades 3 small matmuls for +2.3% recall. */ +static int g_pilot_evict_guard=1;/* PILOT_EVICT_GUARD=0 -> old behavior (a speculation evicts the plain LRU). + * Default ON: a speculative pilot load may evict a RESIDENT expert only if the + * predicted expert is historically HOTTER than the victim (same LFRU hysteresis as + * tier_pick_lfru); otherwise it drops the speculation rather than thrash a warm + * demand-loaded expert. Cache placement only -> output byte-identical. (#441) */ /* Handshake main<->pilota per il load-vero cross-layer. Invariante di sicurezza in DUE parti: * 1) Percorso MATMUL (moe): il pilota scrive SOLO ecache[layer] con layer > g_cur_moe_layer; * il matmul in moe() legge SOLO ecache[layer]==g_cur_moe_layer, e la barriera a inizio moe() @@ -3427,7 +3432,16 @@ static void pilot_realload(Model *m, int layer, int eid){ for(int z=0;zecap){ slot=nn; isnew=1; } - else { int lru=0; for(int z=1;z output unchanged. */ + if(g_pilot_evict_guard && m->eheat && m->elast && Sl[lru].eid>=0){ + int vid=Sl[lru].eid; + uint64_t vs=tier_lfru_score(m->eheat[layer][vid],m->elast[layer][vid],m->eaccess_clock); + uint64_t cs=tier_lfru_score(m->eheat[layer][eid],m->elast[layer][eid],m->eaccess_clock); + if(cs<=vs+(vs>>2)+(4u<<8)){ atomic_fetch_add_explicit(&g_pilot_drops,1,memory_order_relaxed); + pthread_mutex_unlock(&g_pilot_mx); return; } } } ESlot *dst=&Sl[slot]; dst->eid=-1; /* nascondi dagli scan-hint mentre carica */ g_pilot_inflight[layer]++; @@ -3478,6 +3492,14 @@ static void pilot_uring_batch(Model *m){ if(Sl[z].eid< -1) continue; /* URING reservation in flight */ if(slot<0 || Sl[z].used=0 && Sl[slot].eid>=0 && g_pilot_evict_guard && m->eheat && m->elast){ + int vid=Sl[slot].eid; + uint64_t vs=tier_lfru_score(m->eheat[layer][vid],m->elast[layer][vid],m->eaccess_clock); + uint64_t cs=tier_lfru_score(m->eheat[layer][eid],m->elast[layer][eid],m->eaccess_clock); + if(cs<=vs+(vs>>2)+(4u<<8)){ atomic_fetch_add_explicit(&g_pilot_drops,1,memory_order_relaxed); + pthread_mutex_unlock(&g_pilot_mx); continue; } + } } if(slot<0){ atomic_fetch_add_explicit(&g_pilot_drops,1,memory_order_relaxed); pthread_mutex_unlock(&g_pilot_mx); continue; } ESlot *dst=&Sl[slot]; @@ -6105,6 +6127,7 @@ int main(int argc, char **argv){ if(g_pilot_real) g_pilot=1; /* PILOT_REAL implica il pilota attivo */ g_pilot_two = getenv("PILOT_TWO")?atoi(getenv("PILOT_TWO")):0; /* 1 = two-step: shared-expert-corrected router prediction (+2.3% recall, 3 extra matmuls) */ if(g_pilot_two) g_pilot=1; /* PILOT_TWO implies PILOT active */ + g_pilot_evict_guard = getenv("PILOT_EVICT_GUARD")?atoi(getenv("PILOT_EVICT_GUARD")):1; /* 0 = old LRU eviction (A/B) */ /* Default K: hint-only PILOT keeps 8 (WILLNEED hints are free, no eviction). * Under PILOT_REAL the speculative loads are REAL and create LRU eviction * pressure, so at ~28% mispredict a large K thrashes the cache — default to 6