/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./benchmarks/Benchmark_comms.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 using namespace std; using namespace Grid; struct time_statistics{ double mean; double err; double min; double max; void statistics(std::vector v){ double sum = std::accumulate(v.begin(), v.end(), 0.0); mean = sum / v.size(); std::vector diff(v.size()); std::transform(v.begin(), v.end(), diff.begin(), [=](double x) { return x - mean; }); double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); err = std::sqrt(sq_sum / (v.size()*(v.size() - 1))); auto result = std::minmax_element(v.begin(), v.end()); min = *result.first; max = *result.second; } }; void header(){ std::cout <1) nmu++; std::cout << GridLogMessage << "Number of iterations to average: "<< Nloop << std::endl; std::vector t_time(Nloop); // time_statistics timestat; std::cout< > xbuf(8); std::vector > rbuf(8); for(int mu=0;mu<8;mu++){ xbuf[mu].resize(lat*lat*lat*Ls); rbuf[mu].resize(lat*lat*lat*Ls); } uint64_t bytes=lat*lat*lat*Ls*sizeof(HalfSpinColourVectorD); int ncomm; for(int mu=0;mu<4;mu++){ if (mpi_layout[mu]>1 ) { double start=usecond(); for(int i=0;i requests; Grid.ShiftedRanks(mu,comm_proc,xmit_to_rank,recv_from_rank); Grid.SendToRecvFrom((void *)&xbuf[mu][0], xmit_to_rank, (void *)&rbuf[mu][0], recv_from_rank, bytes); } comm_proc = mpi_layout[mu]-1; { std::vector requests; Grid.ShiftedRanks(mu,comm_proc,xmit_to_rank,recv_from_rank); Grid.SendToRecvFrom((void *)&xbuf[mu+4][0], xmit_to_rank, (void *)&rbuf[mu+4][0], recv_from_rank, bytes); } } Grid.Barrier(); double stop=usecond(); double mean=(stop-start)/Nloop; double dbytes = bytes*ppn; double xbytes = dbytes*2.0*ncomm; double rbytes = xbytes; double bidibytes = xbytes+rbytes; std::cout< xbuf(8); std::vector rbuf(8); uint64_t bytes = lat*lat*lat*Ls*sizeof(HalfSpinColourVectorD); for(int d=0;d<8;d++){ xbuf[d] = (HalfSpinColourVectorD *)acceleratorAllocDevice(bytes); rbuf[d] = (HalfSpinColourVectorD *)acceleratorAllocDevice(bytes); } int ncomm; for(int mu=0;mu<4;mu++){ if (mpi_layout[mu]>1 ) { double start=usecond(); for(int i=0;i requests; Grid.ShiftedRanks(mu,comm_proc,xmit_to_rank,recv_from_rank); Grid.SendToRecvFrom((void *)&xbuf[mu][0], xmit_to_rank, (void *)&rbuf[mu][0], recv_from_rank, bytes); } comm_proc = mpi_layout[mu]-1; { std::vector requests; Grid.ShiftedRanks(mu,comm_proc,xmit_to_rank,recv_from_rank); Grid.SendToRecvFrom((void *)&xbuf[mu+4][0], xmit_to_rank, (void *)&rbuf[mu+4][0], recv_from_rank, bytes); } } Grid.Barrier(); double stop=usecond(); double mean=(stop-start)/Nloop; double dbytes = bytes*ppn; double xbytes = dbytes*2.0*ncomm; double rbytes = xbytes; double bidibytes = xbytes+rbytes; std::cout< PollDtoH -> CopySynchronise -> Begin -> PollIRecv -> Complete // // verbatim as CartesianStencil::CommunicateBegin/Complete drive it, so this // measures the code that actually runs inside the Dslash rather than a // simplified stand-in built on SendToRecvFrom. // // THREE byte counts are reported, because they differ and conflating them // has already produced an impossible number (272 GB/s/node against a // 200 GB/s wire): // // offered : the whole halo this rank presents, all 8 directions. // off-node : the subset whose partner is on another node, classified // GEOMETRICALLY via IsOffNode() -- independent of --shm-mpi. // to-MPI : what StencilSendToRecvFrom{Prepare,Begin} actually handed to // MPI, i.e. their return value, exactly as the Stencil counts // it. Under --shm-mpi 1 Grid delegates intranode transfers to // MPI as well, so this approaches "offered"; under --shm-mpi 0 // Grid moves them itself and this approaches "off-node". // // Only the off-node column may be compared against wire speed. ///////////////////////////////////////////////////////////////////////////// std::cout< xbuf(8), rbuf(8); for(int d=0;d<8;d++){ xbuf[d] = (HalfSpinColourVectorD *)acceleratorAllocDevice(bytes); rbuf[d] = (HalfSpinColourVectorD *)acceleratorAllocDevice(bytes); } // Packet table in the same shape the Stencil builds: 8 directions, // to/from ranks from ShiftedRanks, participation gated on mpi_layout. // COMPACT packet list, exactly as the Stencil builds it: only the // directions that actually communicate get a packet. Passing a // self-send with do_send=0 is not equivalent -- the assert // "dest != _processor" in StencilSendToRecvFromBegin is unconditional. std::vector to_rank, from_rank, buf_id; double offered = 0.0, offnode = 0.0; for(int mu=0;mu<4;mu++){ if ( mpi_layout[mu] > 1 ) { int s,d; Grid.ShiftedRanks(mu,+1,s,d); to_rank.push_back(d); from_rank.push_back(s); buf_id.push_back(mu); Grid.ShiftedRanks(mu,-1,s,d); to_rank.push_back(d); from_rank.push_back(s); buf_id.push_back(mu+4); } } int npkt = to_rank.size(); for(int i=0;i reqs; for(int n=0;n