From 01858754edfecc4b460a886393ad2b2249d09a53 Mon Sep 17 00:00:00 2001 From: Peter Boyle Date: Sun, 23 Aug 2026 12:14:23 -0400 Subject: [PATCH] Unhappy test looking for work aroudn to avoid allgather --- tests/debug/Test_allgather.cc | 59 +++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/tests/debug/Test_allgather.cc b/tests/debug/Test_allgather.cc index de8a314d3..623fdd2c2 100644 --- a/tests/debug/Test_allgather.cc +++ b/tests/debug/Test_allgather.cc @@ -208,8 +208,15 @@ int main(int argc, char **argv) // 18.7 MB gathered). Depth 0 is AG_NPART=144 AG_WORDS=232800. const int64_t AGW = getenv("AG_WORDS") ? atol(getenv("AG_WORDS")) : 4096; const int AGN = getenv("AG_NPART") ? atoi(getenv("AG_NPART")) : (P+1)/2; + // Stage skips. T6 is the pathological one: at 288 ranks with 9 contributors + // it takes ~26 minutes and aborts on at least one rank, which would prevent + // T7 from ever running. T7 is therefore ordered FIRST, and AG_T6=0 skips + // the slow stage entirely when only the Bcast answer is wanted. + const int doT5 = getenv("AG_T5") ? atoi(getenv("AG_T5")) : 1; + const int doT6 = getenv("AG_T6") ? atoi(getenv("AG_T6")) : 1; + const int doT7 = getenv("AG_T7") ? atoi(getenv("AG_T7")) : 1; - { + if ( doT5 ) { const int64_t W = AGW; // words per contributing rank std::vector counts(P,0), displs(P,0); int64_t total=0; @@ -233,7 +240,42 @@ int main(int argc, char **argv) std::to_string(total*16/1048576)+" MB gathered", ok); } - { + //////////////////////////////////////////////////////////////////////// + // T7 : the SAME shape as T6, but assembled by C sequential MPI_Bcast -- + // one broadcast per contributing rank -- instead of one MPI_Allgatherv. + // + // This is the transport of DENSE_GATHER=2. Bcast takes no count vector, + // so the zero-count asymmetry that makes T6 run at ~0.18 MB/s and trip + // mpir_request.h:508 cannot arise. It costs C collectives rather than 1 + // and the roots do not transmit concurrently, so the byte cost is about + // 2x that of an ideal allgather; it is worth having only if Bcast is + // faster PER BYTE than the alternatives. Compare the T6 and T7 times. + //////////////////////////////////////////////////////////////////////// + if ( doT7 ) { + const int64_t W = AGW; + int nroot = AGN < 1 ? 1 : (AGN > P ? P : AGN); + int64_t total = (int64_t)nroot*W; + + deviceVector dall(total>0?total:1); + std::vector hall(total), hmine(W); + for(int64_t i=0;iBroadcast(r,(void *)&dall[(int64_t)r*W],(uint64_t)W*sizeof(ComplexD)); + + acceleratorCopyFromDevice(&dall[0],&hall[0],total*sizeof(ComplexD)); + bool ok=true; + for(int r=0;r P ? P : AGN); @@ -262,6 +304,19 @@ int main(int argc, char **argv) std::to_string(total*16/1048576)+" MB gathered", ok); } + // Reduce across ranks before reporting. Report() prints from rank 0 only + // and `failures` is rank-local, so a stage that passes on rank 0 and fails + // (or aborts) elsewhere would otherwise be announced as ALL PASS -- which + // is exactly what happened at 288 ranks with 9 contributors. + { + uint64_t f = failures; + grid->GlobalSum(f); + if ( f && !failures ) + std::cout << GridLogMessage << " ** failures on OTHER ranks: " << f + << " (this rank saw none) **" << std::endl; + failures = (int)f; + } + std::cout << GridLogMessage << (failures ? "AllGather regression: FAILURES" : "AllGather regression: ALL PASS") << std::endl;