From d2dfd115bef09ababd012f07b1df169f9e4e61dc Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Mon, 24 Feb 2025 09:06:21 +0100 Subject: [PATCH] ENH: provide isolated "*_algorithm" versions of Pstream gather routines - enables better selection of linear vs tree and improves future reuse. ENH: optimize listReduce/listCombineReduce for single-value lists --- src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H | 106 ++++++++---- .../db/IOstreams/Pstreams/PstreamGather.txx | 163 +++++++++++++++--- .../IOstreams/Pstreams/PstreamGatherList.txx | 37 ++-- 3 files changed, 231 insertions(+), 75 deletions(-) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H index a43808ed46..0e26a4a399 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H @@ -126,6 +126,19 @@ public: // Gather/scatter : single value + //- Implementation: gather (reduce) single element data onto + //- UPstream::masterNo() + template + static void gather_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + //! [in,out] + T& value, + const BinaryOp& bop, + const int tag, + const int communicator + ); + //- Gather (reduce) data, applying \c bop to combine \c value //- from different processors. The basis for Foam::reduce(). // A no-op for non-parallel. @@ -214,6 +227,19 @@ public: // Gather/combine variants working on entire List + //- Implementation: gather (reduce) list element data onto + //- UPstream::masterNo() + template + static void listGather_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + //! [in,out] + UList& values, + const BinaryOp& bop, + const int tag, + const int communicator + ); + //- Gather (reduce) list elements, //- applying \c bop to each list element // @@ -240,27 +266,27 @@ public: const label comm = UPstream::worldComm ); - //- Gather (reduce) list elements, - //- applying \c bop to combine each list element. + //- Reduce list elements (list must be equal size on all ranks), + //- applying \c bop to each list element. // // \tparam InplaceMode indicates that the binary operator // modifies values in-place, not using assignment template - static void listGatherReduce + static void listReduce ( //! [in,out] the result is consistent on all ranks - List& values, + UList& values, const BinaryOp& bop, const int tag = UPstream::msgType(), const label comm = UPstream::worldComm ); - //- Forwards to Pstream::listGatherReduce with an \em in-place \c cop + //- Forwards to Pstream::listReduce with an \em in-place \c cop template static void listCombineReduce ( //! [in,out] the result is consistent on all ranks - List& values, + UList& values, const CombineOp& cop, const int tag = UPstream::msgType(), const label comm = UPstream::worldComm @@ -271,7 +297,7 @@ public: static void listCombineAllGather ( //! [in,out] the result is consistent on all ranks - List& values, + UList& values, const CombineOp& cop, const int tag = UPstream::msgType(), const label comm = UPstream::worldComm @@ -283,6 +309,18 @@ public: // Gather/combine variants working on Map/HashTable containers + //- Implementation: gather (reduce) Map/HashTable containers onto + //- UPstream::masterNo() + template + static void mapGather_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + Container& values, + const BinaryOp& bop, + const int tag, + const int communicator + ); + //- Gather (reduce) Map/HashTable containers, //- applying \c bop to combine entries from different processors. // @@ -316,7 +354,7 @@ public: // // Wraps mapCombineGather/broadcast (may change in the future). template - static void mapGatherReduce + static void mapReduce ( //! [in,out] the result is consistent on all ranks Container& values, @@ -325,7 +363,7 @@ public: const label comm = UPstream::worldComm ); - //- Forwards to Pstream::mapGatherReduce with an \em in-place \c cop + //- Forwards to Pstream::mapReduce with an \em in-place \c cop template static void mapCombineReduce ( @@ -351,37 +389,33 @@ public: } -private: - - // Private implementations - - //- Gather data, but keep individual values separate. - template - static void gatherList_tree_algorithm - ( - //! [in,out] - UList& values, - const int tag, - const label communicator - ); - - //- Inverse of gatherList_tree_algorithm - template - static void scatterList_tree_algorithm - ( - //! [in,out] - UList& values, - const int tag, - const label communicator - ); - - -public: - // Gather/scatter keeping the individual processor data separate. // The values is a List of size UPstream::nProcs() where // values[UPstream::myProcNo()] is the data for the current processor. + //- Implementation: gather data, keeping individual values separate. + //- Output is only valid (consistent) on UPstream::masterNo() + template + static void gatherList_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + //! [in,out] + UList& values, + const int tag, + const int communicator + ); + + //- Implementation: inverse of gatherList_algorithm + template + static void scatterList_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + //! [in,out] + UList& values, + const int tag, + const int communicator + ); + //- Gather data, but keep individual values separate. template static void gatherList diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx index 154aee8fb9..8aa66bb795 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx @@ -49,12 +49,13 @@ Note // Single value variants template -void Foam::Pstream::gather +void Foam::Pstream::gather_algorithm ( + const UPstream::commsStructList& comms, // Communication order T& value, const BinaryOp& bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -64,12 +65,12 @@ void Foam::Pstream::gather } else { - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? - const auto& myComm = comms[UPstream::myProcNo(communicator)]; + const label myProci = UPstream::myProcNo(communicator); + const auto& myComm = comms[myProci]; const auto& below = myComm.below(); + // Receive from my downstairs neighbours for (const auto proci : below) { @@ -146,6 +147,37 @@ void Foam::Pstream::gather } +template +void Foam::Pstream::gather +( + T& value, + const BinaryOp& bop, + const int tag, + const label communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::gather_algorithm + ( + commOrder, + value, + bop, + tag, + communicator + ); + } +} + + template void Foam::Pstream::combineGather ( @@ -183,12 +215,13 @@ void Foam::Pstream::combineReduce // List variants template -void Foam::Pstream::listGather +void Foam::Pstream::listGather_algorithm ( + const UPstream::commsStructList& comms, // Communication order UList& values, const BinaryOp& bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator) || values.empty()) @@ -198,10 +231,9 @@ void Foam::Pstream::listGather } else { - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? - const auto& myComm = comms[UPstream::myProcNo(communicator)]; + const label myProci = UPstream::myProcNo(communicator); + const auto& myComm = comms[myProci]; const auto& below = myComm.below(); // Same length on all ranks @@ -295,17 +327,70 @@ void Foam::Pstream::listGather template -void Foam::Pstream::listGatherReduce +void Foam::Pstream::listGather ( - List& values, + UList& values, + const BinaryOp& bop, + const int tag, + const label communicator +) +{ + if (!UPstream::is_parallel(communicator) || values.empty()) + { + // Nothing to do + return; + } + else if (values.size() == 1) + { + // Single value - optimized version + Pstream::gather + ( + values[0], + bop, + tag, + communicator + ); + } + else + { + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::listGather_algorithm + ( + commOrder, + values, + bop, + tag, + communicator + ); + } +} + + +template +void Foam::Pstream::listReduce +( + UList& values, const BinaryOp& bop, const int tag, const label comm ) { - Pstream::listGather(values, bop, tag, comm); - if (!values.empty()) + if (!UPstream::is_parallel(comm) || values.empty()) { + // Nothing to do + } + else if (values.size() == 1) + { + // Single value - optimized version + Pstream::gather(values[0], bop, tag, comm); + Pstream::broadcast(values[0], comm); + } + else + { + // Multiple values + Pstream::listGather(values, bop, tag, comm); Pstream::broadcast(values, comm); } } @@ -328,14 +413,14 @@ void Foam::Pstream::listCombineGather template void Foam::Pstream::listCombineReduce ( - List& values, + UList& values, const CombineOp& cop, const int tag, const label comm ) { // In-place binary operation - Pstream::listGatherReduce(values, cop, tag, comm); + Pstream::listReduce(values, cop, tag, comm); } @@ -344,12 +429,13 @@ void Foam::Pstream::listCombineReduce // Map variants template -void Foam::Pstream::mapGather +void Foam::Pstream::mapGather_algorithm ( + const UPstream::commsStructList& comms, // Communication order Container& values, const BinaryOp& bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -359,12 +445,12 @@ void Foam::Pstream::mapGather } else { - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? - const auto& myComm = comms[UPstream::myProcNo(communicator)]; + const label myProci = UPstream::myProcNo(communicator); + const auto& myComm = comms[myProci]; const auto& below = myComm.below(); + // Receive from my downstairs neighbours for (const auto proci : below) { @@ -430,7 +516,38 @@ void Foam::Pstream::mapGather template -void Foam::Pstream::mapGatherReduce +void Foam::Pstream::mapGather +( + Container& values, + const BinaryOp& bop, + const int tag, + const label communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::mapGather_algorithm + ( + commOrder, + values, + bop, + tag, + communicator + ); + } +} + + +template +void Foam::Pstream::mapReduce ( Container& values, const BinaryOp& bop, @@ -473,7 +590,7 @@ void Foam::Pstream::mapCombineReduce ) { // In-place binary operation - Pstream::mapGatherReduce + Pstream::mapReduce ( values, cop, tag, comm ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx index 082e168800..a77c13bda6 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx @@ -43,11 +43,12 @@ Description // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template -void Foam::Pstream::gatherList_tree_algorithm +void Foam::Pstream::gatherList_algorithm ( + const UPstream::commsStructList& comms, // Communication order UList& values, const int tag, - const label communicator + const int communicator ) { if (FOAM_UNLIKELY(!UPstream::is_parallel(communicator))) @@ -65,11 +66,8 @@ void Foam::Pstream::gatherList_tree_algorithm << Foam::abort(FatalError); } - const label myProci = UPstream::myProcNo(communicator); - - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? + const label myProci = UPstream::myProcNo(communicator); const auto& myComm = comms[myProci]; @@ -253,11 +251,12 @@ void Foam::Pstream::gatherList_tree_algorithm template -void Foam::Pstream::scatterList_tree_algorithm +void Foam::Pstream::scatterList_algorithm ( + const UPstream::commsStructList& comms, // Communication order UList& values, const int tag, - const label communicator + const int communicator ) { if (FOAM_UNLIKELY(!UPstream::is_parallel(communicator))) @@ -279,11 +278,8 @@ void Foam::Pstream::scatterList_tree_algorithm << Foam::abort(FatalError); } - const label myProci = UPstream::myProcNo(communicator); - - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? + const label myProci = UPstream::myProcNo(communicator); const auto& myComm = comms[myProci]; @@ -448,7 +444,10 @@ void Foam::Pstream::gatherList } else { - Pstream::gatherList_tree_algorithm(values, tag, communicator); + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::gatherList_algorithm(commOrder, values, tag, communicator); } } @@ -479,7 +478,10 @@ void Foam::Pstream::scatterList } else { - Pstream::scatterList_tree_algorithm(values, tag, communicator); + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::scatterList_algorithm(commOrder, values, tag, communicator); } } @@ -511,8 +513,11 @@ void Foam::Pstream::allGatherList } else { - Pstream::gatherList(values, tag, comm); - Pstream::scatterList(values, tag, comm); + // Communication order + const auto& commOrder = UPstream::whichCommunication(comm); + + Pstream::gatherList_algorithm(commOrder, values, tag, comm); + Pstream::scatterList_algorithm(commOrder, values, tag, comm); } }