#include "kernels.h" #include #include #include #include using B = __nv_bfloat16; union Pack { uint4 v; B b[8]; __nv_bfloat162 h[4]; }; static cudaStream_t stream() { return at::cuda::getCurrentCUDAStream(); } static const B* ptr(const Tensor& t) { return t.defined() ? (const B*)t.data_ptr() : nullptr; } static B* ptr(Tensor& t) { return (B*)t.data_ptr(); } Tensor nhwc_empty(int64_t c,int64_t t,int64_t h,int64_t w,const Tensor& like) { return at::empty({1,c,t,h,w},like.options().memory_format(at::MemoryFormat::ChannelsLast3d)); } Tensor last_frames(const Tensor& x,int n,int ph) { int C=x.size(1),T=x.size(2),H=x.size(3)-2*ph,W=x.size(4); Tensor y=nhwc_empty(C,n,H,W,x); size_t row=(size_t)H*W*C*sizeof(B),src_pitch=(size_t)(H+2*ph)*W*C*sizeof(B); const B* source=ptr(x)+((int64_t)(T-n)*(H+2*ph)+ph)*W*C; C10_CUDA_CHECK(cudaMemcpy2DAsync(ptr(y),row,source,src_pitch,row,n,cudaMemcpyDeviceToDevice,stream())); return y; } // The halo edge pack/scatter lives in comm.cu (halo_pack/halo_unpack, vectorised), with the transport. __global__ void finish_vector(B* x,const B* b,const B* s,int64_t n,int C) { for(int64_t i=(int64_t)blockIdx.x*blockDim.x+threadIdx.x;i>>(ptr(x),ptr(b),ptr(s),n,C); else finish_scalar<<>>(ptr(x),ptr(b),ptr(s),n,C); C10_CUDA_KERNEL_LAUNCH_CHECK(); } __global__ void write_kernel(const B* x,B* out,int64_t n,int T,int H,int W,int fullT,int fullH,int offsetT,int offsetH) { int64_t i=(int64_t)blockIdx.x*blockDim.x+threadIdx.x; if(i>>(ptr(x),ptr(out),x.numel(),x.size(2),x.size(3),x.size(4),out.size(2),out.size(3),frame_offset,row_offset); C10_CUDA_KERNEL_LAUNCH_CHECK(); } // phases_kernel used to sit here: PR17 replaces it, together with finish_phases below, with one // bandwidth-bound pass in resample.cu that writes the interleaved tensor directly. // F(4x4,3x3), with fp32 spatial transforms and bf16 transformed operands. __device__ __forceinline__ void bt6(float v0,float v1,float v2,float v3,float v4,float v5,float* y) { float a=v4-4*v2,b=v3-4*v1,c=v4-v2,d=2*(v3-v1); y[0]=4*v0-5*v2+v4;y[1]=a+b;y[2]=a-b;y[3]=c+d;y[4]=c-d;y[5]=4*v1-5*v3+v5; } __global__ void winograd_input_kernel(const B* x,B* v,int C,int D,int H,int W,int PH,int TH,int TW) { int HP=H+2*PH,CV=C/2;int64_t n=(int64_t)D*TH*TW*CV; for(int64_t i=(int64_t)blockIdx.x*blockDim.x+threadIdx.x;i=0&&y=0&&xx>>(ptr(x),ptr(v),C,D,H,W,ph,TH,TW); C10_CUDA_KERNEL_LAUNCH_CHECK();return v; } // (WinoPtrs, at6, winograd_output_kernel and winograd_output are deleted: with the fused inverse // in wino_epilogue.cu nothing calls them. That file's a6v reads the same A^T out of shared memory // instead of 36 separate global pointers, and it is the only copy of the transform left there.)