char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
5a6caa05f
char/aliceai-t5-moe
1#include "fa-vec.h" 2 3#include "bench.h" 4#include "ggml-backend.h" 5#include "ggml-metal-tuning.h" 6#include "ggml.h" 7 8#include <algorithm> 9#include <cmath> 10#include <cstdio> 11#include <cstring> 12#include <random> 13#include <set> 14#include <string> 15#include <vector> 16 17// GQA spec-decode shape: enough query heads to keep the GPU busy so the Q>1 K/V-reuse 18// benefit is visible. nh KV heads, nr2 query heads each, nr3 batches. 19static const int FA_NH = 4 ; 20static const int FA_NR2 = 8 ; 21static const int FA_NR3 = 1 ; 22 23struct fa_shape { 24int dk ; 25int dv ; 26int ne01 ;// query rows 27int ne11 ;// KV length 28ggml_type type_kv ; 29}; 30 31// mirrors test_flash_attn_ext::build_graph for the subset this tuner sweeps 32// (mask=true, sinks=false, prec=F32, type_K==type_V, no permute) 33static ggml_tensor * fa_build_graph (ggml_context * ctx ,const fa_shape & s ) { 34const int64_t dk_padded = GGML_PAD (s .dk ,ggml_blck_size (s .type_kv )); 35const int64_t dv_padded = GGML_PAD (s .dv ,ggml_blck_size (s .type_kv )); 36 37ggml_tensor * q = ggml_new_tensor_4d (ctx ,GGML_TYPE_F32 ,dk_padded ,s .ne01 ,FA_NH * FA_NR2 ,FA_NR3 ); 38ggml_set_name (q ,"q" ); 39 40// K/V are views of a 2x-tall parent, as they are of the KV cache in production 41ggml_tensor * k0 = ggml_new_tensor_4d (ctx ,s .type_kv ,dk_padded ,2 * s .ne11 ,FA_NH ,FA_NR3 ); 42ggml_tensor * k = ggml_view_4d (ctx ,k0 ,dk_padded ,s .ne11 ,FA_NH ,FA_NR3 ,k0 -> nb [1 ],k0 -> nb [2 ],k0 -> nb [3 ],0 ); 43ggml_set_name (k ,"k" ); 44 45ggml_tensor * v = nullptr ; 46if (dk_padded == 576 && dv_padded == 512 ) { 47// MLA: the V cache is a sub-view of the K cache 48v = ggml_view_4d (ctx ,k ,dv_padded ,s .ne11 ,FA_NH ,FA_NR3 ,k -> nb [1 ],k -> nb [2 ],k -> nb [3 ],0 ); 49 }else { 50ggml_tensor * v0 = ggml_new_tensor_4d (ctx ,s .type_kv ,dv_padded ,2 * s .ne11 ,FA_NH ,FA_NR3 ); 51v = ggml_view_4d (ctx ,v0 ,dv_padded ,s .ne11 ,FA_NH ,FA_NR3 ,v0 -> nb [1 ],v0 -> nb [2 ],v0 -> nb [3 ],0 ); 52 } 53ggml_set_name (v ,"v" ); 54 55ggml_tensor * m = ggml_new_tensor_4d (ctx ,GGML_TYPE_F16 ,s .ne11 ,s .ne01 ,1 ,FA_NR3 ); 56ggml_set_name (m ,"m" ); 57 58ggml_tensor * out = ggml_flash_attn_ext (ctx ,q ,k ,v ,m ,1.0f /sqrtf ((float )s .dk ),0.0f ,0.0f ); 59ggml_prec_set_acc (out ,GGML_PREC_F32 ); 60ggml_set_name (out ,"out" ); 61 62return out ; 63} 64 65static uint64_t fa_op_flops (const fa_shape & s ) { 66// Q*K^T is ne01 x dk x ne11, P*V is ne01 x ne11 x dv, per head 67return (uint64_t )2 * FA_NH * FA_NR2 * s .ne01 * (s .dk + s .dv )* s .ne11 * FA_NR3 ; 68} 69 70static void fa_init_uniform (ggml_tensor * t , std::mt19937 & rng ,float min ,float max ) { 71const size_t nels = ggml_nelements (t ); 72 73 std::vector < float > data (nels ); 74 std::uniform_real_distribution < float > dist (min ,max ); 75for (size_t i = 0 ;i < nels ;i ++ ) { 76data [i ]= dist (rng ); 77 } 78 79if (t -> type == GGML_TYPE_F32 ) { 80ggml_backend_tensor_set (t ,data .data (),0 ,nels * sizeof (float )); 81return ; 82 } 83 84GGML_ASSERT (ggml_is_quantized (t -> type )|| t -> type == GGML_TYPE_F16 || t -> type == GGML_TYPE_BF16 ); 85GGML_ASSERT (nels %ggml_blck_size (t -> type )== 0 ); 86 87 std::vector < float > imatrix (t -> ne [0 ],1.0f ); 88const float * im = imatrix .data (); 89if (!ggml_quantize_requires_imatrix (t -> type )) { 90// when the imatrix is optional, exercise both paths; pick via one of the random numbers 91if (data [0 ]> 0.5f * (min + max )) { 92im = nullptr ; 93 } 94 } 95 96const size_t blck_size = ggml_blck_size (t -> type ); 97const size_t n_blocks = nels /blck_size ; 98 99 std::vector < uint8_t > dataq (ggml_row_size (t -> type ,nels )); 100ggml_quantize_chunk (t -> type ,data .data (),dataq .data (),0 ,n_blocks ,blck_size ,im ); 101 102ggml_backend_tensor_set (t ,dataq .data (),0 ,dataq .size ()); 103} 104 105// mirrors init_tensor_kq_mask: f16 mask with ~20% of its blocks set to -INF or zero. 106// the -INF blocks are what drives the kernel's skip-INF path, so this pattern is 107// load-bearing for the timings, not just for numerics. 108static void fa_init_kq_mask (ggml_tensor * t , std::mt19937 & rng ,float min ,float max ) { 109GGML_ASSERT (t -> type == GGML_TYPE_F16 ); 110 111const int32_t ne0 = (int32_t )t -> ne [0 ]; 112const int32_t ne1 = (int32_t )t -> ne [1 ]; 113const int32_t ne2 = (int32_t )t -> ne [2 ]; 114const int32_t ne3 = (int32_t )t -> ne [3 ]; 115 116 std::vector < float > data_f32 (size_t (ne0 )* ne1 * ne2 * ne3 ); 117 std::vector < ggml_fp16_t > data_f16 (size_t (ne0 )* ne1 * ne2 * ne3 ); 118 119 std::uniform_real_distribution < float > dis (min ,max ); 120for (size_t i = 0 ;i < data_f32 .size ();i ++ ) { 121data_f32 [i ]= dis (rng ); 122 } 123 124const int blck0 = 128 ; 125const int blck1 = 64 ; 126 127const int n_inf_zero_blocks = 0.2 * (ne0 * ne1 * ne2 * ne3 ) / (blck0 * blck1 ); 128 129for (int b = 0 ;b < n_inf_zero_blocks ;b ++ ) { 130const int p3 = (int ) (rng () %ne3 ); 131const int p2 = (int ) (rng () %ne2 ); 132const int p1 = (int ) (rng () %ne1 ); 133const int p0 = (int ) (rng () %ne0 ); 134 135const bool inf = rng ()& 1 ; 136 137for (int i1 = 0 ;i1 < blck1 && p1 + i1 < ne1 ;i1 ++ ) { 138const int idx = p3 * ne2 * ne1 * ne0 + p2 * ne1 * ne0 + (p1 + i1 )* ne0 + p0 ; 139 140for (int i0 = 0 ;i0 < blck0 && p0 + i0 < ne0 ;i0 ++ ) { 141data_f32 [idx + i0 ]= inf ?- INFINITY :0.0f ; 142 } 143 } 144 } 145 146ggml_fp32_to_fp16_row (data_f32 .data (),data_f16 .data (),ne0 * ne1 * ne2 * ne3 ); 147 148ggml_backend_tensor_set (t ,data_f16 .data (),0 ,data_f16 .size ()* sizeof (ggml_fp16_t )); 149} 150 151static unsigned fa_cell_seed (const fa_shape & s ,unsigned base ) { 152unsigned h = base ; 153for (int v : {s .dk ,s .dv ,s .ne01 ,s .ne11 , (int )s .type_kv }) { 154h = h * 1000003u + (unsigned )v ; 155 } 156return h ; 157} 158 159static void fa_init_tensors (ggml_context * ctx ,const fa_shape & s ,unsigned base_seed ) { 160 std::mt19937 rng (fa_cell_seed (s ,base_seed )); 161 162for (ggml_tensor * t = ggml_get_first_tensor (ctx );t != NULL ;t = ggml_get_next_tensor (ctx ,t )) { 163if (t -> view_src != NULL ) { 164continue ;// views share their parent's data 165 } 166if (strcmp (t -> name ,"m" )== 0 ) { 167fa_init_kq_mask (t ,rng ,-1.0f ,1.0f ); 168 }else { 169fa_init_uniform (t ,rng ,-1.0f ,1.0f ); 170 } 171 } 172} 173 174using set_override_t = void (* )(int ,int ); 175using clear_override_t = void (* )(void ); 176using bucket_t = int (* )(int64_t ); 177using baseline_ne_t = int (* )(int ,int ); 178using device_token_t = const char * (* ) (ggml_backend_dev_t ); 179 180struct fa_procs { 181set_override_t set_ov = nullptr ; 182clear_override_t clr_ov = nullptr ; 183bucket_t ne11_bucket = nullptr ; 184bucket_t ne01_bucket = nullptr ; 185baseline_ne_t baseline_ne = nullptr ; 186device_token_t dev_token = nullptr ; 187 188bool ok ()const {return set_ov && clr_ov && ne11_bucket && ne01_bucket && baseline_ne && dev_token ; } 189}; 190 191static fa_procs fa_resolve_procs (ggml_backend_dev_t dev ) { 192ggml_backend_reg_t reg = ggml_backend_dev_backend_reg (dev ); 193 194fa_procs p ; 195p .set_ov = (set_override_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_metal_tuning_set_fa_vec_override" ); 196p .clr_ov = 197 (clear_override_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_metal_tuning_clear_fa_vec_override" ); 198p .ne11_bucket = (bucket_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_metal_tuning_fa_vec_ne11_bucket" ); 199p .ne01_bucket = (bucket_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_metal_tuning_fa_vec_ne01_bucket" ); 200p .baseline_ne = 201 (baseline_ne_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_metal_tuning_fa_vec_baseline_ne" ); 202p .dev_token = (device_token_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_metal_tuning_device_token" ); 203 204return p ; 205} 206 207static bool fa_filter_has (const char * filter ,const char * name ) { 208if (!filter ) { 209return true; 210 } 211 212const std::string f = std::string ("," )+ filter + "," ; 213 214return f .find (std::string ("," )+ name + "," )!= std::string::npos ; 215} 216 217struct fa_cand { 218int Q ,NE ; 219}; 220 221struct fa_point { 222int dk ,dv ,ne11 ,ne01 ; 223 std::vector < double > t ; 224}; 225 226// base_i identifies the (Q=1, baseline NE) anchor configuration. 227static std::vector < fa_cand > fa_build_cands (const fa_procs & procs ,int dk ,int dv ,int & base_i ) { 228const int base_ne = procs .baseline_ne (dk ,dv ); 229 230 std::vector < fa_cand > cands ; 231base_i = -1 ; 232for (int ne : ggml_metal_tuning::fa_vec_legal_ne (dk ,dv )) { 233for (int Q : {1 ,2 ,4 }) { 234if (Q == 1 && ne == base_ne ) { 235base_i = (int )cands .size (); 236 } 237cands .push_back ({Q ,ne }); 238 } 239 } 240GGML_ASSERT (base_i >=0 ); 241 242return cands ; 243} 244 245bool tuner_fa_vec_run (ggml_backend_t backend ,ggml_backend_dev_t dev ,const tuner_opts & opts ) { 246const fa_procs procs = fa_resolve_procs (dev ); 247if (!procs .ok ()) { 248fprintf (stderr ,"error: metal fa_vec tuning procs unavailable\n" ); 249return false; 250 } 251 252const char * dev_token = procs .dev_token (dev ); 253 254struct shape_t { 255int dk ,dv ; 256 }; 257 258const shape_t shapes []= { 259 {32 ,32 }, 260 {64 ,64 }, 261 {96 ,96 }, 262 {128 ,128 }, 263 {192 ,192 }, 264 {192 ,128 }, 265 {256 ,256 }, 266 {320 ,256 }, 267 {512 ,512 }, 268 {576 ,512 } 269 }; 270// nsg is a pipeline specialization constant (1 up to ne11=2048, 2 up to 4096, 4 above), so ne11 271// bucket 1 takes two samples to cover both of its regimes. Bucket 0 is not sampled at all: the 272// runtime leaves short KV at baseline, so no measurement there can reach the table. 273const int ne11_rep []= {2048 ,3072 ,8192 ,32768 }; 274const int ne01_rep []= {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,16 };// point buckets (1-4) + tail mod-4 cycle + anchor 275 276struct dtype_t { 277ggml_type type ; 278const char * token ; 279 }; 280 281const dtype_t dtypes []= { 282 {GGML_TYPE_F16 ,"GGML_TYPE_F16" }, 283 {GGML_TYPE_Q4_0 ,"GGML_TYPE_Q4_0" }, 284 {GGML_TYPE_Q4_1 ,"GGML_TYPE_Q4_1" }, 285 {GGML_TYPE_Q5_0 ,"GGML_TYPE_Q5_0" }, 286 {GGML_TYPE_Q5_1 ,"GGML_TYPE_Q5_1" }, 287 {GGML_TYPE_Q8_0 ,"GGML_TYPE_Q8_0" }, 288 }; 289 290const double TUNE_TAU = 0.05 ;// max POINTWISE regret to ride a domain default 291const double TUNE_THETA = 1.05 ;// min AGGREGATE bucket speedup vs baseline to tune at all 292 293const cooldown_opts cool = { 294opts .cooldown ,opts .cool_drift ,opts .cool_eps ,opts .cool_max_wait ,opts .cool_max_retry , 295 }; 296 297fprintf (stderr ,"seed=%u reps=%d cooldown=%s (drift=%.2f eps=%.2f max_wait=%ds max_retry=%d)\n" ,opts .seed , 298opts .reps ,cool .enabled ?"on" :"off" ,cool .drift ,cool .eps ,cool .max_wait ,cool .max_retry ); 299fprintf (stderr ,"device token: %s\n" ,dev_token ); 300 301int n_untrusted = 0 ; 302 303// stdout carries nothing but table rows, so the whole stream pastes into fa_vec_tuned_table 304for (const auto & dtype :dtypes ) { 305const ggml_type type_kv = dtype .type ; 306if (!fa_filter_has (opts .dtype_filter ,ggml_type_name (type_kv ))) { 307continue ; 308 } 309 310fprintf (stderr ,"\n### dtype=%s\n" ,ggml_type_name (type_kv )); 311 312 std::vector < fa_point > pts ; 313 314for (auto s :shapes ) { 315if (!fa_filter_has (opts .dk_filter , std::to_string (s .dk ).c_str ())) { 316continue ; 317 } 318 319int base_i = 0 ; 320 std::vector < fa_cand > cands = fa_build_cands (procs ,s .dk ,s .dv ,base_i ); 321 322for (int ne11 :ne11_rep ) { 323for (int ne01 :ne01_rep ) { 324const fa_shape sh = {s .dk ,s .dv ,ne01 ,ne11 ,type_kv }; 325 326perf_cell cell = build_perf_cell ( 327backend , [& ](ggml_context * ctx ) {return fa_build_graph (ctx ,sh ); }, 328 [& ](ggml_context * ctx ) {fa_init_tensors (ctx ,sh ,opts .seed ); }, 329 [& ](ggml_tensor * ) {return fa_op_flops (sh ); }); 330 331if (cell .gf == nullptr ) { 332continue ; 333 } 334 335// randomize candidate order to decorrelate thermal drift across the cell 336 std::vector < int > order ((size_t )cands .size ()); 337for (size_t i = 0 ;i < order .size ();++ i ) { 338order [i ]= (int )i ; 339 } 340 std::shuffle (order .begin (),order .end (), std::mt19937 (fa_cell_seed (sh ,opts .seed ))); 341 342char label [128 ]; 343snprintf (label ,sizeof (label ),"dk=%d ne11=%d" ,s .dk ,ne11 ); 344 345cell_result r = measure_cell ( 346backend ,cell ,opts .reps ,order , [& ](int i ) {procs .set_ov (cands [i ].Q ,cands [i ].NE ); }, 347 [& ]() {procs .clr_ov (); },base_i ,cool ,label ); 348 349if (r .anchor_min > 0.0 ) { 350fprintf (stderr ,"# noise dk=%d dv=%d ne11=%d ne01=%d spread=%.1f%%\n" ,s .dk ,s .dv ,ne11 ,ne01 , 351100.0 * (r .anchor_max - r .anchor_min ) /r .anchor_min ); 352 } 353 354if (!r .trusted ) { 355n_untrusted ++ ; 356fprintf (stderr ,"# DROP untrusted cell dk=%d dv=%d ne11=%d ne01=%d\n" ,s .dk ,s .dv ,ne11 ,ne01 ); 357continue ; 358 } 359 360int best_i = -1 ; 361for (size_t i = 0 ;i < cands .size ();++ i ) { 362if (r .t [i ]> 0.0 && (best_i < 0 || r .t [i ]< r .t [best_i ])) { 363best_i = (int )i ; 364 } 365 } 366const double base_t = r .t [base_i ]; 367const bool keep = best_i >=0 && base_t > 0.0 && r .t [best_i ]< base_t * 0.98 ; 368 369fprintf (stderr ,"# dtype=%s dk=%d dv=%d ne11=%d ne01=%d:" ,ggml_type_name (type_kv ),s .dk ,s .dv , 370ne11 ,ne01 ); 371for (size_t i = 0 ;i < cands .size ();++ i ) { 372fprintf (stderr ," Q%dNE%d=%.1f%s" ,cands [i ].Q ,cands [i ].NE ,r .t [i ], 373 (int )i == best_i ?"*" :"" ); 374 } 375if (keep ) { 376fprintf (stderr ," => Q%d,NE%d %.2fx\n" ,cands [best_i ].Q ,cands [best_i ].NE , 377base_t /r .t [best_i ]); 378 }else { 379fprintf (stderr ," => baseline\n" ); 380 } 381 382pts .push_back ({s .dk ,s .dv ,ne11 ,ne01 ,r .t }); 383 } 384 } 385 } 386 387// compress into pasteable rows. per (dk,dv) and ne01 domain {decode==1, batch>=2}, 388// emit one ne11-collapsed default cfg (ne11_b=-1) plus a per-bucket exception wherever the 389// default's pointwise regret vs the bucket target exceeds TUNE_TAU, or the default is not 390// admissible for that bucket (see never_slower / admissible below). 391 std::vector < std::string > rows_out ; 392char rbuf [192 ]; 393 394for (auto s :shapes ) { 395if (!fa_filter_has (opts .dk_filter , std::to_string (s .dk ).c_str ())) { 396continue ; 397 } 398 399int base_i = 0 ; 400 std::vector < fa_cand > cands = fa_build_cands (procs ,s .dk ,s .dv ,base_i ); 401 402struct bkt_t { 403int b11 ,b01 ,Ti ; 404 std::vector < double > agg ; 405 std::vector < const fa_point *> bp ; 406 }; 407 408// A config may represent a bucket only if it is no slower than baseline at every point that 409// bucket covers. The aggregate gate below sums absolute times, so it can pass on the aligned 410// and deep points while a misaligned ne01 pays the mod-Q padding. Nothing measured, nothing 411// proven: a bucket with no surviving sample admits baseline only. 412auto never_slower = [& ](const std::vector < const fa_point *> & bp ,int i ) { 413if (i == base_i ) { 414return true; 415 } 416if (bp .empty ()) { 417return false; 418 } 419for (const auto * p :bp ) { 420if (p -> t [i ] <=0.0 || p -> t [base_i ] <=0.0 || p -> t [i ]> p -> t [base_i ]) { 421return false; 422 } 423 } 424return true; 425 }; 426 427// The padded-row waste ceil(n/Q)*Q/n is largest at the smallest ne01 of each residue class 428// mod Q, so one of a bucket's first Q values carries the worst padding it can ever see, and 429// that value has to be sampled. Otherwise the bucket bounds nothing: a config picked on the 430// aligned ne01=8,16 says nothing about ne01=9. This covers the padding term only - the 431// per-row cost varies with ne01 too - so it is a floor on the evidence, not a proof. 432auto admissible = [& ](const std::vector < const fa_point *> & bp ,int b01 ,int i ) { 433if (!never_slower (bp ,i )) { 434return false; 435 } 436const int Q = cands [i ].Q ; 437if (Q == 1 ) { 438return true;// one row per threadgroup, no padding to witness 439 } 440int lo = bp [0 ]-> ne01 ; 441for (const auto * p :bp ) { 442lo = std::min (lo ,p -> ne01 ); 443 } 444while (lo > 1 && procs .ne01_bucket (lo - 1 )== b01 ) { 445lo -- ;// walk down to where this bucket's runtime domain starts 446 } 447int wit = lo ; 448double wmax = 0.0 ; 449for (int n = lo ;n < lo + Q && procs .ne01_bucket (n )== b01 ;++ n ) { 450const int padded = ((n + Q - 1 ) /Q )* Q ; 451const double w = (double )padded /n ; 452if (w > wmax ) { 453wmax = w ; 454wit = n ; 455 } 456 } 457for (const auto * p :bp ) { 458if (p -> ne01 == wit ) { 459return true; 460 } 461 } 462return false; 463 }; 464 465 std::set < std::pair < int ,int >> buckets ; 466for (int ne11 :ne11_rep ) { 467const int b11 = procs .ne11_bucket (ne11 ); 468if (b11 == 0 ) { 469continue ; 470 } 471for (int ne01 :ne01_rep ) { 472buckets .insert ({b11 ,procs .ne01_bucket (ne01 ) }); 473 } 474 } 475 476 std::vector < bkt_t > bks ; 477for (const auto & bb :buckets ) { 478const int b11 = bb .first ,b01 = bb .second ; 479 480 std::vector < const fa_point *> bp ; 481for (const auto & p :pts ) { 482if (p .dk == s .dk && p .dv == s .dv && procs .ne11_bucket (p .ne11 )== b11 && 483procs .ne01_bucket (p .ne01 )== b01 ) { 484bp .push_back (& p ); 485 } 486 } 487 488fprintf (stderr ,"# bucket dk=%d dv=%d ne11_b=%d ne01_b=%d samples=%zu\n" ,s .dk ,s .dv ,b11 ,b01 , 489bp .size ()); 490if (bp .empty ()) { 491// nothing to check a config against, so pin the bucket to baseline instead of 492// letting the ne11-collapsed domain default ride in unmeasured 493fprintf (stderr ,"# WARN empty bucket dk=%d dv=%d ne11_b=%d ne01_b=%d -> baseline\n" ,s .dk ,s .dv , 494b11 ,b01 ); 495bks .push_back ({b11 ,b01 ,base_i , std::vector < double > (cands .size (),0.0 ), {} }); 496continue ; 497 } 498 499 std::vector < double > agg (cands .size (),0.0 ),worst (cands .size (),0.0 ); 500for (const auto * p :bp ) { 501double bestt = 0.0 ; 502for (size_t i = 0 ;i < cands .size ();++ i ) { 503if (p -> t [i ]> 0.0 && (bestt == 0.0 || p -> t [i ]< bestt )) { 504bestt = p -> t [i ]; 505 } 506 } 507for (size_t i = 0 ;i < cands .size ();++ i ) { 508agg [i ]+= p -> t [i ]; 509if (p -> t [i ]> 0.0 && bestt > 0.0 ) { 510worst [i ]= std::max (worst [i ],p -> t [i ] /bestt ); 511 } 512 } 513 } 514 515int robust = -1 ,oracle_pick = -1 ; 516for (size_t i = 0 ;i < cands .size ();++ i ) { 517auto tighter = [& ](int j ) { 518return j < 0 || worst [i ]< worst [j ]|| 519 (worst [i ]== worst [j ]&& (cands [i ].Q < cands [j ].Q || 520 (cands [i ].Q == cands [j ].Q && cands [i ].NE < cands [j ].NE ))); 521 }; 522if (tighter (oracle_pick )) { 523oracle_pick = (int )i ; 524 } 525if (admissible (bp ,b01 , (int )i )&& tighter (robust )) { 526robust = (int )i ; 527 } 528 } 529 530const bool tune = robust != base_i && agg [base_i ]> 0.0 && agg [robust ]> 0.0 && 531agg [base_i ] /agg [robust ] >=TUNE_THETA ; 532 533// report what the no-harm rule cost this bucket, but only when it changed the outcome: 534// a sweep on another machine then shows where the winner loses, instead of just 535// emitting a smaller table 536const bool refused = oracle_pick != robust && oracle_pick != base_i && agg [base_i ]> 0.0 && 537agg [oracle_pick ]> 0.0 && agg [base_i ] /agg [oracle_pick ] >=TUNE_THETA ; 538if (refused ) { 539double over = 0.0 ; 540int at11 = 0 ,at01 = 0 ; 541for (const auto * p :bp ) { 542if (p -> t [base_i ]> 0.0 && p -> t [oracle_pick ] /p -> t [base_i ]- 1.0 > over ) { 543over = p -> t [oracle_pick ] /p -> t [base_i ]- 1.0 ; 544at11 = p -> ne11 ; 545at01 = p -> ne01 ; 546 } 547 } 548if (over > 0.0 ) { 549fprintf (stderr , 550"# reject dk=%d dv=%d ne11_b=%d ne01_b=%d Q%dNE%d: +%.2f%% vs baseline at " 551"ne11=%d ne01=%d\n" , 552s .dk ,s .dv ,b11 ,b01 ,cands [oracle_pick ].Q ,cands [oracle_pick ].NE ,100.0 * over ,at11 , 553at01 ); 554 }else { 555fprintf (stderr ,"# reject dk=%d dv=%d ne11_b=%d ne01_b=%d Q%dNE%d: no padding witness\n" ,s .dk , 556s .dv ,b11 ,b01 ,cands [oracle_pick ].Q ,cands [oracle_pick ].NE ); 557 } 558 } 559 560bks .push_back ({b11 ,b01 ,tune ?robust :base_i ,agg ,bp }); 561 } 562 563// pointwise regret of default cfg d vs the bucket target: a ratio-of-sums lets a 564// default that wins on aligned ne01 hide a large penalty on a misaligned point 565auto reg_pointwise = [& ](const bkt_t * b ,int d ) { 566double r = 0.0 ; 567for (const auto * p :b -> bp ) { 568const double td = p -> t [d ],tT = p -> t [b -> Ti ]; 569if (td > 0.0 && tT > 0.0 ) { 570r = std::max (r ,td /tT - 1.0 ); 571 } 572 } 573return r ; 574 }; 575 576for (int dom = 0 ;dom <=1 ;++ dom ) {// 0 = decode (ne01==1), 1 = batch (ne01>=2) 577 std::vector < const bkt_t *> db ; 578for (const auto & b :bks ) { 579if ((dom == 0 )== (b .b01 == 0 )) { 580db .push_back (& b ); 581 } 582 } 583if (db .empty ()) { 584continue ; 585 } 586 587// default cfg = the one minimizing (#rows, total achieved time, Q, NE) 588int bestD = -1 ,bestRows = 1 <<30 ; 589double bestTot = 0.0 ; 590for (size_t d = 0 ;d < cands .size ();++ d ) { 591int rows = ((int )d != base_i ) ?1 :0 ; 592double tot = 0.0 ; 593for (const auto * b :db ) { 594if (reg_pointwise (b , (int )d )> TUNE_TAU || !admissible (b -> bp ,b -> b01 , (int )d )) { 595rows ++ ; 596tot += b -> agg [b -> Ti ]; 597 }else { 598tot += b -> agg [d ]; 599 } 600 } 601const bool better = 602bestD < 0 || rows < bestRows || 603 (rows == bestRows && 604 (tot < bestTot || 605 (tot == bestTot && (cands [d ].Q < cands [bestD ].Q || 606 (cands [d ].Q == cands [bestD ].Q && cands [d ].NE < cands [bestD ].NE ))))); 607if (better ) { 608bestD = (int )d ; 609bestRows = rows ; 610bestTot = tot ; 611 } 612 } 613 614if (bestD != base_i ) { 615snprintf (rbuf ,sizeof (rbuf )," { { %s, %s, %d, %d, -1, %d }, { %d, %d } }," ,dev_token , 616dtype .token ,s .dk ,s .dv ,dom ,cands [bestD ].Q ,cands [bestD ].NE ); 617rows_out .emplace_back (rbuf ); 618 } 619for (const auto * b :db ) { 620if (reg_pointwise (b ,bestD ) <=TUNE_TAU && admissible (b -> bp ,b -> b01 ,bestD )) { 621continue ; 622 } 623snprintf (rbuf ,sizeof (rbuf )," { { %s, %s, %d, %d, %d, %d }, { %d, %d } }," ,dev_token , 624dtype .token ,s .dk ,s .dv ,b -> b11 ,b -> b01 ,cands [b -> Ti ].Q ,cands [b -> Ti ].NE ); 625rows_out .emplace_back (rbuf ); 626 } 627 } 628 } 629 630for (const auto & r :rows_out ) { 631printf ("%s\n" ,r .c_str ()); 632 } 633fflush (stdout ); 634 } 635 636if (n_untrusted > 0 ) { 637fprintf (stderr ,"\n%d cells excluded as untrusted (see DROP lines above)\n" ,n_untrusted ); 638 } 639 640return true; 641}