From 2e0c19c9153e94d2474ead2ab0ac2069729b99a1 Mon Sep 17 00:00:00 2001 From: Peter Boyle Date: Fri, 21 Aug 2026 21:25:18 -0400 Subject: [PATCH] Allgather test --- tests/debug/Test_allgather.cc | 259 ++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 tests/debug/Test_allgather.cc diff --git a/tests/debug/Test_allgather.cc b/tests/debug/Test_allgather.cc new file mode 100644 index 000000000..7d5d6d0d0 --- /dev/null +++ b/tests/debug/Test_allgather.cc @@ -0,0 +1,259 @@ +/************************************************************************************* + Grid physics library, www.github.com/paboyle/Grid + + Source file: ./tests/debug/Test_allgather.cc + + Copyright (C) 2026 + +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. + + See the full license in the file "LICENSE" in the top level distribution + directory +*************************************************************************************/ +/* END LEGAL */ + +////////////////////////////////////////////////////////////////////////////// +// Regression gate for CartesianCommunicator::AllGather / AllGatherV. +// +// CPU build under mpirun: +// mpirun -n 1 ./Test_allgather --grid 8.8.8.8 --mpi 1.1.1.1 +// mpirun -n 2 ./Test_allgather --grid 8.8.8.8 --mpi 1.1.1.2 +// mpirun -n 3 ./Test_allgather --grid 8.8.8.12 --mpi 1.1.1.3 +// mpirun -n 4 ./Test_allgather --grid 8.8.8.8 --mpi 1.1.1.4 +// +// T1 : uniform AllGather, rank-ordered concatenation. +// T2 : AllGatherV with non-uniform counts and displacements. +// T3 : bitwise equivalence with the zero-fill + GlobalSumVector idiom +// that AllGatherV is intended to replace. +// T4 : the same equivalence for the GatherGemm panel layout -- a +// column-major kchunk x n panel whose rows are owned in contiguous +// rank-major ranges, requiring a pack on send and a repack on receive. +// +// T3 and T4 are the ones that matter: they certify AllGatherV as a drop-in +// for the existing idiom, bit for bit, before it is used anywhere. +////////////////////////////////////////////////////////////////////////////// + +#include + +using namespace Grid; + +static int failures = 0; + +static void Report(const std::string &name, bool pass, const std::string &detail="") +{ + std::cout << GridLogMessage << " " << name << (pass ? " PASS" : " ** FAIL **"); + if ( detail.size() ) std::cout << " " << detail; + std::cout << std::endl; + if ( !pass ) failures++; +} + +// A value that is unique to (rank, index) so that any misplacement shows up. +static ComplexD Stamp(int rank, int64_t idx) +{ + return ComplexD( 1000.0*(rank+1) + (double)idx, -(double)(rank+1) ); +} + +int main(int argc, char **argv) +{ + Grid_init(&argc, &argv); + + GridCartesian *grid = SpaceTimeGrid::makeFourDimGrid(GridDefaultLatt(), + GridDefaultSimd(Nd, vComplexD::Nsimd()), + GridDefaultMpi()); + const int P = grid->ProcessorCount(); + const int me = grid->ThisRank(); + + std::cout << GridLogMessage << "AllGather regression: " << P << " ranks" << std::endl; + + //////////////////////////////////////////////////////////////////////// + // T1 : uniform AllGather + //////////////////////////////////////////////////////////////////////// + { + const int64_t W = 37; // words per rank + std::vector mine(W), all((uint64_t)W*P); + for(int64_t i=0;iAllGather((void *)&mine[0], (void *)&all[0], (uint64_t)W, sizeof(ComplexD)); + + bool ok = true; + for(int r=0;r counts(P), displs(P); + int64_t total = 0; + for(int r=0;r mine(counts[me]), all(total); + for(int64_t i=0;iAllGatherV((void *)&mine[0], counts[me], + (void *)&all[0], counts, displs, sizeof(ComplexD)); + + bool ok = true; + for(int r=0;r counts(P), displs(P); + int64_t total = 0; + for(int r=0;r mine(counts[me]); + for(int64_t i=0;i viaSum(total, ComplexD(0.0,0.0)); + for(int64_t i=0;iGlobalSumVector(&viaSum[0], (int)total); + + // (b) the primitive + std::vector viaGather(total); + grid->AllGatherV((void *)&mine[0], counts[me], + (void *)&viaGather[0], counts, displs, sizeof(ComplexD)); + + bool ok = true; + for(int64_t i=0;i rowStart(P+1); + rowStart[0]=0; + for(int r=0;r mine((uint64_t)myRows*n); + for(int64_t j=0;j viaSum((uint64_t)kchunk*n, ComplexD(0.0,0.0)); + for(int64_t j=0;jGlobalSumVector(&viaSum[0], (int)(kchunk*n)); + + // (b) AllGatherV into rank-major order, then repack into the panel + std::vector counts(P), displs(P); + int64_t tot=0; + for(int r=0;r rankMajor(tot); + grid->AllGatherV((void *)&mine[0], counts[me], + (void *)&rankMajor[0], counts, displs, sizeof(ComplexD)); + + std::vector viaGather((uint64_t)kchunk*n); + for(int r=0;r counts(P,0), displs(P,0); + int64_t total=0; + for(int r=0;r dmine(W), dall(total); + std::vector hmine(W), hall(total); + for(int64_t i=0;iAllGatherV((void *)&dmine[0], counts[me], + (void *)&dall[0], counts, displs, sizeof(ComplexD)); + + acceleratorCopyFromDevice(&dall[0],&hall[0],total*sizeof(ComplexD)); + bool ok=true; + for(int r=0;r counts(P,0), displs(P,0); + int64_t total=0; + for(int r=0;r dmine(W>0?W:1), dall(total>0?total:1); + std::vector hmine(W), hall(total); + for(int64_t i=0;iAllGatherV((void *)&dmine[0], counts[me], + (void *)&dall[0], counts, displs, sizeof(ComplexD)); + + acceleratorCopyFromDevice(&dall[0],&hall[0],total*sizeof(ComplexD)); + bool ok=true; + for(int r=0;r