// RTX 4090 (sm_89) float32 ReLU design-space sweep. // Sweeps vector width x unroll x store-policy x load-policy x block size across // tensor sizes, verifies correctness, reports best effective bandwidth per size. #include #include #include #include #include #include #include #include #include #define CK(x) do{ cudaError_t e=(x); if(e){ printf("CUDA err %s:%d: %s\n",__FILE__,__LINE__,cudaGetErrorString(e)); exit(1);} }while(0) __device__ __forceinline__ float relu1(float x){ return x > 0.0f ? x : 0.0f; } template __device__ __forceinline__ void st4(float4* p, float4 v){ if (STORE) __stcs(p, v); else *p = v; } template __device__ __forceinline__ float4 ld4(const float4* p){ return LOAD ? __ldcs(p) : *p; } template __device__ __forceinline__ void st2(float2* p, float2 v){ if (STORE) __stcs(p, v); else *p = v; } template __device__ __forceinline__ float2 ld2(const float2* p){ return LOAD ? __ldcs(p) : *p; } // ---- float4 kernel, templated unroll/store/load ---- template __global__ void kv4(float4* __restrict__ out, const float4* __restrict__ in, long long n4){ long long stride=(long long)gridDim.x*blockDim.x; for(long long b=(long long)blockIdx.x*blockDim.x+threadIdx.x; b(in+i); } #pragma unroll for(int u=0;u(out+i, r[u]); } } } // ---- float2 kernel ---- template __global__ void kv2(float2* __restrict__ out, const float2* __restrict__ in, long long n2){ long long stride=(long long)gridDim.x*blockDim.x; for(long long b=(long long)blockIdx.x*blockDim.x+threadIdx.x; b(in+i); } #pragma unroll for(int u=0;u(out+i, r[u]); } } } // ---- scalar grid-stride reference ---- __global__ void kscalar(float* __restrict__ out, const float* __restrict__ in, long long n){ long long stride=(long long)gridDim.x*blockDim.x; for(long long i=(long long)blockIdx.x*blockDim.x+threadIdx.x; i void launch_v4(float* out,const float* in,long long n,int threads){ long long n4=n/4, tail=n4*4; if(n4>0){ long long blk=ceil_div(n4,(long long)threads*U); kv4<<<(unsigned)std::min(blk, 1u<<31 - 1), threads>>>((float4*)out,(const float4*)in,n4); } if(tail>>(out,in,tail,n); } } template void launch_v2(float* out,const float* in,long long n,int threads){ long long n2=n/2, tail=n2*2; if(n2>0){ long long blk=ceil_div(n2,(long long)threads*U); kv2<<<(unsigned)std::min(blk, 1u<<31 - 1), threads>>>((float2*)out,(const float2*)in,n2); } if(tail>>(out,in,tail,n); } } void launch_scalar(float* out,const float* in,long long n,int threads){ // full-ish grid stride: cap blocks to a large number; one pass covers it long long blk=std::min(ceil_div(n,threads), 262144); kscalar<<<(unsigned)blk,threads>>>(out,in,n); } struct Cfg { std::string name; int threads; std::function fn; }; int main(){ cudaDeviceProp p; CK(cudaGetDeviceProperties(&p,0)); printf("GPU %s SMs=%d peakMemClk=%d kHz busWidth=%d-bit\n", p.name, p.multiProcessorCount, p.memoryClockRate, p.memoryBusWidth); double peak_gbps = 2.0 * p.memoryClockRate * 1e3 * (p.memoryBusWidth/8) / 1e9; // 2x for DDR printf("theoretical DRAM peak ~%.0f GB/s\n\n", peak_gbps); std::vector cfgs; for(int t : {128,256,512}){ char b[64]; #define ADD4(U,S,L,tag) { snprintf(b,64,"v4 u%d %-8s blk%d",U,tag,t); cfgs.push_back({b,t,launch_v4}); } ADD4(1,0,0,"def") ADD4(2,0,0,"def") ADD4(4,0,0,"def") ADD4(1,1,0,"st.cs") ADD4(2,1,0,"st.cs") ADD4(4,1,0,"st.cs") ADD4(1,0,1,"ld.cs") ADD4(1,1,1,"ld+st.cs") ADD4(2,1,1,"ld+st.cs") #undef ADD4 } // a couple of reference points for(int t : {256,512}){ char b[64]; snprintf(b,64,"v2 u1 def blk%d",t); cfgs.push_back({b,t,launch_v2<1,0,0>}); } for(int t : {256}){ char b[64]; snprintf(b,64,"v2 u2 st.cs blk%d",t); cfgs.push_back({b,t,launch_v2<2,1,0>}); } cfgs.push_back({"scalar blk256",256,launch_scalar}); // sizes (in elements): include 1024^2 and 4096^2 plus a sweep std::vector sizes = { 1<<16, 1<<18, 1024LL*1024, 1<<22, 4096LL*4096, 1<<26, 1<<27 }; const int WARM=50, ITER=200; for(long long n : sizes){ size_t bytes=n*sizeof(float); float *din,*dout; CK(cudaMalloc(&din,bytes)); CK(cudaMalloc(&dout,bytes)); // init host with mix of + and - (and a few exact patterns) std::vector h(n); for(long long i=0;i ho(n); CK(cudaMemcpy(ho.data(),dout,bytes,cudaMemcpyDeviceToHost)); bool ok=true; for(long long i=0;i0?h[i]:0; if(ho[i]!=e) ok=false; } // timing for(int w=0;wbestbw){ bestbw=bw; best=c.name; } } printf(" >> BEST: %s %.0f GB/s (%.1f%% of peak)\n\n", best.c_str(), bestbw, 100*bestbw/peak_gbps); cudaFree(din); cudaFree(dout); } return 0; }