diff --git a/Grid/lattice/Lattice_reduction.h b/Grid/lattice/Lattice_reduction.h index a6bbcf15..66788a4c 100644 --- a/Grid/lattice/Lattice_reduction.h +++ b/Grid/lattice/Lattice_reduction.h @@ -31,6 +31,7 @@ Author: Christoph Lehner #if defined(GRID_SYCL) #include #endif +#include NAMESPACE_BEGIN(Grid); @@ -448,19 +449,10 @@ template inline void sliceSum(const Lattice &Data,std::vector< int e1= grid->_slice_nblock[orthogdim]; int e2= grid->_slice_block [orthogdim]; int stride=grid->_slice_stride[orthogdim]; - - // sum over reduced dimension planes, breaking out orthog dir - // Parallel over orthog direction - autoView( Data_v, Data, CpuRead); - thread_for( r,rd, { - int so=r*grid->_ostride[orthogdim]; // base offset for start of plane - for(int n=0;n_ostride[orthogdim]; + + //Reduce Data down to lvSum + sliceSumReduction(Data,lvSum,rd, e1,e2,stride,ostride,Nsimd); // Sum across simd lanes in the plane, breaking out orthog dir. Coordinate icoor(Nd); @@ -504,6 +496,7 @@ sliceSum(const Lattice &Data,int orthogdim) return result; } + template static void sliceInnerProductVector( std::vector & result, const Lattice &lhs,const Lattice &rhs,int orthogdim) { diff --git a/Grid/lattice/Lattice_slicesum_core.h b/Grid/lattice/Lattice_slicesum_core.h new file mode 100644 index 00000000..7c3518cd --- /dev/null +++ b/Grid/lattice/Lattice_slicesum_core.h @@ -0,0 +1,218 @@ +#pragma once +#include +#if defined(GRID_CUDA) + +#include +#define gpucub cub +#define gpuError_t cudaError_t +#define gpuSuccess cudaSuccess + +#elif defined(GRID_HIP) + +#include +#define gpucub hipcub +#define gpuError_t hipError_t +#define gpuSuccess hipSuccess + +#endif + + +NAMESPACE_BEGIN(Grid); + + +#if defined(GRID_CUDA) || defined(GRID_HIP) +template inline void sliceSumReduction_cub_small(const vobj *Data, Vector &lvSum, const int rd, const int e1, const int e2, const int stride, const int ostride, const int Nsimd) { + size_t subvol_size = e1*e2; + commVector reduction_buffer(rd*subvol_size); + auto rb_p = &reduction_buffer[0]; + vobj zero_init; + zeroit(zero_init); + + + void *temp_storage_array = NULL; + size_t temp_storage_bytes = 0; + vobj *d_out; + int* d_offsets; + + std::vector offsets(rd+1,0); + + for (int i = 0; i < offsets.size(); i++) { + offsets[i] = i*subvol_size; + } + + //Allocate memory for output and offset arrays on device + d_out = static_cast(acceleratorAllocDevice(rd*sizeof(vobj))); + + d_offsets = static_cast(acceleratorAllocDevice((rd+1)*sizeof(int))); + + //copy offsets to device + acceleratorCopyToDeviceAsync(&offsets[0],d_offsets,sizeof(int)*(rd+1),computeStream); + + + gpuError_t gpuErr = gpucub::DeviceSegmentedReduce::Reduce(temp_storage_array, temp_storage_bytes, rb_p,d_out, rd, d_offsets, d_offsets+1, ::gpucub::Sum(), zero_init, computeStream); + if (gpuErr!=gpuSuccess) { + std::cout << GridLogError << "Lattice_slicesum_gpu.h: Encountered error during gpucub::DeviceSegmentedReduce::Reduce (setup)! Error: " << gpuErr < inline void sliceSumReduction_cub_large(const vobj *Data, Vector &lvSum, const int rd, const int e1, const int e2, const int stride, const int ostride, const int Nsimd) { + typedef typename vobj::vector_type vector; + const int words = sizeof(vobj)/sizeof(vector); + const int osites = rd*e1*e2; + commVectorbuffer(osites); + vector *dat = (vector *)Data; + vector *buf = &buffer[0]; + Vector lvSum_small(rd); + vector *lvSum_ptr = (vector *)&lvSum[0]; + + for (int w = 0; w < words; w++) { + accelerator_for(ss,osites,1,{ + buf[ss] = dat[ss*words+w]; + }); + + sliceSumReduction_cub_small(buf,lvSum_small,rd,e1,e2,stride, ostride,Nsimd); + + for (int r = 0; r < rd; r++) { + lvSum_ptr[w+words*r]=lvSum_small[r]; + } + + } + + +} + +template inline void sliceSumReduction_cub(const Lattice &Data, Vector &lvSum, const int rd, const int e1, const int e2, const int stride, const int ostride, const int Nsimd) +{ + autoView(Data_v, Data, AcceleratorRead); + #if defined(GRID_CUDA) + sliceSumReduction_cub_small(&Data_v[0], lvSum, rd, e1, e2, stride, ostride, Nsimd); + + #elif defined (GRID_HIP) //hipcub cannot deal with large vobjs that don't fit in shared memory, therefore separate into _small/_large. + if constexpr (sizeof(vobj) <= 256) { + sliceSumReduction_cub_small(&Data_v[0], lvSum, rd, e1, e2, stride, ostride, Nsimd); + } + else { + sliceSumReduction_cub_large(&Data_v[0], lvSum, rd, e1, e2, stride, ostride, Nsimd); + } + #endif +} +#endif + + +#if defined(GRID_SYCL) +template inline void sliceSumReduction_sycl(const Lattice &Data, Vector &lvSum, const int &rd, const int &e1, const int &e2, const int &stride, const int &ostride, const int &Nsimd) +{ + typedef typename vobj::scalar_object sobj; + size_t subvol_size = e1*e2; + + vobj *mysum = (vobj *) malloc_shared(sizeof(vobj),*theGridAccelerator); + vobj vobj_zero; + zeroit(vobj_zero); + + commVector reduction_buffer(rd*subvol_size); + + auto rb_p = &reduction_buffer[0]; + + autoView(Data_v, Data, AcceleratorRead); + + //prepare reduction buffer + accelerator_for2d( s,subvol_size, r,rd, (size_t)Nsimd,{ + + int n = s / e2; + int b = s % e2; + int so=r*ostride; // base offset for start of plane + int ss= so+n*stride+b; + + coalescedWrite(rb_p[r*subvol_size+s], coalescedRead(Data_v[ss])); + + }); + + for (int r = 0; r < rd; r++) { + mysum[0] = vobj_zero; //dirty hack: cannot pass vobj_zero as identity to sycl::reduction as its not device_copyable + theGridAccelerator->submit([&](cl::sycl::handler &cgh) { + auto Reduction = cl::sycl::reduction(mysum,std::plus<>()); + cgh.parallel_for(cl::sycl::range<1>{subvol_size}, + Reduction, + [=](cl::sycl::id<1> item, auto &sum) { + auto s = item[0]; + sum += rb_p[r*subvol_size+s]; + }); + }); + theGridAccelerator->wait(); + lvSum[r] = mysum[0]; + } + + free(mysum,*theGridAccelerator); +} +#endif + +template inline void sliceSumReduction_cpu(const Lattice &Data, Vector &lvSum, const int &rd, const int &e1, const int &e2, const int &stride, const int &ostride, const int &Nsimd) +{ + // sum over reduced dimension planes, breaking out orthog dir + // Parallel over orthog direction + autoView( Data_v, Data, CpuRead); + thread_for( r,rd, { + int so=r*ostride; // base offset for start of plane + for(int n=0;n inline void sliceSumReduction(const Lattice &Data, Vector &lvSum, const int &rd, const int &e1, const int &e2, const int &stride, const int &ostride, const int &Nsimd) +{ + #if defined(GRID_CUDA) || defined(GRID_HIP) + + sliceSumReduction_cub(Data, lvSum, rd, e1, e2, stride, ostride, Nsimd); + + #elif defined(GRID_SYCL) + + sliceSumReduction_sycl(Data, lvSum, rd, e1, e2, stride, ostride, Nsimd); + + #else + sliceSumReduction_cpu(Data, lvSum, rd, e1, e2, stride, ostride, Nsimd); + + #endif +} + + +NAMESPACE_END(Grid); \ No newline at end of file diff --git a/Grid/perfmon/Tracing.h b/Grid/perfmon/Tracing.h index 5000cef4..10b638dc 100644 --- a/Grid/perfmon/Tracing.h +++ b/Grid/perfmon/Tracing.h @@ -34,7 +34,7 @@ class GridTracer { }; inline void tracePush(const char *name) { roctxRangePushA(name); } inline void tracePop(const char *name) { roctxRangePop(); } -inline int traceStart(const char *name) { roctxRangeStart(name); } +inline int traceStart(const char *name) { return roctxRangeStart(name); } inline void traceStop(int ID) { roctxRangeStop(ID); } #endif diff --git a/Grid/threads/Accelerator.h b/Grid/threads/Accelerator.h index ff5ccd7a..d4407fad 100644 --- a/Grid/threads/Accelerator.h +++ b/Grid/threads/Accelerator.h @@ -225,6 +225,8 @@ inline void acceleratorFreeShared(void *ptr){ cudaFree(ptr);}; inline void acceleratorFreeDevice(void *ptr){ cudaFree(ptr);}; inline void acceleratorCopyToDevice(void *from,void *to,size_t bytes) { cudaMemcpy(to,from,bytes, cudaMemcpyHostToDevice);} inline void acceleratorCopyFromDevice(void *from,void *to,size_t bytes){ cudaMemcpy(to,from,bytes, cudaMemcpyDeviceToHost);} +inline void acceleratorCopyToDeviceAsync(void *from, void *to, size_t bytes, cudaStream_t stream = copyStream) { cudaMemcpyAsync(to,from,bytes, cudaMemcpyHostToDevice, stream);} +inline void acceleratorCopyFromDeviceAsync(void *from, void *to, size_t bytes, cudaStream_t stream = copyStream) { cudaMemcpyAsync(to,from,bytes, cudaMemcpyDeviceToHost, stream);} inline void acceleratorMemSet(void *base,int value,size_t bytes) { cudaMemset(base,value,bytes);} inline void acceleratorCopyDeviceToDeviceAsynch(void *from,void *to,size_t bytes) // Asynch { @@ -442,6 +444,8 @@ inline void acceleratorFreeShared(void *ptr){ auto r=hipFree(ptr);}; inline void acceleratorFreeDevice(void *ptr){ auto r=hipFree(ptr);}; inline void acceleratorCopyToDevice(void *from,void *to,size_t bytes) { auto r=hipMemcpy(to,from,bytes, hipMemcpyHostToDevice);} inline void acceleratorCopyFromDevice(void *from,void *to,size_t bytes){ auto r=hipMemcpy(to,from,bytes, hipMemcpyDeviceToHost);} +inline void acceleratorCopyToDeviceAsync(void *from, void *to, size_t bytes, hipStream_t stream = copyStream) { auto r = hipMemcpyAsync(to,from,bytes, hipMemcpyHostToDevice, stream);} +inline void acceleratorCopyFromDeviceAsync(void *from, void *to, size_t bytes, hipStream_t stream = copyStream) { auto r = hipMemcpyAsync(to,from,bytes, hipMemcpyDeviceToHost, stream);} //inline void acceleratorCopyDeviceToDeviceAsynch(void *from,void *to,size_t bytes) { hipMemcpy(to,from,bytes, hipMemcpyDeviceToDevice);} //inline void acceleratorCopySynchronise(void) { } inline void acceleratorMemSet(void *base,int value,size_t bytes) { auto r=hipMemset(base,value,bytes);} diff --git a/tests/core/Test_sliceSum.cc b/tests/core/Test_sliceSum.cc new file mode 100644 index 00000000..e366f1f3 --- /dev/null +++ b/tests/core/Test_sliceSum.cc @@ -0,0 +1,321 @@ +#include + +template inline void sliceSumCPU(const Grid::Lattice &Data,std::vector &result,int orthogdim) +{ + using namespace Grid; + /////////////////////////////////////////////////////// + // FIXME precision promoted summation + // may be important for correlation functions + // But easily avoided by using double precision fields + /////////////////////////////////////////////////////// + typedef typename vobj::scalar_object sobj; + typedef typename vobj::scalar_object::scalar_type scalar_type; + GridBase *grid = Data.Grid(); + assert(grid!=NULL); + + const int Nd = grid->_ndimension; + const int Nsimd = grid->Nsimd(); + + assert(orthogdim >= 0); + assert(orthogdim < Nd); + + int fd=grid->_fdimensions[orthogdim]; + int ld=grid->_ldimensions[orthogdim]; + int rd=grid->_rdimensions[orthogdim]; + + Vector lvSum(rd); // will locally sum vectors first + Vector lsSum(ld,Zero()); // sum across these down to scalars + ExtractBuffer extracted(Nsimd); // splitting the SIMD + + result.resize(fd); // And then global sum to return the same vector to every node + for(int r=0;r_slice_nblock[orthogdim]; + int e2= grid->_slice_block [orthogdim]; + int stride=grid->_slice_stride[orthogdim]; + int ostride=grid->_ostride[orthogdim]; + + //Reduce Data down to lvSum + sliceSumReduction_cpu(Data,lvSum,rd, e1,e2,stride,ostride,Nsimd); + + // Sum across simd lanes in the plane, breaking out orthog dir. + Coordinate icoor(Nd); + + for(int rt=0;rtiCoorFromIindex(icoor,idx); + + int ldx =rt+icoor[orthogdim]*rd; + + lsSum[ldx]=lsSum[ldx]+extracted[idx]; + + } + } + + // sum over nodes. + for(int t=0;t_processor_coor[orthogdim] ) { + result[t]=lsSum[lt]; + } else { + result[t]=Zero(); + } + + } + scalar_type * ptr = (scalar_type *) &result[0]; + int words = fd*sizeof(sobj)/sizeof(scalar_type); + grid->GlobalSumVector(ptr, words); +} + + +int main (int argc, char ** argv) { + + using namespace Grid; + + Grid_init(&argc,&argv); + + + Coordinate latt_size({64,64,64,16}); + auto simd_layout = GridDefaultSimd(Nd, vComplexD::Nsimd()); + auto mpi_layout = GridDefaultMpi(); + GridCartesian Grid(latt_size, simd_layout, mpi_layout); + + std::vector seeds({1, 2, 3, 4}); + + GridParallelRNG pRNG(&Grid); + pRNG.SeedFixedIntegers(seeds); + + LatticeComplexD test_data(&Grid); + gaussian(pRNG,test_data); + + std::vector reduction_reference; + std::vector reduction_result; + + //warmup + for (int sweeps = 0; sweeps < 5; sweeps++) { + reduction_result = sliceSum(test_data,0); + } + + int trace_id = traceStart("sliceSum benchmark - ComplexD"); + std::cout << GridLogMessage << "Testing ComplexD" << std::endl; + std::cout << GridLogMessage << "sizeof(ComplexD) = " << sizeof(ComplexD) << std::endl; + std::cout << GridLogMessage << "sizeof(vComplexD) = " << sizeof(vComplexD) << std::endl; + for (int i = 0; i < Nd; i++) { + + RealD t=-usecond(); + + tracePush("sliceSum"); + sliceSumCPU(test_data,reduction_reference,i); + tracePop("sliceSum"); + + t+=usecond(); + std::cout << GridLogMessage << "Orthog. dir. = " << i << std::endl; + std::cout << GridLogMessage << "CPU sliceSum took "< reduction_reference_cv; + std::vector reduction_result_cv; + + //warmup + for (int sweeps = 0; sweeps < 5; sweeps++) { + reduction_result_cv = sliceSum(test_data_cv,0); + } + trace_id = traceStart("sliceSum benchmark - SpinVectorD"); + + std::cout << GridLogMessage << "Testing SpinVectorD" << std::endl; + std::cout << GridLogMessage << "sizeof(SpinVectorD) = " << sizeof(SpinVectorD) << std::endl; + std::cout << GridLogMessage << "sizeof(vSpinVectorD) = " << sizeof(vSpinVectorD) << std::endl; + for (int i = 0; i < Nd; i++) { + + RealD t=-usecond(); + + tracePush("sliceSum"); + sliceSumCPU(test_data_cv,reduction_reference_cv,i); + tracePop("sliceSum"); + + t+=usecond(); + std::cout << GridLogMessage << "Orthog. dir. = " << i << std::endl; + std::cout << GridLogMessage << "CPU sliceSum took "< reduction_reference_scv; + std::vector reduction_result_scv; + + //warmup + for (int sweeps = 0; sweeps < 5; sweeps++) { + reduction_result_scv = sliceSum(test_data_scv,0); + } + trace_id = traceStart("sliceSum benchmark - SpinColourVectorD"); + + std::cout << GridLogMessage << "Testing SpinColourVectorD" << std::endl; + std::cout << GridLogMessage << "sizeof(SpinColourVectorD) = " << sizeof(SpinColourVectorD) << std::endl; + std::cout << GridLogMessage << "sizeof(vSpinColourVectorD) = " << sizeof(vSpinColourVectorD) << std::endl; + for (int i = 0; i < Nd; i++) { + + RealD t=-usecond(); + + tracePush("sliceSum"); + sliceSumCPU(test_data_scv,reduction_reference_scv,i); + tracePop("sliceSum"); + + t+=usecond(); + std::cout << GridLogMessage << "Orthog. dir. = " << i << std::endl; + std::cout << GridLogMessage << "CPU sliceSum took "< reduction_reference_scm; + std::vector reduction_result_scm; + + //warmup + for (int sweeps = 0; sweeps < 5; sweeps++) { + reduction_result_scm = sliceSum(test_data_scm,0); + } + trace_id = traceStart("sliceSum benchmark - SpinColourMatrixD"); + + std::cout << GridLogMessage << "Testing SpinColourMatrixD" << std::endl; + std::cout << GridLogMessage << "sizeof(SpinColourMatrixD) = " << sizeof(SpinColourMatrixD) << std::endl; + std::cout << GridLogMessage << "sizeof(vSpinColourMatrixD) = " << sizeof(vSpinColourMatrixD) << std::endl; + for (int i = 0; i < Nd; i++) { + + RealD t=-usecond(); + + tracePush("sliceSum"); + sliceSumCPU(test_data_scm,reduction_reference_scm,i); + tracePop("sliceSum"); + + t+=usecond(); + std::cout << GridLogMessage << "Orthog. dir. = " << i << std::endl; + std::cout << GridLogMessage << "CPU sliceSum took "<