Skip to content

Commit dd97ed4

Browse files
committed
bench_paper_fusion: add unfused device-side GLASS chain arm (per-primitive kernels, global intermediates) to isolate fusion benefit from device-vs-host
1 parent 5ce552b commit dd97ed4

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

‎bench/bench_paper_fusion.cu‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,43 @@ __global__ void k_fused_riccati(const T* gP, const T* gA, const T* gB, const T*
205205
for (uint32_t i = rank; i < NU*NX; i += size) gK[p*NU*NX + i] = sK[i];
206206
}
207207

208+
// ─── UNFUSED device-side GLASS chain ─────────────────────────────────────────
209+
// The same math as the fused kernel, but each primitive launched as its own
210+
// kernel with every intermediate (PB, S, G) round-tripping through GLOBAL
211+
// memory — what a caller writes with general GLASS primitives and NO fused
212+
// riccati_gain. Isolates the fusion/smem benefit from the device-vs-host
213+
// benefit: host chain → device unfused = dispatch+locality of device
214+
// execution; device unfused → fused = composition keeping intermediates
215+
// on-chip. One block per problem, glass::block ops on global pointers.
216+
template <typename T, uint32_t NX, uint32_t NU>
217+
__global__ void k_unf_pb(const T* gP, const T* gB, T* gPB) {
218+
const size_t p = blockIdx.x;
219+
glass::gemm<T>(NX, NU, NX, (T)1, gP + p*NX*NX, gB + p*NX*NU, (T)0, gPB + p*NX*NU);
220+
}
221+
template <typename T, uint32_t NX, uint32_t NU>
222+
__global__ void k_unf_s(const T* gB, const T* gPB, const T* gR, T* gS) {
223+
const size_t p = blockIdx.x;
224+
T* S = gS + p*NU*NU;
225+
const T* R = gR + p*NU*NU;
226+
for (uint32_t i = threadIdx.x; i < NU*NU; i += blockDim.x) S[i] = R[i];
227+
__syncthreads();
228+
// S += Bᵀ·PB (op(A)=Bᵀ is NU×NX)
229+
glass::gemm<T, /*TRANSPOSE_A=*/true>(NU, NU, NX, (T)1, gB + p*NX*NU,
230+
gPB + p*NX*NU, (T)1, S);
231+
}
232+
template <typename T, uint32_t NX, uint32_t NU>
233+
__global__ void k_unf_g(const T* gPB, const T* gA, T* gG) {
234+
const size_t p = blockIdx.x;
235+
// G = (P·B)ᵀ·A = Bᵀ·P·A (P symmetric)
236+
glass::gemm<T, /*TRANSPOSE_A=*/true>(NU, NX, NX, (T)1, gPB + p*NX*NU,
237+
gA + p*NX*NX, (T)0, gG + p*NU*NX);
238+
}
239+
template <typename T, uint32_t NX, uint32_t NU>
240+
__global__ void k_unf_solve(T* gS, T* gG) {
241+
const size_t p = blockIdx.x;
242+
glass::posv<T>(NU, NX, gS + p*NU*NU, gG + p*NU*NX); // K lands in G
243+
}
244+
208245
// ─── per-(dtype, shape) driver ───────────────────────────────────────────────
209246
struct Handles { cublasHandle_t cb; cusolverDnHandle_t cs; };
210247

@@ -288,6 +325,12 @@ static void run_shape(Handles H, const char* dt) {
288325
auto fused = [&](int tb) {
289326
k_fused_riccati<T, NX, NU><<<B, tb, smem>>>(dP, dA, dB_, dR, dK, B);
290327
};
328+
auto unfused = [&](int tb) {
329+
k_unf_pb <T, NX, NU><<<B, tb>>>(dP, dB_, dPB);
330+
k_unf_s <T, NX, NU><<<B, tb>>>(dB_, dPB, dR, dS);
331+
k_unf_g <T, NX, NU><<<B, tb>>>(dPB, dA, dG);
332+
k_unf_solve<T, NX, NU><<<B, tb>>>(dS, dG);
333+
};
291334
auto chain = [&] {
292335
CK(cudaMemcpyAsync(dS, dR, RR*(size_t)B*sizeof(T), cudaMemcpyDeviceToDevice));
293336
xgemm_sb(H.cb, CUBLAS_OP_N, NX, NU, NX, (T)1, dP, NX, PP, dB_, NX, BB, (T)0, dPB, NX, BB, B);
@@ -314,6 +357,12 @@ static void run_shape(Handles H, const char* dt) {
314357
for (size_t i = 0; i < KK; i++) me = fmax(me, fabs((double)hK[i] - refK[i]));
315358
printf("CHECK shape=%ux%u dtype=%s impl=chain maxerr=%.3e\n", NX, NU, dt, me);
316359
if (!(me < tol)) { fprintf(stderr, "FATAL chain mismatch\n"); exit(4); }
360+
unfused(128); CK(cudaDeviceSynchronize());
361+
CK(cudaMemcpy(hK.data(), dG, KK*sizeof(T), cudaMemcpyDeviceToHost));
362+
me = 0;
363+
for (size_t i = 0; i < KK; i++) me = fmax(me, fabs((double)hK[i] - refK[i]));
364+
printf("CHECK shape=%ux%u dtype=%s impl=glass_unfused maxerr=%.3e\n", NX, NU, dt, me);
365+
if (!(me < tol)) { fprintf(stderr, "FATAL glass_unfused mismatch\n"); exit(4); }
317366
}
318367

319368
// timing: median over 5 trials of REPS event-bracketed reps
@@ -325,6 +374,9 @@ static void run_shape(Handles H, const char* dt) {
325374
{"fused_tb128", [&]{ fused(128); }},
326375
{"fused_tb256", [&]{ fused(256); }}, // wide-block probe: the (36,12)/(48,16)
327376
{"fused_tb512", [&]{ fused(512); }}, // chain-wins cells may be TB-starved
377+
{"glass_unfused_tb32", [&]{ unfused(32); }},
378+
{"glass_unfused_tb128", [&]{ unfused(128); }},
379+
{"glass_unfused_tb256", [&]{ unfused(256); }},
328380
{"chain", chain},
329381
};
330382
std::mt19937 order_rng(0x46555345u ^ (NX << 20) ^ (NU << 12) ^

0 commit comments

Comments
 (0)