/* Microbenchmark: old (full-qsort) vs new (quickselect partial-select) DSA top-keep. * * This is NOT a unit test -- test_dsa_select.c proves correctness. This measures the * headline claim of #356: that replacing the O(nk log nk) qsort over all nk context * scores with an O(nk) partial_select_desc is materially faster per call, which is * the win the issue was opened for -- and that the win GROWS with context length * (because quickselect is linear average, qsort is n-log-n). * * It re-implements the OLD top-keep inline (qsort + threshold + scans) on a private * buffer so the A/B runs in one process, same inputs, same warm caches -- a controlled * comparison. It calls the REAL (new) partial_select_desc via the include-glm.c * pattern, replicating the production threshold derivation + scans. * * Methodology (chosen to be honest, not to flatter the change): * - keep = 2048 (the real GLM-5.2 index_topk), nk swept across context lengths from * the 2049 activation boundary up to 65536 (a long conversation). * - Three score shapes: (a) realistic peaked -- a few hot keys, long tail, the shape * real DSA attention scores take; (b) uniform random -- no structure; (c) a plateau * of ties, to exercise the boundary-membership path. * - Each (shape, nk) is timed over N_REPEAT=2000 iterations, with the scores frozen * so both algorithms do IDENTICAL work. We report median ns/call and the new/old * ratio. A warmup pass primes caches before timing. * * Run: make tests/bench_dsa_select && ./tests/bench_dsa_select (not in TEST_BINS) */ #define main coli_glm_main_unused #include "../glm.c" #undef main #include #include /* ---- the OLD algorithm, verbatim from dev before #356, on a private buffer ---- */ static int cmp_pdesc_old(const void *a, const void *b){ float x=*(const float*)a, y=*(const float*)b; return xy?-1:0; } static void keep_old(const float *isc, int nk, int keep, int *dst, int *nd_out){ float *tmp=malloc((size_t)nk*sizeof(float)); memcpy(tmp,isc,(size_t)nk*sizeof(float)); qsort(tmp,(size_t)nk,sizeof(float),cmp_pdesc_old); float thr=tmp[keep-1]; int nd=0; for(int t=0;tthr) dst[nd++]=t; for(int t=0;t=0 && ts[b]>k){ ts[b+1]=ts[b]; b--; } ts[b+1]=k; } free(dst); return ts[N_REPEAT/2]; } /* the NEW algorithm calls the real partial_select_desc + replicates the production * threshold derivation and position scans. */ static void keep_new(const float *isc, int nk, int keep, int *dst, int *nd_out){ float *tmp=malloc((size_t)nk*sizeof(float)); memcpy(tmp,isc,(size_t)nk*sizeof(float)); partial_select_desc(tmp,nk,keep); float thr=tmp[0]; for(int t=1;tthr) dst[nd++]=t; for(int t=0;t> 17; brng ^= brng << 5; return (double)(brng >> 8) * (1.0 / 16777216.0); } static void fill_realistic(float *isc, int nk){ /* few hot, long distinct tail */ for(int i=0;i boundary path */ for(int i=0;i