/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/cshift/Cshift_mpi.h Copyright (C) 2015 Author: Peter Boyle Author: paboyle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ #ifndef _GRID_CSHIFT_MPI_H_ #define _GRID_CSHIFT_MPI_H_ NAMESPACE_BEGIN(Grid); const int Cshift_verbose=0; template Lattice Cshift(const Lattice &rhs,int dimension,int shift) { typedef typename vobj::vector_type vector_type; typedef typename vobj::scalar_type scalar_type; Lattice ret(rhs.Grid()); int fd = rhs.Grid()->_fdimensions[dimension]; int rd = rhs.Grid()->_rdimensions[dimension]; // Map to always positive shift modulo global full dimension. shift = (shift+fd)%fd; ret.Checkerboard() = rhs.Grid()->CheckerBoardDestination(rhs.Checkerboard(),shift,dimension); // the permute type int simd_layout = rhs.Grid()->_simd_layout[dimension]; int comm_dim = rhs.Grid()->_processors[dimension] >1 ; int splice_dim = rhs.Grid()->_simd_layout[dimension]>1 && (comm_dim); RealD t1,t0; t0=usecond(); if ( !comm_dim ) { // std::cout << "CSHIFT: Cshift_local" < void Cshift_comms(Lattice& ret,const Lattice &rhs,int dimension,int shift) { int sshift[2]; sshift[0] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Even); sshift[1] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Odd); // std::cout << "Cshift_comms dim "< void Cshift_comms_simd(Lattice& ret,const Lattice &rhs,int dimension,int shift) { int sshift[2]; sshift[0] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Even); sshift[1] = rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,Odd); // std::cout << "Cshift_comms_simd dim "< void Cshift_comms(Lattice &ret,const Lattice &rhs,int dimension,int shift,int cbmask) { typedef typename vobj::vector_type vector_type; typedef typename vobj::scalar_type scalar_type; GridBase *grid=rhs.Grid(); Lattice temp(rhs.Grid()); int fd = rhs.Grid()->_fdimensions[dimension]; int rd = rhs.Grid()->_rdimensions[dimension]; int pd = rhs.Grid()->_processors[dimension]; int simd_layout = rhs.Grid()->_simd_layout[dimension]; int comm_dim = rhs.Grid()->_processors[dimension] >1 ; assert(simd_layout==1); assert(comm_dim==1); assert(shift>=0); assert(shift_slice_nblock[dimension]*rhs.Grid()->_slice_block[dimension]; static deviceVector send_buf; send_buf.resize(buffer_size); static deviceVector recv_buf; recv_buf.resize(buffer_size); #ifndef ACCELERATOR_AWARE_MPI #ifdef GRID_CHECKSUM_COMMS buffer_size += (8 + sizeof(vobj) - 1) / sizeof(vobj); #endif static hostVector hsend_buf; hsend_buf.resize(buffer_size); static hostVector hrecv_buf; hrecv_buf.resize(buffer_size); #ifdef GRID_CHECKSUM_COMMS buffer_size -= (8 + sizeof(vobj) - 1) / sizeof(vobj); #endif #endif int cb= (cbmask==0x2)? Odd : Even; int sshift= rhs.Grid()->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,cb); RealD tcopy=0.0; RealD tgather=0.0; RealD tscatter=0.0; RealD tcomms=0.0; uint64_t xbytes=0; for(int x=0;x>1; int bytes = words * sizeof(vobj); FlightRecorder::StepLog("Cshift_Gather_plane"); tgather-=usecond(); Gather_plane_simple (rhs,send_buf,dimension,sx,cbmask); tgather+=usecond(); FlightRecorder::StepLog("Cshift_Gather_plane_complete"); // int rank = grid->_processor; int recv_from_rank; int xmit_to_rank; grid->ShiftedRanks(dimension,comm_proc,xmit_to_rank,recv_from_rank); tcomms-=usecond(); grid->Barrier(); FlightRecorder::StepLog("Cshift_SendRecv"); #ifdef ACCELERATOR_AWARE_MPI grid->SendToRecvFrom((void *)&send_buf[0], xmit_to_rank, (void *)&recv_buf[0], recv_from_rank, bytes); #else // bouncy bouncy acceleratorCopyFromDevice(&send_buf[0],&hsend_buf[0],bytes); #ifdef GRID_CHECKSUM_COMMS assert(bytes % 8 == 0); uint64_t checksum_index = grid->incrementChecksumIndex(); *(uint64_t*)(((char*)&hsend_buf[0]) + bytes) = checksum_gpu((uint64_t*)&send_buf[0], bytes / 8) ^ (1 + checksum_index); bytes += 8; #endif grid->SendToRecvFrom((void *)&hsend_buf[0], xmit_to_rank, (void *)&hrecv_buf[0], recv_from_rank, bytes); #ifdef GRID_CHECKSUM_COMMS bytes -= 8; acceleratorCopyToDevice(&hrecv_buf[0],&recv_buf[0],bytes); uint64_t expected_cs = *(uint64_t*)(((char*)&hrecv_buf[0]) + bytes); uint64_t computed_cs = checksum_gpu((uint64_t*)&recv_buf[0], bytes / 8) ^ (1 + checksum_index); assert(expected_cs == computed_cs); #else acceleratorCopyToDevice(&hrecv_buf[0],&recv_buf[0],bytes); #endif #endif FlightRecorder::StepLog("Cshift_SendRecv_complete"); xbytes+=bytes; grid->Barrier(); tcomms+=usecond(); FlightRecorder::StepLog("Cshift_barrier_complete"); tscatter-=usecond(); Scatter_plane_simple (ret,recv_buf,dimension,x,cbmask); tscatter+=usecond(); } } if (Cshift_verbose){ std::cout << GridLogPerformance << " Cshift copy "< void Cshift_comms_simd(Lattice &ret,const Lattice &rhs,int dimension,int shift,int cbmask) { GridBase *grid=rhs.Grid(); const int Nsimd = grid->Nsimd(); typedef typename vobj::vector_type vector_type; typedef typename vobj::scalar_object scalar_object; typedef typename vobj::scalar_type scalar_type; int fd = grid->_fdimensions[dimension]; int rd = grid->_rdimensions[dimension]; int ld = grid->_ldimensions[dimension]; int pd = grid->_processors[dimension]; int simd_layout = grid->_simd_layout[dimension]; int comm_dim = grid->_processors[dimension] >1 ; // std::cout << "Cshift_comms_simd dim "<< dimension << " fd "<=0); assert(shiftPermuteType(dimension); /////////////////////////////////////////////// // Simd direction uses an extract/merge pair /////////////////////////////////////////////// int buffer_size = grid->_slice_nblock[dimension]*grid->_slice_block[dimension]; // int words = sizeof(vobj)/sizeof(vector_type); static std::vector > send_buf_extract; send_buf_extract.resize(Nsimd); static std::vector > recv_buf_extract; recv_buf_extract.resize(Nsimd); scalar_object * recv_buf_extract_mpi; scalar_object * send_buf_extract_mpi; for(int s=0;s hsend_buf; hsend_buf.resize(buffer_size); static hostVector hrecv_buf; hrecv_buf.resize(buffer_size); #ifdef GRID_CHECKSUM_COMMS buffer_size -= (8 + sizeof(vobj) - 1) / sizeof(vobj); #endif #endif int bytes = buffer_size*sizeof(scalar_object); ExtractPointerArray pointers(Nsimd); // ExtractPointerArray rpointers(Nsimd); // received pointers /////////////////////////////////////////// // Work out what to send where /////////////////////////////////////////// int cb = (cbmask==0x2)? Odd : Even; int sshift= grid->CheckerBoardShiftForCB(rhs.Checkerboard(),dimension,shift,cb); // loop over outer coord planes orthog to dim for(int x=0;x>(permute_type+1)); int ic= (i&inner_bit)? 1:0; int my_coor = rd*ic + x; int nbr_coor = my_coor+sshift; int nbr_proc = ((nbr_coor)/ld) % pd;// relative shift in processors int nbr_ic = (nbr_coor%ld)/rd; // inner coord of peer int nbr_ox = (nbr_coor%rd); // outer coord of peer int nbr_lane = (i&(~inner_bit)); int recv_from_rank; int xmit_to_rank; if (nbr_ic) nbr_lane|=inner_bit; assert (sx == nbr_ox); if(nbr_proc){ grid->ShiftedRanks(dimension,nbr_proc,xmit_to_rank,recv_from_rank); tcomms-=usecond(); grid->Barrier(); send_buf_extract_mpi = &send_buf_extract[nbr_lane][0]; recv_buf_extract_mpi = &recv_buf_extract[i][0]; #ifdef ACCELERATOR_AWARE_MPI grid->SendToRecvFrom((void *)send_buf_extract_mpi, xmit_to_rank, (void *)recv_buf_extract_mpi, recv_from_rank, bytes); #else // bouncy bouncy acceleratorCopyFromDevice((void *)send_buf_extract_mpi,(void *)&hsend_buf[0],bytes); #ifdef GRID_CHECKSUM_COMMS assert(bytes % 8 == 0); uint64_t checksum_index = grid->incrementChecksumIndex(); *(uint64_t*)(((char*)&hsend_buf[0]) + bytes) = checksum_gpu((uint64_t*)send_buf_extract_mpi, bytes / 8) ^ (1 + checksum_index); bytes += 8; #endif grid->SendToRecvFrom((void *)&hsend_buf[0], xmit_to_rank, (void *)&hrecv_buf[0], recv_from_rank, bytes); #ifdef GRID_CHECKSUM_COMMS bytes -= 8; acceleratorCopyToDevice((void *)&hrecv_buf[0],(void *)recv_buf_extract_mpi,bytes); uint64_t expected_cs = *(uint64_t*)(((char*)&hrecv_buf[0]) + bytes); uint64_t computed_cs = checksum_gpu((uint64_t*)recv_buf_extract_mpi, bytes / 8) ^ (1 + checksum_index); if (expected_cs != computed_cs) { fprintf(stderr, "CSHIFT %ld <> %ld\n", expected_cs, computed_cs); fflush(stderr); } assert(expected_cs == computed_cs); #else acceleratorCopyToDevice((void *)&hrecv_buf[0],(void *)recv_buf_extract_mpi,bytes); #endif #endif xbytes+=bytes; grid->Barrier(); tcomms+=usecond(); rpointers[i] = &recv_buf_extract[i][0]; } else { rpointers[i] = &send_buf_extract[nbr_lane][0]; } } tscatter-=usecond(); Scatter_plane_merge(ret,rpointers,dimension,x,cbmask); tscatter+=usecond(); } if(Cshift_verbose){ std::cout << GridLogPerformance << " Cshift (s) copy "<