/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/communicator/Communicator_mpi.cc Copyright (C) 2015 Author: Peter Boyle 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 */ #include "Grid.h" #include #include namespace Grid { /////////////////////////////////////////////////////////////////////////////////////////////////// // Info that is setup once and indept of cartesian layout /////////////////////////////////////////////////////////////////////////////////////////////////// int CartesianCommunicator::ShmSetup = 0; MPI_Comm CartesianCommunicator::communicator_world; MPI_Comm CartesianCommunicator::ShmComm; MPI_Win CartesianCommunicator::ShmWindow; std::vector CartesianCommunicator::GroupRanks; std::vector CartesianCommunicator::MyGroup; std::vector CartesianCommunicator::ShmCommBufs; void *CartesianCommunicator::ShmBufferSelf(void) { return ShmCommBufs[ShmRank]; } void *CartesianCommunicator::ShmBuffer(int rank) { int gpeer = GroupRanks[rank]; if (gpeer == MPI_UNDEFINED){ return NULL; } else { return ShmCommBufs[gpeer]; } } void *CartesianCommunicator::ShmBufferTranslate(int rank,void * local_p) { int gpeer = GroupRanks[rank]; if (gpeer == MPI_UNDEFINED){ return NULL; } else { uint64_t offset = (uint64_t)local_p - (uint64_t)ShmCommBufs[ShmRank]; uint64_t remote = (uint64_t)ShmCommBufs[gpeer]+offset; return (void *) remote; } } void CartesianCommunicator::Init(int *argc, char ***argv) { int flag; MPI_Initialized(&flag); // needed to coexist with other libs apparently if ( !flag ) { MPI_Init(argc,argv); } MPI_Comm_dup (MPI_COMM_WORLD,&communicator_world); MPI_Comm_rank(communicator_world,&WorldRank); MPI_Comm_size(communicator_world,&WorldSize); ///////////////////////////////////////////////////////////////////// // Split into groups that can share memory ///////////////////////////////////////////////////////////////////// MPI_Comm_split_type(communicator_world, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL,&ShmComm); MPI_Comm_rank(ShmComm ,&ShmRank); MPI_Comm_size(ShmComm ,&ShmSize); GroupSize = WorldSize/ShmSize; ///////////////////////////////////////////////////////////////////// // find world ranks in our SHM group (i.e. which ranks are on our node) ///////////////////////////////////////////////////////////////////// MPI_Group WorldGroup, ShmGroup; MPI_Comm_group (communicator_world, &WorldGroup); MPI_Comm_group (ShmComm, &ShmGroup); std::vector world_ranks(WorldSize); GroupRanks.resize(WorldSize); MyGroup.resize(ShmSize); for(int r=0;r()); int myleader = MyGroup[0]; std::vector leaders_1hot(WorldSize,0); std::vector leaders_group(GroupSize,0); leaders_1hot [ myleader ] = 1; /////////////////////////////////////////////////////////////////// // global sum leaders over comm world /////////////////////////////////////////////////////////////////// int ierr=MPI_Allreduce(MPI_IN_PLACE,&leaders_1hot[0],WorldSize,MPI_INT,MPI_SUM,communicator_world); assert(ierr==0); /////////////////////////////////////////////////////////////////// // find the group leaders world rank /////////////////////////////////////////////////////////////////// int group=0; for(int l=0;l coor = _processor_coor; assert(std::abs(shift) <_processors[dim]); coor[dim] = (_processor_coor[dim] + shift + _processors[dim])%_processors[dim]; Lexicographic::IndexFromCoor(coor,source,_processors); source = LexicographicToWorldRank[source]; coor[dim] = (_processor_coor[dim] - shift + _processors[dim])%_processors[dim]; Lexicographic::IndexFromCoor(coor,dest,_processors); dest = LexicographicToWorldRank[dest]; } int CartesianCommunicator::RankFromProcessorCoor(std::vector &coor) { int rank; Lexicographic::IndexFromCoor(coor,rank,_processors); rank = LexicographicToWorldRank[rank]; return rank; } void CartesianCommunicator::ProcessorCoorFromRank(int rank, std::vector &coor) { Lexicographic::CoorFromIndex(coor,rank,_processors); rank = LexicographicToWorldRank[rank]; } CartesianCommunicator::CartesianCommunicator(const std::vector &processors) { int ierr; communicator=communicator_world; _ndimension = processors.size(); //////////////////////////////////////////////////////////////// // Assert power of two shm_size. //////////////////////////////////////////////////////////////// int log2size = -1; for(int i=0;i<=MAXLOG2RANKSPERNODE;i++){ if ( (0x1< WorldDims = processors; ShmDims.resize(_ndimension,1); GroupDims.resize(_ndimension); ShmCoor.resize(_ndimension); GroupCoor.resize(_ndimension); WorldCoor.resize(_ndimension); for(int l2=0;l2 reqs(0); SendToRecvFromBegin(reqs,xmit,dest,recv,from,bytes); SendToRecvFromComplete(reqs); } void CartesianCommunicator::SendRecvPacket(void *xmit, void *recv, int sender, int receiver, int bytes) { MPI_Status stat; assert(sender != receiver); int tag = sender; if ( _processor == sender ) { MPI_Send(xmit, bytes, MPI_CHAR,receiver,tag,communicator); } if ( _processor == receiver ) { MPI_Recv(recv, bytes, MPI_CHAR,sender,tag,communicator,&stat); } } // Basic Halo comms primitive void CartesianCommunicator::SendToRecvFromBegin(std::vector &list, void *xmit, int dest, void *recv, int from, int bytes) { #if 1 MPI_Request xrq; MPI_Request rrq; static int sequence; int ierr; int tag; int check; assert(dest != _processor); assert(from != _processor); int gdest = GroupRanks[dest]; int gfrom = GroupRanks[from]; int gme = GroupRanks[_processor]; sequence++; char *from_ptr = (char *)ShmCommBufs[ShmRank]; int small = (bytes "<< gdest<<" " < &list, void *xmit, int dest, void *recv, int from, int bytes) { MPI_Request xrq; MPI_Request rrq; int ierr; assert(dest != _processor); assert(from != _processor); int gdest = GroupRanks[dest]; int gfrom = GroupRanks[from]; int gme = GroupRanks[_processor]; assert(gme == ShmRank); if ( gdest == MPI_UNDEFINED ) { ierr =MPI_Isend(xmit, bytes, MPI_CHAR,dest,_processor,communicator,&xrq); assert(ierr==0); list.push_back(xrq); } if ( gfrom ==MPI_UNDEFINED) { ierr=MPI_Irecv(recv, bytes, MPI_CHAR,from,from,communicator,&rrq); assert(ierr==0); list.push_back(rrq); } StencilBarrier(); } void CartesianCommunicator::StencilSendToRecvFromComplete(std::vector &list) { SendToRecvFromComplete(list); } void CartesianCommunicator::StencilBarrier(void) { MPI_Win_sync (ShmWindow); MPI_Barrier (ShmComm); MPI_Win_sync (ShmWindow); } void CartesianCommunicator::SendToRecvFromComplete(std::vector &list) { int nreq=list.size(); std::vector status(nreq); int ierr = MPI_Waitall(nreq,&list[0],&status[0]); assert(ierr==0); } void CartesianCommunicator::Barrier(void) { int ierr = MPI_Barrier(communicator); assert(ierr==0); } void CartesianCommunicator::Broadcast(int root,void* data, int bytes) { int ierr=MPI_Bcast(data, bytes, MPI_BYTE, root, communicator); assert(ierr==0); } void CartesianCommunicator::BroadcastWorld(int root,void* data, int bytes) { int ierr= MPI_Bcast(data, bytes, MPI_BYTE, root, communicator_world); assert(ierr==0); } }