From 7d8d5f310967bac599ecf66f97ee308b3baee90d Mon Sep 17 00:00:00 2001 From: 0xhis <125838106+0xhis@users.noreply.github.com> Date: Sat, 11 Jul 2026 03:59:01 -0700 Subject: [PATCH] Reduce allocation overhead in quantized matmul and MoE routing (thread-local scratch, trimmed temporaries) (#43) * Reuse quantization scratch buffers * Trim MoE routing temporaries --------- Co-authored-by: 0xhis <0xhis@users.noreply.github.com> --- c/glm.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/c/glm.c b/c/glm.c index 4783dcc..4b5e9dc 100644 --- a/c/glm.c +++ b/c/glm.c @@ -453,6 +453,22 @@ static void matmul_i4_idot(float *y, const int8_t *xq, const float *sx, const ui for(int s=0;sg_qscratch.xq_cap){ + int8_t *p=realloc(g_qscratch.xq,xn); + if(!p){ fprintf(stderr,"OOM quant scratch\n"); exit(1); } + g_qscratch.xq=p; g_qscratch.xq_cap=xn; + } + if(sn>g_qscratch.sx_cap){ + float *p=realloc(g_qscratch.sx,sn*sizeof(float)); + if(!p){ fprintf(stderr,"OOM quant scales\n"); exit(1); } + g_qscratch.sx=p; g_qscratch.sx_cap=sn; + } + *xq=g_qscratch.xq; *sx=g_qscratch.sx; +} + static void matmul_qt(float *y, const float *x, QT *w, int S){ #ifdef COLI_CUDA /* The CUDA backend owns persistent copies only for model-resident tensors. @@ -476,12 +492,12 @@ static void matmul_qt(float *y, const float *x, QT *w, int S){ * pay (S>=2 gate); on ARM/SDOT single-token DOES pay (see g_i4s / PR #9 for the VNNI * twin). Threshold configurable via I4S. */ if(g_idot && (w->fmt==1 || (w->fmt==2 && S>=g_i4s))){ - int I=w->I; - int8_t *xq=malloc((size_t)S*I); float sxb[64]; float *sx=S<=64?sxb:falloc(S); + int I=w->I; int8_t *xq; float *sx; + if(S<0 || I<0 || (size_t)S>SIZE_MAX/(size_t)(I?I:1)){ fprintf(stderr,"matmul_qt: shape overflow\n"); exit(1); } + quant_scratch((size_t)S*I,(size_t)S,&xq,&sx); for(int s=0;sfmt==1) matmul_q_idot(y,xq,sx,w->q8,w->s,S,I,w->O); else matmul_i4_idot(y,xq,sx,w->q4,w->s,S,I,w->O); - free(xq); if(sx!=sxb) free(sx); return; } if(w->fmt==1) matmul_q(y,x,w->q8,w->s,S,w->I,w->O); @@ -1146,7 +1162,7 @@ static void attention(Model *m, Layer *l, int layer, float *x, int S, int pos_ba * nell'ordine (routed nel loro ordine di union, poi shared). */ static void moe(Model *m, Layer *l, int layer, float *x, int S, float *out){ Cfg *c=&m->c; int D=c->hidden, E=c->n_experts, K=c->topk, I=c->moe_inter; - float *logit=falloc(E), *sig=falloc(E), *choice=falloc(E); + float *logit=falloc(E), *choice=falloc(E); int sI=c->moe_inter*c->n_shared; /* ---- FASE A: routing di tutte le S posizioni ---- */ int *idxs=malloc((size_t)S*K*sizeof(int)); float *ws=malloc((size_t)S*K*sizeof(float)); @@ -1154,13 +1170,13 @@ static void moe(Model *m, Layer *l, int layer, float *x, int S, float *out){ for(int s=0;srouter, 1, D, E); - for(int e=0;erouter_bias[e]; } + for(int e=0;erouter_bias[e]; } int *idx=idxs+(int64_t)s*K; float *w=ws+(int64_t)s*K; int Ksel = g_topk>0 ? (g_topkbv){bv=choice[e];best=e;} } - idx[kk]=best; w[kk]=sig[best]; + idx[kk]=best; w[kk]=logit[best]; } int Ke=Ksel; if(g_topp>0 && g_topp<1.f){ @@ -1194,10 +1210,11 @@ static void moe(Model *m, Layer *l, int layer, float *x, int S, float *out){ m->enr[layer]=keff[S-1]; for(int kk=0;kkeroute[layer][kk]=idxs[(int64_t)(S-1)*K+kk]; /* ---- FASE B: union degli expert del batch ---- */ int *uniq=malloc((size_t)E*sizeof(int)); int nu=0; - { char *seen=calloc(E,1); - for(int s=0;ssh_down, S); for(int64_t z=0;z<(int64_t)S*D;z++) out[z]+=hh[z]; - free(logit); free(sig); free(choice); free(idxs); free(ws); free(keff); free(uniq); + free(logit); free(choice); free(idxs); free(ws); free(keff); free(uniq); free(xg); free(gg); free(uu); free(hh); free(rows); free(rw); free(sg); free(su); }