mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: extend mpiAllGather to include integer and float types
- was previously limited to 'char' whereas gatherv/scatterv already supported various integer and float types STYLE: rebundle allToAll declarations with macros ENH: provide a version of allToAllConsensus returning the Map - simplifies use and avoids ambiguities in the send/recv parameters - the Map version will now also transmit zero value data if they exist in the Map. Unlike the List version, zero values are not necessary to signal connectivity with a Map. COMP: forwarding template parameters for NBX routines ENH: consolidate PstreamBuffers size exchange options - had a variety of nearly identical backends for all-to-all, gather/scatter. Now combined internally with a dispatch enumeration which provides better control over which size exchange algorithm is used. DEFEATURE: remove experimental full-NBX PstreamBuffers variant - no advantages seen compared to the hybrid NBX/PEX approach. Removal reduces some code cruft. DEFEATURE: remove experimental "double non-blocking" NBX version - the idea was to avoid blocking receives for very large data transfers, but that is usually better accomplished with a hybrid NBX/PEX approach like PstreamBuffers allows
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
/*--------------------------------*- C++ -*----------------------------------*\
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
| ========= | |
|
| ========= | |
|
||||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||||
| \\ / O peration | Version: v2306 |
|
| \\ / O peration | Version: v2312 |
|
||||||
| \\ / A nd | Website: www.openfoam.com |
|
| \\ / A nd | Website: www.openfoam.com |
|
||||||
| \\/ M anipulation | |
|
| \\/ M anipulation | |
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
@ -174,12 +174,13 @@ OptimisationSwitches
|
|||||||
nbx.tuning 0;
|
nbx.tuning 0;
|
||||||
|
|
||||||
// Additional PstreamBuffers tuning parameters (experimental)
|
// Additional PstreamBuffers tuning parameters (experimental)
|
||||||
// -1 : PEX with all-to-all for buffer sizes and point-to-point
|
// 0 : (legacy PEX)
|
||||||
// for contents (legacy approach)
|
// * all-to-all for buffer sizes [legacy approach]
|
||||||
// 0 : hybrid PEX with NBX for buffer sizes and point-to-point
|
// * point-to-point for contents
|
||||||
// for contents (proposed new approach)
|
// 1 : (hybrid PEX)
|
||||||
// 1 : full NBX for buffer sizes and contents (very experimental)
|
// * NBX for buffer sizes [new approach]
|
||||||
pbufs.tuning -1;
|
// * point-to-point for contents
|
||||||
|
pbufs.tuning 0;
|
||||||
|
|
||||||
|
|
||||||
// =====
|
// =====
|
||||||
|
|||||||
@ -599,7 +599,7 @@ public:
|
|||||||
|
|
||||||
// Non-blocking exchange
|
// Non-blocking exchange
|
||||||
|
|
||||||
//- Exchange \em contiguous data using non-blocking consensus
|
//- Exchange \em contiguous data using non-blocking consensus (NBX)
|
||||||
//- Sends sendData, receives into recvData.
|
//- Sends sendData, receives into recvData.
|
||||||
//
|
//
|
||||||
// Each entry of the recvBufs list is cleared before receipt.
|
// Each entry of the recvBufs list is cleared before receipt.
|
||||||
@ -614,10 +614,10 @@ public:
|
|||||||
List<Container>& recvBufs,
|
List<Container>& recvBufs,
|
||||||
const int tag,
|
const int tag,
|
||||||
const label comm,
|
const label comm,
|
||||||
const bool wait = true //!< Wait for requests to complete
|
const bool wait = true //!< (ignored)
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Exchange \em contiguous data using non-blocking consensus
|
//- Exchange \em contiguous data using non-blocking consensus (NBX)
|
||||||
//- Sends sendData, receives into recvData.
|
//- Sends sendData, receives into recvData.
|
||||||
//
|
//
|
||||||
// Each \em entry of the recvBufs map is cleared before receipt,
|
// Each \em entry of the recvBufs map is cleared before receipt,
|
||||||
@ -636,7 +636,23 @@ public:
|
|||||||
Map<Container>& recvBufs,
|
Map<Container>& recvBufs,
|
||||||
const int tag,
|
const int tag,
|
||||||
const label comm,
|
const label comm,
|
||||||
const bool wait = true //!< Wait for requests to complete
|
const bool wait = true //!< (ignored)
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Exchange \em contiguous data using non-blocking consensus (NBX)
|
||||||
|
//- Sends sendData returns receive information.
|
||||||
|
//
|
||||||
|
// For \b non-parallel : copy own rank (if it exists and non-empty)
|
||||||
|
//
|
||||||
|
// \note The message tag should be chosen to be a unique value
|
||||||
|
// since the implementation uses probing with ANY_SOURCE !!
|
||||||
|
template<class Container, class Type>
|
||||||
|
static Map<Container> exchangeConsensus
|
||||||
|
(
|
||||||
|
const Map<Container>& sendBufs,
|
||||||
|
const int tag,
|
||||||
|
const label comm,
|
||||||
|
const bool wait = true //!< (ignored)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ License
|
|||||||
int Foam::PstreamBuffers::algorithm
|
int Foam::PstreamBuffers::algorithm
|
||||||
(
|
(
|
||||||
// Name may change in the future (JUN-2023)
|
// Name may change in the future (JUN-2023)
|
||||||
Foam::debug::optimisationSwitch("pbufs.tuning", -1)
|
Foam::debug::optimisationSwitch("pbufs.tuning", 0)
|
||||||
);
|
);
|
||||||
registerOptSwitch
|
registerOptSwitch
|
||||||
(
|
(
|
||||||
@ -46,20 +46,19 @@ registerOptSwitch
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Simple enumerations
|
|
||||||
// -------------------
|
|
||||||
static constexpr int algorithm_PEX_allToAll = -1; // Traditional PEX
|
|
||||||
//static constexpr int algorithm_PEX_hybrid = 0; // Possible new default?
|
|
||||||
static constexpr int algorithm_full_NBX = 1; // Very experimental
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
inline void Foam::PstreamBuffers::setFinished(bool on) noexcept
|
||||||
|
{
|
||||||
|
finishedSendsCalled_ = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void Foam::PstreamBuffers::initFinalExchange()
|
inline void Foam::PstreamBuffers::initFinalExchange()
|
||||||
{
|
{
|
||||||
// Could also check that it is not called twice
|
// Could also check that it is not called twice
|
||||||
// but that is used for overlapping send/recv (eg, overset)
|
// but that is used for overlapping send/recv (eg, overset)
|
||||||
finishedSendsCalled_ = true;
|
setFinished(true);
|
||||||
|
|
||||||
clearUnregistered();
|
clearUnregistered();
|
||||||
}
|
}
|
||||||
@ -67,56 +66,121 @@ inline void Foam::PstreamBuffers::initFinalExchange()
|
|||||||
|
|
||||||
void Foam::PstreamBuffers::finalExchange
|
void Foam::PstreamBuffers::finalExchange
|
||||||
(
|
(
|
||||||
|
enum modeOption mode,
|
||||||
const bool wait,
|
const bool wait,
|
||||||
labelList& recvSizes
|
labelList& recvSizes
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
initFinalExchange();
|
initFinalExchange();
|
||||||
|
|
||||||
if (commsType_ == UPstream::commsTypes::nonBlocking)
|
// Pre-flight checks
|
||||||
|
switch (mode)
|
||||||
{
|
{
|
||||||
if
|
case modeOption::DEFAULT :
|
||||||
(
|
|
||||||
wait
|
|
||||||
&& (algorithm >= algorithm_full_NBX)
|
|
||||||
&& (UPstream::maxCommsSize <= 0)
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
// NBX algorithm (nonblocking exchange)
|
// Choose (ALL_TO_ALL | NBX_PEX) from static settings
|
||||||
// - when requested and waiting, no data chunking etc
|
mode =
|
||||||
|
|
||||||
PstreamDetail::exchangeConsensus<DynamicList<char>, char>
|
|
||||||
(
|
(
|
||||||
sendBuffers_,
|
(algorithm <= 0)
|
||||||
recvBuffers_,
|
? modeOption::ALL_TO_ALL
|
||||||
recvSizes,
|
: modeOption::NBX_PEX
|
||||||
(tag_ + 271828), // some unique tag?
|
|
||||||
comm_,
|
|
||||||
wait
|
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
case modeOption::GATHER :
|
||||||
|
{
|
||||||
|
// gather mode (all-to-one) : master [0] <- everyone
|
||||||
|
// - only send to master [0]
|
||||||
|
// note: master [0] is also allowed to 'send' to itself
|
||||||
|
|
||||||
|
for (label proci = 1; proci < sendBuffers_.size(); ++proci)
|
||||||
|
{
|
||||||
|
sendBuffers_[proci].clear();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case modeOption::SCATTER :
|
||||||
|
{
|
||||||
|
// scatter mode (one-to-all) : master [0] -> everyone
|
||||||
|
|
||||||
|
if (!UPstream::master(comm_))
|
||||||
|
{
|
||||||
|
// Non-master: has no sends
|
||||||
|
clearSends();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default :
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PEX algorithm with two different flavours of exchanging sizes
|
if (commsType_ == UPstream::commsTypes::nonBlocking)
|
||||||
|
{
|
||||||
|
// PEX algorithm with different flavours of exchanging sizes
|
||||||
|
// PEX stage 1: exchange sizes
|
||||||
|
|
||||||
|
labelList sendSizes; // Not used by gather/scatter
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case modeOption::GATHER :
|
||||||
|
{
|
||||||
|
// gather mode (all-to-one): master [0] <- everyone
|
||||||
|
// - presumed that MPI_Gather will be the most efficient
|
||||||
|
|
||||||
|
recvSizes =
|
||||||
|
UPstream::listGatherValues(sendBuffers_[0].size(), comm_);
|
||||||
|
|
||||||
|
if (!UPstream::master(comm_))
|
||||||
|
{
|
||||||
|
recvSizes.resize_nocopy(nProcs_);
|
||||||
|
recvSizes = Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case modeOption::SCATTER :
|
||||||
|
{
|
||||||
|
// scatter mode (one-to-all): master [0] -> everyone
|
||||||
|
// - presumed that MPI_Scatter will be the most efficient
|
||||||
|
|
||||||
|
recvSizes.resize_nocopy(nProcs_);
|
||||||
|
|
||||||
|
if (UPstream::master(comm_))
|
||||||
|
{
|
||||||
|
forAll(sendBuffers_, proci)
|
||||||
|
{
|
||||||
|
recvSizes[proci] = sendBuffers_[proci].size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const label myRecv
|
||||||
|
(
|
||||||
|
UPstream::listScatterValues(recvSizes, comm_)
|
||||||
|
);
|
||||||
|
|
||||||
|
recvSizes = Zero;
|
||||||
|
recvSizes[0] = myRecv;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case modeOption::NBX_PEX :
|
||||||
|
{
|
||||||
// Assemble the send sizes (cf. Pstream::exchangeSizes)
|
// Assemble the send sizes (cf. Pstream::exchangeSizes)
|
||||||
labelList sendSizes(nProcs_);
|
sendSizes.resize_nocopy(nProcs_);
|
||||||
forAll(sendBuffers_, proci)
|
forAll(sendBuffers_, proci)
|
||||||
{
|
{
|
||||||
sendSizes[proci] = sendBuffers_[proci].size();
|
sendSizes[proci] = sendBuffers_[proci].size();
|
||||||
}
|
}
|
||||||
recvSizes.resize_nocopy(nProcs_);
|
recvSizes.resize_nocopy(nProcs_);
|
||||||
|
|
||||||
if (algorithm == algorithm_PEX_allToAll)
|
// Exchange sizes (non-blocking consensus)
|
||||||
{
|
|
||||||
// PEX stage 1: exchange sizes (all-to-all)
|
|
||||||
UPstream::allToAll(sendSizes, recvSizes, comm_);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// PEX stage 1: exchange sizes (non-blocking consensus)
|
|
||||||
UPstream::allToAllConsensus
|
UPstream::allToAllConsensus
|
||||||
(
|
(
|
||||||
sendSizes,
|
sendSizes,
|
||||||
@ -124,8 +188,27 @@ void Foam::PstreamBuffers::finalExchange
|
|||||||
(tag_ + 314159), // some unique tag?
|
(tag_ + 314159), // some unique tag?
|
||||||
comm_
|
comm_
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case modeOption::DEFAULT :
|
||||||
|
case modeOption::ALL_TO_ALL :
|
||||||
|
{
|
||||||
|
// Assemble the send sizes (cf. Pstream::exchangeSizes)
|
||||||
|
sendSizes.resize_nocopy(nProcs_);
|
||||||
|
forAll(sendBuffers_, proci)
|
||||||
|
{
|
||||||
|
sendSizes[proci] = sendBuffers_[proci].size();
|
||||||
|
}
|
||||||
|
recvSizes.resize_nocopy(nProcs_);
|
||||||
|
|
||||||
|
// Exchange sizes (all-to-all)
|
||||||
|
UPstream::allToAll(sendSizes, recvSizes, comm_);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// PEX stage 2: point-to-point data exchange
|
// PEX stage 2: point-to-point data exchange
|
||||||
Pstream::exchange<DynamicList<char>, char>
|
Pstream::exchange<DynamicList<char>, char>
|
||||||
(
|
(
|
||||||
@ -166,7 +249,7 @@ void Foam::PstreamBuffers::finalExchange
|
|||||||
recvSizes[proci] = 1; // Connected
|
recvSizes[proci] = 1; // Connected
|
||||||
}
|
}
|
||||||
|
|
||||||
for (label proci=0; proci < nProcs_; ++proci)
|
for (label proci = 0; proci < nProcs_; ++proci)
|
||||||
{
|
{
|
||||||
if (!recvSizes[proci]) // Not connected
|
if (!recvSizes[proci]) // Not connected
|
||||||
{
|
{
|
||||||
@ -200,93 +283,6 @@ void Foam::PstreamBuffers::finalExchange
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::PstreamBuffers::finalGatherScatter
|
|
||||||
(
|
|
||||||
const bool isGather,
|
|
||||||
const bool wait,
|
|
||||||
labelList& recvSizes
|
|
||||||
)
|
|
||||||
{
|
|
||||||
initFinalExchange();
|
|
||||||
|
|
||||||
if (isGather)
|
|
||||||
{
|
|
||||||
// gather mode (all-to-one)
|
|
||||||
|
|
||||||
// Only send to master [0]. Master is also allowed to 'send' to itself
|
|
||||||
|
|
||||||
for (label proci=1; proci < sendBuffers_.size(); ++proci)
|
|
||||||
{
|
|
||||||
sendBuffers_[proci].clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// scatter mode (one-to-all)
|
|
||||||
|
|
||||||
if (!UPstream::master(comm_))
|
|
||||||
{
|
|
||||||
// Non-master: has no sends
|
|
||||||
clearSends();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (commsType_ == UPstream::commsTypes::nonBlocking)
|
|
||||||
{
|
|
||||||
// Use PEX algorithm
|
|
||||||
// - for a non-sparse gather/scatter, it is presumed that
|
|
||||||
// MPI_Gather/MPI_Scatter will be the most efficient way to
|
|
||||||
// communicate the sizes.
|
|
||||||
|
|
||||||
// PEX stage 1: exchange sizes (gather or scatter)
|
|
||||||
if (isGather)
|
|
||||||
{
|
|
||||||
// gather mode (all-to-one): master [0] <- everyone
|
|
||||||
|
|
||||||
recvSizes =
|
|
||||||
UPstream::listGatherValues(sendBuffers_[0].size(), comm_);
|
|
||||||
|
|
||||||
if (!UPstream::master(comm_))
|
|
||||||
{
|
|
||||||
recvSizes.resize_nocopy(nProcs_);
|
|
||||||
recvSizes = Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// scatter mode (one-to-all): master [0] -> everyone
|
|
||||||
|
|
||||||
recvSizes.resize_nocopy(nProcs_);
|
|
||||||
|
|
||||||
if (UPstream::master(comm_))
|
|
||||||
{
|
|
||||||
forAll(sendBuffers_, proci)
|
|
||||||
{
|
|
||||||
recvSizes[proci] = sendBuffers_[proci].size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const label myRecv(UPstream::listScatterValues(recvSizes, comm_));
|
|
||||||
|
|
||||||
recvSizes = Zero;
|
|
||||||
recvSizes[0] = myRecv;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PEX stage 2: point-to-point data exchange
|
|
||||||
Pstream::exchange<DynamicList<char>, char>
|
|
||||||
(
|
|
||||||
sendBuffers_,
|
|
||||||
recvSizes,
|
|
||||||
recvBuffers_,
|
|
||||||
tag_,
|
|
||||||
comm_,
|
|
||||||
wait
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::PstreamBuffers::PstreamBuffers
|
Foam::PstreamBuffers::PstreamBuffers
|
||||||
@ -382,7 +378,7 @@ void Foam::PstreamBuffers::clear()
|
|||||||
{
|
{
|
||||||
clearSends();
|
clearSends();
|
||||||
clearRecvs();
|
clearRecvs();
|
||||||
finishedSendsCalled_ = false;
|
setFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -431,13 +427,13 @@ void Foam::PstreamBuffers::clearStorage()
|
|||||||
}
|
}
|
||||||
recvPositions_ = Zero;
|
recvPositions_ = Zero;
|
||||||
|
|
||||||
finishedSendsCalled_ = false;
|
setFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::PstreamBuffers::initRegisterSend()
|
void Foam::PstreamBuffers::initRegisterSend()
|
||||||
{
|
{
|
||||||
if (!finishedSendsCalled_)
|
if (!finished())
|
||||||
{
|
{
|
||||||
for (label proci = 0; proci < nProcs_; ++proci)
|
for (label proci = 0; proci < nProcs_; ++proci)
|
||||||
{
|
{
|
||||||
@ -474,7 +470,7 @@ bool Foam::PstreamBuffers::hasSendData() const
|
|||||||
|
|
||||||
bool Foam::PstreamBuffers::hasRecvData() const
|
bool Foam::PstreamBuffers::hasRecvData() const
|
||||||
{
|
{
|
||||||
if (finishedSendsCalled_)
|
if (finished())
|
||||||
{
|
{
|
||||||
forAll(recvBuffers_, proci)
|
forAll(recvBuffers_, proci)
|
||||||
{
|
{
|
||||||
@ -504,7 +500,7 @@ Foam::label Foam::PstreamBuffers::sendDataCount(const label proci) const
|
|||||||
|
|
||||||
Foam::label Foam::PstreamBuffers::recvDataCount(const label proci) const
|
Foam::label Foam::PstreamBuffers::recvDataCount(const label proci) const
|
||||||
{
|
{
|
||||||
if (finishedSendsCalled_)
|
if (finished())
|
||||||
{
|
{
|
||||||
const label len(recvBuffers_[proci].size() - recvPositions_[proci]);
|
const label len(recvBuffers_[proci].size() - recvPositions_[proci]);
|
||||||
|
|
||||||
@ -529,7 +525,7 @@ Foam::labelList Foam::PstreamBuffers::recvDataCounts() const
|
|||||||
{
|
{
|
||||||
labelList counts(nProcs_, Zero);
|
labelList counts(nProcs_, Zero);
|
||||||
|
|
||||||
if (finishedSendsCalled_)
|
if (finished())
|
||||||
{
|
{
|
||||||
forAll(recvBuffers_, proci)
|
forAll(recvBuffers_, proci)
|
||||||
{
|
{
|
||||||
@ -560,7 +556,7 @@ Foam::label Foam::PstreamBuffers::maxNonLocalRecvCount
|
|||||||
{
|
{
|
||||||
label maxLen = 0;
|
label maxLen = 0;
|
||||||
|
|
||||||
if (finishedSendsCalled_)
|
if (finished())
|
||||||
{
|
{
|
||||||
forAll(recvBuffers_, proci)
|
forAll(recvBuffers_, proci)
|
||||||
{
|
{
|
||||||
@ -599,7 +595,7 @@ Foam::label Foam::PstreamBuffers::maxNonLocalRecvCount() const
|
|||||||
const Foam::UList<char>
|
const Foam::UList<char>
|
||||||
Foam::PstreamBuffers::peekRecvData(const label proci) const
|
Foam::PstreamBuffers::peekRecvData(const label proci) const
|
||||||
{
|
{
|
||||||
if (finishedSendsCalled_)
|
if (finished())
|
||||||
{
|
{
|
||||||
const label pos = recvPositions_[proci];
|
const label pos = recvPositions_[proci];
|
||||||
const label len = recvBuffers_[proci].size();
|
const label len = recvBuffers_[proci].size();
|
||||||
@ -625,18 +621,17 @@ Foam::PstreamBuffers::peekRecvData(const label proci) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Foam::PstreamBuffers::allowClearRecv(bool on) noexcept
|
|
||||||
{
|
|
||||||
bool old(allowClearRecv_);
|
|
||||||
allowClearRecv_ = on;
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Foam::PstreamBuffers::finishedSends(const bool wait)
|
void Foam::PstreamBuffers::finishedSends(const bool wait)
|
||||||
{
|
{
|
||||||
labelList recvSizes;
|
labelList recvSizes;
|
||||||
finalExchange(wait, recvSizes);
|
finalExchange(modeOption::DEFAULT, wait, recvSizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::PstreamBuffers::finishedSendsNBX(const bool wait)
|
||||||
|
{
|
||||||
|
labelList recvSizes;
|
||||||
|
finalExchange(modeOption::NBX_PEX, wait, recvSizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -649,7 +644,7 @@ void Foam::PstreamBuffers::finishedSends
|
|||||||
// Resize for copying back
|
// Resize for copying back
|
||||||
recvSizes.resize_nocopy(sendBuffers_.size());
|
recvSizes.resize_nocopy(sendBuffers_.size());
|
||||||
|
|
||||||
finalExchange(wait, recvSizes);
|
finalExchange(modeOption::DEFAULT, wait, recvSizes);
|
||||||
|
|
||||||
if (commsType_ != UPstream::commsTypes::nonBlocking)
|
if (commsType_ != UPstream::commsTypes::nonBlocking)
|
||||||
{
|
{
|
||||||
@ -717,8 +712,9 @@ bool Foam::PstreamBuffers::finishedSends
|
|||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
// Update send/recv topology
|
// Update send/recv topology
|
||||||
|
|
||||||
labelList recvSizes;
|
labelList recvSizes;
|
||||||
finishedSends(recvSizes, wait); // eg, using all-to-all
|
finishedSends(recvSizes, wait); // modeOption::DEFAULT (eg all-to-all)
|
||||||
|
|
||||||
// The send ranks
|
// The send ranks
|
||||||
sendProcs.clear();
|
sendProcs.clear();
|
||||||
@ -754,14 +750,14 @@ bool Foam::PstreamBuffers::finishedSends
|
|||||||
void Foam::PstreamBuffers::finishedGathers(const bool wait)
|
void Foam::PstreamBuffers::finishedGathers(const bool wait)
|
||||||
{
|
{
|
||||||
labelList recvSizes;
|
labelList recvSizes;
|
||||||
finalGatherScatter(true, wait, recvSizes);
|
finalExchange(modeOption::GATHER, wait, recvSizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::PstreamBuffers::finishedScatters(const bool wait)
|
void Foam::PstreamBuffers::finishedScatters(const bool wait)
|
||||||
{
|
{
|
||||||
labelList recvSizes;
|
labelList recvSizes;
|
||||||
finalGatherScatter(false, wait, recvSizes);
|
finalExchange(modeOption::SCATTER, wait, recvSizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -771,7 +767,7 @@ void Foam::PstreamBuffers::finishedGathers
|
|||||||
const bool wait
|
const bool wait
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
finalGatherScatter(true, wait, recvSizes);
|
finalExchange(modeOption::GATHER, wait, recvSizes);
|
||||||
|
|
||||||
if (commsType_ != UPstream::commsTypes::nonBlocking)
|
if (commsType_ != UPstream::commsTypes::nonBlocking)
|
||||||
{
|
{
|
||||||
@ -793,7 +789,7 @@ void Foam::PstreamBuffers::finishedScatters
|
|||||||
const bool wait
|
const bool wait
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
finalGatherScatter(false, wait, recvSizes);
|
finalExchange(modeOption::SCATTER, wait, recvSizes);
|
||||||
|
|
||||||
if (commsType_ != UPstream::commsTypes::nonBlocking)
|
if (commsType_ != UPstream::commsTypes::nonBlocking)
|
||||||
{
|
{
|
||||||
@ -809,4 +805,27 @@ void Foam::PstreamBuffers::finishedScatters
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
// Controls
|
||||||
|
|
||||||
|
bool Foam::PstreamBuffers::finished() const noexcept
|
||||||
|
{
|
||||||
|
return finishedSendsCalled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::PstreamBuffers::allowClearRecv() const noexcept
|
||||||
|
{
|
||||||
|
return allowClearRecv_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::PstreamBuffers::allowClearRecv(bool on) noexcept
|
||||||
|
{
|
||||||
|
bool old(allowClearRecv_);
|
||||||
|
allowClearRecv_ = on;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -32,7 +32,7 @@ Description
|
|||||||
|
|
||||||
Use UOPstream to stream data into buffers, call finishedSends() to
|
Use UOPstream to stream data into buffers, call finishedSends() to
|
||||||
notify that data is in buffers and then use IUPstream to get data out
|
notify that data is in buffers and then use IUPstream to get data out
|
||||||
of received buffers. Works with both blocking and nonBlocking. Does
|
of received buffers. Works with both blocking and non-blocking. Does
|
||||||
not make much sense with scheduled since there you would not need these
|
not make much sense with scheduled since there you would not need these
|
||||||
explicit buffers.
|
explicit buffers.
|
||||||
|
|
||||||
@ -151,6 +151,19 @@ class bitSet;
|
|||||||
|
|
||||||
class PstreamBuffers
|
class PstreamBuffers
|
||||||
{
|
{
|
||||||
|
// Private Data Types
|
||||||
|
|
||||||
|
//- Private enumeration for handling PEX stage 1 (sizing) modes
|
||||||
|
enum class modeOption : unsigned char
|
||||||
|
{
|
||||||
|
DEFAULT, //!< Use statically configured algorithm
|
||||||
|
GATHER, //!< Use all-to-one (gather) of sizes
|
||||||
|
SCATTER, //!< Use one-to-all (scatter) of sizes
|
||||||
|
ALL_TO_ALL, //!< Use allToAll to obtain sizes
|
||||||
|
NBX_PEX //!< Use consensus exchange (NBX) to obtain sizes
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Private Data
|
// Private Data
|
||||||
|
|
||||||
//- Track if sends are complete
|
//- Track if sends are complete
|
||||||
@ -190,20 +203,24 @@ class PstreamBuffers
|
|||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Change status of finished sends called
|
||||||
|
inline void setFinished(bool on) noexcept;
|
||||||
|
|
||||||
//- Clear 'unregistered' send buffers, tag as being send-ready
|
//- Clear 'unregistered' send buffers, tag as being send-ready
|
||||||
inline void initFinalExchange();
|
inline void initFinalExchange();
|
||||||
|
|
||||||
//- Mark all sends as having been done.
|
//- Mark all sends as having been done.
|
||||||
// This will start receives (nonBlocking comms).
|
// This will start receives (non-blocking comms).
|
||||||
void finalExchange
|
void finalExchange
|
||||||
(
|
(
|
||||||
|
enum modeOption mode,
|
||||||
const bool wait,
|
const bool wait,
|
||||||
labelList& recvSizes
|
labelList& recvSizes
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Mark sends as done.
|
//- Mark sends as done.
|
||||||
// Only exchange sizes using the neighbour ranks
|
// Only exchange sizes using the neighbour ranks
|
||||||
// (nonBlocking comms).
|
// (non-blocking comms).
|
||||||
void finalExchange
|
void finalExchange
|
||||||
(
|
(
|
||||||
const labelUList& sendProcs,
|
const labelUList& sendProcs,
|
||||||
@ -212,14 +229,6 @@ class PstreamBuffers
|
|||||||
labelList& recvSizes
|
labelList& recvSizes
|
||||||
);
|
);
|
||||||
|
|
||||||
//- For all-to-one or one-to-all
|
|
||||||
void finalGatherScatter
|
|
||||||
(
|
|
||||||
const bool isGather,
|
|
||||||
const bool wait,
|
|
||||||
labelList& recvSizes
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Friendship Access
|
// Friendship Access
|
||||||
|
|
||||||
@ -343,17 +352,11 @@ public:
|
|||||||
// Queries
|
// Queries
|
||||||
|
|
||||||
//- True if finishedSends() or finishedNeighbourSends() has been called
|
//- True if finishedSends() or finishedNeighbourSends() has been called
|
||||||
bool finished() const noexcept
|
bool finished() const noexcept;
|
||||||
{
|
|
||||||
return finishedSendsCalled_;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Is clearStorage of individual receive buffer by external hooks
|
//- Is clearStorage of individual receive buffer by external hooks
|
||||||
//- allowed? (default: true)
|
//- allowed? (default: true)
|
||||||
bool allowClearRecv() const noexcept
|
bool allowClearRecv() const noexcept;
|
||||||
{
|
|
||||||
return allowClearRecv_;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- True if any (local) send buffers have data
|
//- True if any (local) send buffers have data
|
||||||
bool hasSendData() const;
|
bool hasSendData() const;
|
||||||
@ -436,74 +439,96 @@ public:
|
|||||||
|
|
||||||
// Regular Functions
|
// Regular Functions
|
||||||
|
|
||||||
//- Mark sends as done
|
//- Mark the send phase as being finished.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers (all-to-all).
|
// Non-blocking mode: populates receive buffers using all-to-all
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
// or NBX (depending on tuning parameters).
|
||||||
|
// \param wait wait for requests to complete (in non-blocking mode)
|
||||||
void finishedSends(const bool wait = true);
|
void finishedSends(const bool wait = true);
|
||||||
|
|
||||||
//- Mark sends as done.
|
//- Mark the send phase as being finished.
|
||||||
|
//
|
||||||
|
// Non-blocking mode: populates receive buffers using NBX.
|
||||||
|
// \param wait wait for requests to complete (in non-blocking mode)
|
||||||
|
void finishedSendsNBX(const bool wait = true);
|
||||||
|
|
||||||
|
//- Mark the send phase as being finished.
|
||||||
//- Recovers the sizes (bytes) received.
|
//- Recovers the sizes (bytes) received.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers (all-to-all).
|
// Non-blocking mode: populates receive buffers using all-to-all
|
||||||
// \param[out] recvSizes the sizes (bytes) received
|
// or NBX (depending on tuning parameters).
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
// \warning currently only valid for non-blocking comms.
|
||||||
|
void finishedSends
|
||||||
|
(
|
||||||
|
//! [out] the sizes (bytes) received
|
||||||
|
labelList& recvSizes,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
|
const bool wait = true
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Mark the send phase as being finished.
|
||||||
|
//- Recovers the sizes (bytes) received.
|
||||||
//
|
//
|
||||||
// \warning currently only valid for nonBlocking comms.
|
// Non-blocking mode: populates receive buffers using NBX.
|
||||||
void finishedSends(labelList& recvSizes, const bool wait = true);
|
// \warning currently only valid for non-blocking comms.
|
||||||
|
void finishedSendsNBX
|
||||||
|
(
|
||||||
|
//! [out] the sizes (bytes) received
|
||||||
|
labelList& recvSizes,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
|
const bool wait = true
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// Functions with restricted neighbours
|
// Functions with restricted neighbours
|
||||||
|
|
||||||
//- Mark sends as done using subset of send/recv ranks
|
//- Mark the send phase as being finished, with communication
|
||||||
//- and recover the sizes (bytes) received.
|
//- being limited to a known subset of send/recv ranks.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers.
|
// Non-blocking mode: populates receive buffers.
|
||||||
//
|
//
|
||||||
// \param neighProcs ranks used for sends/recvs
|
// \warning currently only valid for non-blocking comms.
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
|
||||||
//
|
|
||||||
// \warning currently only valid for nonBlocking comms.
|
|
||||||
// \note Same as finishedSends with identical sendProcs/recvProcs
|
// \note Same as finishedSends with identical sendProcs/recvProcs
|
||||||
void finishedNeighbourSends
|
void finishedNeighbourSends
|
||||||
(
|
(
|
||||||
|
//! ranks used for sends/recvs
|
||||||
const labelUList& neighProcs,
|
const labelUList& neighProcs,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
const bool wait = true
|
const bool wait = true
|
||||||
);
|
);
|
||||||
|
|
||||||
//- Mark sends as done using subset of send/recv ranks
|
//- Mark the send phase as being finished, with communication
|
||||||
//- and recover the sizes (bytes) received.
|
//- being limited to a known subset of send/recv ranks.
|
||||||
|
//- Recovers the sizes (bytes) received.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: it will populate receive buffers.
|
// Non-blocking mode: it will populate receive buffers.
|
||||||
//
|
//
|
||||||
// \param neighProcs ranks used for sends/recvs
|
// \warning currently only valid for non-blocking mode.
|
||||||
// \param[out] recvSizes the sizes (bytes) received
|
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
|
||||||
//
|
|
||||||
// \warning currently only valid for nonBlocking mode.
|
|
||||||
void finishedNeighbourSends
|
void finishedNeighbourSends
|
||||||
(
|
(
|
||||||
|
//! ranks used for sends/recvs
|
||||||
const labelUList& neighProcs,
|
const labelUList& neighProcs,
|
||||||
|
//! [out] the sizes (bytes) received
|
||||||
labelList& recvSizes,
|
labelList& recvSizes,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
const bool wait = true
|
const bool wait = true
|
||||||
);
|
);
|
||||||
|
|
||||||
//- A caching version that uses a limited send/recv connectivity.
|
//- A caching version that uses a limited send/recv connectivity.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers.
|
// Non-blocking mode: populates receive buffers.
|
||||||
// \param sendConnections on/off for sending ranks
|
|
||||||
// \param sendProcs ranks used for sends
|
|
||||||
// \param recvProcs ranks used for recvs
|
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
|
||||||
//
|
|
||||||
// \return True if the send/recv connectivity changed
|
// \return True if the send/recv connectivity changed
|
||||||
//
|
//
|
||||||
// \warning currently only valid for nonBlocking comms.
|
// \warning currently only valid for non-blocking comms.
|
||||||
bool finishedSends
|
bool finishedSends
|
||||||
(
|
(
|
||||||
|
//! inter-rank connections (on/off) for sending ranks
|
||||||
bitSet& sendConnections,
|
bitSet& sendConnections,
|
||||||
|
//! ranks used for sends
|
||||||
DynamicList<label>& sendProcs,
|
DynamicList<label>& sendProcs,
|
||||||
|
//! ranks used for recvs
|
||||||
DynamicList<label>& recvProcs,
|
DynamicList<label>& recvProcs,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
const bool wait = true
|
const bool wait = true
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -515,40 +540,46 @@ public:
|
|||||||
// Non-blocking mode: populates receive buffers.
|
// Non-blocking mode: populates receive buffers.
|
||||||
// Can use recvDataCount, maxRecvCount etc to recover sizes received.
|
// Can use recvDataCount, maxRecvCount etc to recover sizes received.
|
||||||
//
|
//
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
// \param wait wait for requests to complete (in non-blocking mode)
|
||||||
//
|
//
|
||||||
// \warning currently only valid for nonBlocking comms.
|
// \warning currently only valid for non-blocking comms.
|
||||||
void finishedGathers(const bool wait = true);
|
void finishedGathers(const bool wait = true);
|
||||||
|
|
||||||
//- Mark all sends to master as done.
|
//- Mark all sends to master as done.
|
||||||
//- Recovers the sizes (bytes) received.
|
//- Recovers the sizes (bytes) received.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers (all-to-one).
|
// Non-blocking mode: populates receive buffers (all-to-one).
|
||||||
// \param[out] recvSizes the sizes (bytes) received
|
// \warning currently only valid for non-blocking comms.
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
void finishedGathers
|
||||||
//
|
(
|
||||||
// \warning currently only valid for nonBlocking comms.
|
//! [out] the sizes (bytes) received
|
||||||
void finishedGathers(labelList& recvSizes, const bool wait = true);
|
labelList& recvSizes,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
|
const bool wait = true
|
||||||
|
);
|
||||||
|
|
||||||
//- Mark all sends to sub-procs as done.
|
//- Mark all sends to sub-procs as done.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers.
|
// Non-blocking mode: populates receive buffers.
|
||||||
// Can use recvDataCount, maxRecvCount etc to recover sizes received.
|
// Can use recvDataCount, maxRecvCount etc to recover sizes received.
|
||||||
//
|
//
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
// \param wait wait for requests to complete (in non-blocking mode)
|
||||||
//
|
//
|
||||||
// \warning currently only valid for nonBlocking comms.
|
// \warning currently only valid for non-blocking comms.
|
||||||
void finishedScatters(const bool wait = true);
|
void finishedScatters(const bool wait = true);
|
||||||
|
|
||||||
//- Mark all sends to sub-procs as done.
|
//- Mark all sends to sub-procs as done.
|
||||||
//- Recovers the sizes (bytes) received.
|
//- Recovers the sizes (bytes) received.
|
||||||
//
|
//
|
||||||
// Non-blocking mode: populates receive buffers (all-to-one).
|
// Non-blocking mode: populates receive buffers (all-to-one).
|
||||||
// \param[out] recvSizes the sizes (bytes) received
|
// \warning currently only valid for non-blocking comms.
|
||||||
// \param wait wait for requests to complete (in nonBlocking mode)
|
void finishedScatters
|
||||||
//
|
(
|
||||||
// \warning currently only valid for nonBlocking comms.
|
//! [out] the sizes (bytes) received
|
||||||
void finishedScatters(labelList& recvSizes, const bool wait = true);
|
labelList& recvSizes,
|
||||||
|
//! wait for requests to complete (in non-blocking mode)
|
||||||
|
const bool wait = true
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -46,21 +46,19 @@ namespace Foam
|
|||||||
namespace PstreamDetail
|
namespace PstreamDetail
|
||||||
{
|
{
|
||||||
|
|
||||||
//- Exchange \em contiguous data using non-blocking consensus exchange
|
//- Exchange \em contiguous data using non-blocking consensus exchange (NBX)
|
||||||
//- with optional tracking of the receive sizes.
|
//- with optional tracking of the receive sizes.
|
||||||
//
|
//
|
||||||
// No internal guards or resizing - data containers are all properly
|
// No internal guards or resizing - data containers are all properly
|
||||||
// sized before calling.
|
// sized before calling.
|
||||||
//
|
//
|
||||||
// \param[in] sendBufs The send buffers list (size: numProcs)
|
// \param[in] sendBufs The send buffers list (size: numProc)
|
||||||
// \param[out] recvBufs The recv buffers list (size: numProcs)
|
// \param[out] recvBufs The recv buffers list (size: numProc)
|
||||||
// \param[out] recvSizes The recv sizes (size: 0 or numProcs).
|
// \param[out] recvSizes The recv sizes (size: 0 or numProc).
|
||||||
// This parameter can be an empty list, in which case the receive sizes
|
// This parameter can be an empty list, in which case the receive sizes
|
||||||
// are not returned.
|
// are not returned.
|
||||||
// \param tag The message tag
|
// \param tag The message tag
|
||||||
// \param comm The communicator
|
// \param comm The communicator
|
||||||
// \param wait Wait for non-blocking receives to complete
|
|
||||||
// \param recvCommType If blocking or (default) non-blocking
|
|
||||||
|
|
||||||
template<class Container, class Type>
|
template<class Container, class Type>
|
||||||
void exchangeConsensus
|
void exchangeConsensus
|
||||||
@ -69,20 +67,17 @@ void exchangeConsensus
|
|||||||
UList<Container>& recvBufs,
|
UList<Container>& recvBufs,
|
||||||
labelUList& recvSizes,
|
labelUList& recvSizes,
|
||||||
const int tag,
|
const int tag,
|
||||||
const label comm,
|
const label comm
|
||||||
const bool wait = true,
|
|
||||||
const UPstream::commsTypes recvCommType = UPstream::commsTypes::nonBlocking
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
||||||
|
|
||||||
const bool initialBarrier = (UPstream::tuning_NBX_ > 0);
|
const bool initialBarrier = (UPstream::tuning_NBX_ > 0);
|
||||||
|
|
||||||
const label startOfRequests = UPstream::nRequests();
|
|
||||||
const label myProci = UPstream::myProcNo(comm);
|
const label myProci = UPstream::myProcNo(comm);
|
||||||
const label numProc = UPstream::nProcs(comm);
|
const label numProc = UPstream::nProcs(comm);
|
||||||
|
|
||||||
// Initial: clear all receive information
|
// Initial: clear all receive locations
|
||||||
for (auto& buf : recvBufs)
|
for (auto& buf : recvBufs)
|
||||||
{
|
{
|
||||||
buf.clear();
|
buf.clear();
|
||||||
@ -98,28 +93,37 @@ void exchangeConsensus
|
|||||||
if (sendBufs.size() > numProc)
|
if (sendBufs.size() > numProc)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "Send buffers:" << sendBufs.size() << " > numProcs:" << numProc
|
<< "Send buffers:" << sendBufs.size() << " > numProc:" << numProc
|
||||||
<< Foam::abort(FatalError);
|
<< Foam::abort(FatalError);
|
||||||
}
|
}
|
||||||
if (recvBufs.size() < numProc)
|
if (recvBufs.size() < numProc)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "Recv buffers:" << recvBufs.size() << " < numProcs:" << numProc
|
<< "Recv buffers:" << recvBufs.size() << " < numProc:" << numProc
|
||||||
<< Foam::abort(FatalError);
|
<< Foam::abort(FatalError);
|
||||||
}
|
}
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
if (!UPstream::is_parallel(comm))
|
// Fake send/recv for myself - parallel or non-parallel
|
||||||
{
|
{
|
||||||
// Do myself
|
|
||||||
recvBufs[myProci] = sendBufs[myProci];
|
recvBufs[myProci] = sendBufs[myProci];
|
||||||
if (myProci < recvSizes.size())
|
if (myProci < recvSizes.size())
|
||||||
{
|
{
|
||||||
recvSizes[myProci] = recvBufs.size();
|
recvSizes[myProci] = recvBufs.size();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UPstream::is_parallel(comm))
|
||||||
|
{
|
||||||
|
// Nothing left to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Setup sends
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
// An initial barrier may help to avoid synchronisation problems
|
// An initial barrier may help to avoid synchronisation problems
|
||||||
// caused elsewhere
|
// caused elsewhere
|
||||||
if (initialBarrier)
|
if (initialBarrier)
|
||||||
@ -127,11 +131,12 @@ void exchangeConsensus
|
|||||||
UPstream::barrier(comm);
|
UPstream::barrier(comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Algorithm NBX: Nonblocking consensus with List containers
|
// Algorithm NBX: Nonblocking consensus with List containers
|
||||||
|
|
||||||
DynamicList<UPstream::Request> sendRequests(sendBufs.size());
|
DynamicList<UPstream::Request> sendRequests(sendBufs.size());
|
||||||
|
|
||||||
// Start nonblocking synchronous send to processor dest
|
// Start nonblocking synchronous send to destination ranks
|
||||||
for (label proci = 0; proci < numProc; ++proci)
|
for (label proci = 0; proci < numProc; ++proci)
|
||||||
{
|
{
|
||||||
const auto& sendData = sendBufs[proci];
|
const auto& sendData = sendBufs[proci];
|
||||||
@ -140,19 +145,8 @@ void exchangeConsensus
|
|||||||
{
|
{
|
||||||
// Do not send/recv empty data
|
// Do not send/recv empty data
|
||||||
}
|
}
|
||||||
else if (proci == myProci)
|
else if (proci != myProci)
|
||||||
{
|
{
|
||||||
// Do myself
|
|
||||||
recvBufs[proci] = sendData;
|
|
||||||
if (proci < recvSizes.size())
|
|
||||||
{
|
|
||||||
recvSizes[proci] = sendData.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Has data to send.
|
|
||||||
// The MPI send requests are tracked on a local list
|
|
||||||
UOPstream::write
|
UOPstream::write
|
||||||
(
|
(
|
||||||
sendRequests.emplace_back(),
|
sendRequests.emplace_back(),
|
||||||
@ -167,7 +161,15 @@ void exchangeConsensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// Probe and receive
|
// Probe and receive
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// When receiving can use resize() instead of resize_nocopy() since the
|
||||||
|
// slots were already initially cleared.
|
||||||
|
// The resize() also works fine with FixedList since it will
|
||||||
|
// corresponds to a no-op: send and recv sizes will always be
|
||||||
|
// identical to its fixed size() / max_size()
|
||||||
|
|
||||||
UPstream::Request barrierRequest;
|
UPstream::Request barrierRequest;
|
||||||
|
|
||||||
@ -191,17 +193,16 @@ void exchangeConsensus
|
|||||||
const label count = (probed.second / sizeof(Type));
|
const label count = (probed.second / sizeof(Type));
|
||||||
|
|
||||||
auto& recvData = recvBufs[proci];
|
auto& recvData = recvBufs[proci];
|
||||||
recvData.resize_nocopy(count);
|
recvData.resize(count); // OK with resize() instead of _nocopy()
|
||||||
|
|
||||||
if (proci < recvSizes.size())
|
if (proci < recvSizes.size())
|
||||||
{
|
{
|
||||||
recvSizes[proci] = count;
|
recvSizes[proci] = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any non-blocking MPI recv requests are tracked on internal stack
|
|
||||||
UIPstream::read
|
UIPstream::read
|
||||||
(
|
(
|
||||||
recvCommType,
|
UPstream::commsTypes::blocking,
|
||||||
proci,
|
proci,
|
||||||
recvData.data_bytes(),
|
recvData.data_bytes(),
|
||||||
recvData.size_bytes(),
|
recvData.size_bytes(),
|
||||||
@ -229,26 +230,18 @@ void exchangeConsensus
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for non-blocking receives to finish
|
|
||||||
if (wait && recvCommType == UPstream::commsTypes::nonBlocking)
|
|
||||||
{
|
|
||||||
UPstream::waitRequests(startOfRequests);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//- Exchange \em contiguous data using non-blocking consensus exchange.
|
//- Exchange \em contiguous data using non-blocking consensus exchange (NBX)
|
||||||
//
|
//
|
||||||
// No internal guards - the sending Map corresponds to a segment of
|
// No internal guards - the sending Map corresponds to a segment of
|
||||||
// 0-numProcs.
|
// 0-numProc.
|
||||||
//
|
//
|
||||||
// \param[in] sendBufs The send buffers map (addr: 0-numProcs)
|
// \param[in] sendBufs The send buffers map (addr: 0-numProc)
|
||||||
// \param[out] recvBufs The recv buffers map
|
// \param[out] recvBufs The recv buffers map
|
||||||
// \param tag The message tag
|
// \param tag The message tag
|
||||||
// \param comm The communicator
|
// \param comm The communicator
|
||||||
// \param wait Wait for non-blocking receives to complete
|
|
||||||
// \param recvCommType If blocking or (default) non-blocking
|
|
||||||
|
|
||||||
template<class Container, class Type>
|
template<class Container, class Type>
|
||||||
void exchangeConsensus
|
void exchangeConsensus
|
||||||
@ -256,17 +249,17 @@ void exchangeConsensus
|
|||||||
const Map<Container>& sendBufs,
|
const Map<Container>& sendBufs,
|
||||||
Map<Container>& recvBufs,
|
Map<Container>& recvBufs,
|
||||||
const int tag,
|
const int tag,
|
||||||
const label comm,
|
const label comm
|
||||||
const bool wait = true,
|
|
||||||
const UPstream::commsTypes recvCommType = UPstream::commsTypes::nonBlocking
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
||||||
|
|
||||||
const label startOfRequests = UPstream::nRequests();
|
// TDB: const bool initialBarrier = (UPstream::tuning_NBX_ > 0);
|
||||||
const label myProci = UPstream::myProcNo(comm);
|
|
||||||
|
|
||||||
// Initial: clear out receive 'slots'
|
const label myProci = UPstream::myProcNo(comm);
|
||||||
|
const label numProc = UPstream::myProcNo(comm);
|
||||||
|
|
||||||
|
// Initial: clear all receive locations
|
||||||
// Preferrable to clear out the map entries instead of the map itself
|
// Preferrable to clear out the map entries instead of the map itself
|
||||||
// since this can potentially preserve allocated space
|
// since this can potentially preserve allocated space
|
||||||
// (eg DynamicList entries) between calls
|
// (eg DynamicList entries) between calls
|
||||||
@ -276,9 +269,13 @@ void exchangeConsensus
|
|||||||
iter.val().clear();
|
iter.val().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UPstream::is_parallel(comm))
|
if (!UPstream::is_rank(comm))
|
||||||
|
{
|
||||||
|
return; // Process not in communicator
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake send/recv for myself - parallel or non-parallel
|
||||||
{
|
{
|
||||||
// Do myself
|
|
||||||
const auto iter = sendBufs.find(myProci);
|
const auto iter = sendBufs.find(myProci);
|
||||||
if (iter.good())
|
if (iter.good())
|
||||||
{
|
{
|
||||||
@ -290,43 +287,38 @@ void exchangeConsensus
|
|||||||
recvBufs(iter.key()) = sendData;
|
recvBufs(iter.key()) = sendData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UPstream::is_parallel(comm))
|
||||||
|
{
|
||||||
|
// Nothing left to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Setup sends
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// TDB: initialBarrier ...
|
||||||
|
|
||||||
|
|
||||||
// Algorithm NBX: Nonblocking consensus with Map (HashTable) containers
|
// Algorithm NBX: Nonblocking consensus with Map (HashTable) containers
|
||||||
|
|
||||||
DynamicList<UPstream::Request> sendRequests(sendBufs.size());
|
DynamicList<UPstream::Request> sendRequests(sendBufs.size());
|
||||||
|
|
||||||
// Start nonblocking synchronous send to process dest
|
// Start nonblocking synchronous send to destination ranks
|
||||||
forAllConstIters(sendBufs, iter)
|
forAllConstIters(sendBufs, iter)
|
||||||
{
|
{
|
||||||
const label proci = iter.key();
|
const label proci = iter.key();
|
||||||
const auto& sendData = iter.val();
|
const auto& sendData = iter.val();
|
||||||
|
|
||||||
#ifdef FULLDEBUG
|
if (sendData.empty() || proci < 0 || proci >= numProc)
|
||||||
if (proci >= UPstream::nProcs(comm))
|
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
// Do not send/recv empty data or invalid destinations
|
||||||
<< "Send buffer:" << proci << " >= numProcs:"
|
|
||||||
<< UPstream::nProcs(comm)
|
|
||||||
<< Foam::abort(FatalError);
|
|
||||||
}
|
}
|
||||||
#endif
|
else if (proci != myProci)
|
||||||
|
|
||||||
if (sendData.empty())
|
|
||||||
{
|
{
|
||||||
// Do not send/recv empty data
|
|
||||||
}
|
|
||||||
else if (proci == myProci)
|
|
||||||
{
|
|
||||||
// Do myself: insert_or_assign
|
|
||||||
recvBufs(proci) = sendData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Has data to send.
|
|
||||||
// The MPI send requests are tracked on a local list
|
|
||||||
UOPstream::write
|
UOPstream::write
|
||||||
(
|
(
|
||||||
sendRequests.emplace_back(),
|
sendRequests.emplace_back(),
|
||||||
@ -341,7 +333,15 @@ void exchangeConsensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// Probe and receive
|
// Probe and receive
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// When receiving can use resize() instead of resize_nocopy() since the
|
||||||
|
// slots were already initially cleared.
|
||||||
|
// The resize() also works fine with FixedList since it will
|
||||||
|
// corresponds to a no-op: send and recv sizes will always be
|
||||||
|
// identical to its fixed size() / max_size()
|
||||||
|
|
||||||
UPstream::Request barrierRequest;
|
UPstream::Request barrierRequest;
|
||||||
|
|
||||||
@ -365,12 +365,11 @@ void exchangeConsensus
|
|||||||
const label count = (probed.second / sizeof(Type));
|
const label count = (probed.second / sizeof(Type));
|
||||||
|
|
||||||
auto& recvData = recvBufs(proci);
|
auto& recvData = recvBufs(proci);
|
||||||
recvData.resize_nocopy(count);
|
recvData.resize(count); // OK with resize() instead of _nocopy()
|
||||||
|
|
||||||
// Any non-blocking MPI recv requests are tracked on internal stack
|
|
||||||
UIPstream::read
|
UIPstream::read
|
||||||
(
|
(
|
||||||
recvCommType,
|
UPstream::commsTypes::blocking,
|
||||||
proci,
|
proci,
|
||||||
recvData.data_bytes(),
|
recvData.data_bytes(),
|
||||||
recvData.size_bytes(),
|
recvData.size_bytes(),
|
||||||
@ -397,12 +396,6 @@ void exchangeConsensus
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for non-blocking receives to finish
|
|
||||||
if (wait && recvCommType == UPstream::commsTypes::nonBlocking)
|
|
||||||
{
|
|
||||||
UPstream::waitRequests(startOfRequests);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace PstreamDetail
|
} // namespace PstreamDetail
|
||||||
@ -418,7 +411,7 @@ void Foam::Pstream::exchangeConsensus
|
|||||||
List<Container>& recvBufs,
|
List<Container>& recvBufs,
|
||||||
const int tag,
|
const int tag,
|
||||||
const label comm,
|
const label comm,
|
||||||
const bool wait
|
const bool /* wait (ignored) */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
||||||
@ -427,7 +420,7 @@ void Foam::Pstream::exchangeConsensus
|
|||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "Send buffers size:" << sendBufs.size()
|
<< "Send buffers size:" << sendBufs.size()
|
||||||
<< " != numProcs:" << UPstream::nProcs(comm)
|
<< " != numProc:" << UPstream::nProcs(comm)
|
||||||
<< Foam::abort(FatalError);
|
<< Foam::abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,14 +428,13 @@ void Foam::Pstream::exchangeConsensus
|
|||||||
recvBufs.resize_nocopy(sendBufs.size());
|
recvBufs.resize_nocopy(sendBufs.size());
|
||||||
labelList dummyRecvSizes;
|
labelList dummyRecvSizes;
|
||||||
|
|
||||||
PstreamDetail::exchangeConsensus
|
PstreamDetail::exchangeConsensus<Container, Type>
|
||||||
(
|
(
|
||||||
sendBufs,
|
sendBufs,
|
||||||
recvBufs,
|
recvBufs,
|
||||||
dummyRecvSizes,
|
dummyRecvSizes,
|
||||||
tag,
|
tag,
|
||||||
comm,
|
comm
|
||||||
wait
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,20 +446,45 @@ void Foam::Pstream::exchangeConsensus
|
|||||||
Map<Container>& recvBufs,
|
Map<Container>& recvBufs,
|
||||||
const int tag,
|
const int tag,
|
||||||
const label comm,
|
const label comm,
|
||||||
const bool wait
|
const bool /* wait (ignored) */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
||||||
|
|
||||||
PstreamDetail::exchangeConsensus
|
PstreamDetail::exchangeConsensus<Container, Type>
|
||||||
(
|
(
|
||||||
sendBufs,
|
sendBufs,
|
||||||
recvBufs,
|
recvBufs,
|
||||||
tag,
|
tag,
|
||||||
comm,
|
comm
|
||||||
wait
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Container, class Type>
|
||||||
|
Foam::Map<Container>
|
||||||
|
Foam::Pstream::exchangeConsensus
|
||||||
|
(
|
||||||
|
const Map<Container>& sendBufs,
|
||||||
|
const int tag,
|
||||||
|
const label comm,
|
||||||
|
const bool /* wait (ignored) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Map<Container> recvBufs;
|
||||||
|
|
||||||
|
static_assert(is_contiguous<Type>::value, "Contiguous data only!");
|
||||||
|
|
||||||
|
PstreamDetail::exchangeConsensus<Container, Type>
|
||||||
|
(
|
||||||
|
sendBufs,
|
||||||
|
recvBufs,
|
||||||
|
tag,
|
||||||
|
comm
|
||||||
|
);
|
||||||
|
|
||||||
|
return recvBufs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -44,6 +44,7 @@ SourceFiles
|
|||||||
#include "labelList.H"
|
#include "labelList.H"
|
||||||
#include "DynamicList.H"
|
#include "DynamicList.H"
|
||||||
#include "HashTable.H"
|
#include "HashTable.H"
|
||||||
|
#include "Map.H"
|
||||||
#include "Enum.H"
|
#include "Enum.H"
|
||||||
#include "ListOps.H"
|
#include "ListOps.H"
|
||||||
|
|
||||||
@ -55,9 +56,6 @@ namespace Foam
|
|||||||
//- Implementation details for UPstream/Pstream/MPI etc.
|
//- Implementation details for UPstream/Pstream/MPI etc.
|
||||||
namespace PstreamDetail {}
|
namespace PstreamDetail {}
|
||||||
|
|
||||||
// Forward Declarations
|
|
||||||
template<class T> class Map;
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
/*---------------------------------------------------------------------------*\
|
||||||
Class UPstream Declaration
|
Class UPstream Declaration
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
@ -968,119 +966,76 @@ public:
|
|||||||
//- Shutdown (finalize) MPI as required and exit program with errNo.
|
//- Shutdown (finalize) MPI as required and exit program with errNo.
|
||||||
static void exit(int errNo = 1);
|
static void exit(int errNo = 1);
|
||||||
|
|
||||||
//- Exchange integer data with all processors (in the communicator).
|
|
||||||
// \c sendData[proci] is the value to send to proci.
|
|
||||||
// After return recvData contains the data from the other processors.
|
|
||||||
// \n
|
|
||||||
// For \b non-parallel : does a simple copy of sendData to recvData
|
|
||||||
static void allToAll
|
|
||||||
(
|
|
||||||
const UList<int32_t>& sendData,
|
|
||||||
UList<int32_t>& recvData,
|
|
||||||
const label communicator = worldComm
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Exchange integer data with all processors (in the communicator).
|
#undef Pstream_CommonRoutines
|
||||||
// \c sendData[proci] is the value to send to proci.
|
#define Pstream_CommonRoutines(Native) \
|
||||||
// After return recvData contains the data from the other processors.
|
\
|
||||||
// \n
|
/*!\brief Exchange \c Native data with all ranks in communicator */ \
|
||||||
// For \b non-parallel : does a simple copy of sendData to recvData
|
/*! \em non-parallel : simple copy of \p sendData to \p recvData */ \
|
||||||
static void allToAll
|
static void allToAll \
|
||||||
(
|
( \
|
||||||
const UList<int64_t>& sendData,
|
/*! [in] The value at [proci] is sent to proci */ \
|
||||||
UList<int64_t>& recvData,
|
const UList<Native>& sendData, \
|
||||||
const label communicator = worldComm
|
/*! [out] The data received from the other ranks */ \
|
||||||
);
|
UList<Native>& recvData, \
|
||||||
|
const label communicator = worldComm \
|
||||||
|
); \
|
||||||
|
\
|
||||||
|
/*!\brief Exchange \em non-zero \c Native data between ranks [NBX] */ \
|
||||||
|
/*! \p recvData is always initially assigned zero and no non-zero */ \
|
||||||
|
/*! values are sent/received from other ranks. */ \
|
||||||
|
/*! \em non-parallel : simple copy of \p sendData to \p recvData */ \
|
||||||
|
/*! \note The message tag should be chosen to be a unique value */ \
|
||||||
|
/*! since the implementation uses probing with ANY_SOURCE !! */ \
|
||||||
|
/*! An initial barrier may help to avoid synchronisation problems */ \
|
||||||
|
/*! caused elsewhere (See "nbx.tuning" opt switch) */ \
|
||||||
|
static void allToAllConsensus \
|
||||||
|
( \
|
||||||
|
/*! [in] The \em non-zero value at [proci] is sent to proci */ \
|
||||||
|
const UList<Native>& sendData, \
|
||||||
|
/*! [out] The non-zero value received from each rank */ \
|
||||||
|
UList<Native>& recvData, \
|
||||||
|
/*! Message tag for the communication */ \
|
||||||
|
const int tag, \
|
||||||
|
const label communicator = worldComm \
|
||||||
|
); \
|
||||||
|
\
|
||||||
|
/*!\brief Exchange \c Native data between ranks [NBX] */ \
|
||||||
|
/*! \p recvData map is always cleared initially so a simple check */ \
|
||||||
|
/*! of its keys is sufficient to determine connectivity. */ \
|
||||||
|
/*! \em non-parallel : copy own rank (if it exists) */ \
|
||||||
|
/*! See notes about message tags and "nbx.tuning" opt switch */ \
|
||||||
|
static void allToAllConsensus \
|
||||||
|
( \
|
||||||
|
/*! [in] The value at [proci] is sent to proci. */ \
|
||||||
|
const Map<Native>& sendData, \
|
||||||
|
/*! [out] The values received from given ranks. */ \
|
||||||
|
Map<Native>& recvData, \
|
||||||
|
/*! Message tag for the communication */ \
|
||||||
|
const int tag, \
|
||||||
|
const label communicator = worldComm \
|
||||||
|
); \
|
||||||
|
\
|
||||||
|
/*!\brief Exchange \c Native data between ranks [NBX] */ \
|
||||||
|
/*! \returns any received data as a Map */ \
|
||||||
|
static Map<Native> allToAllConsensus \
|
||||||
|
( \
|
||||||
|
/*! [in] The value at [proci] is sent to proci. */ \
|
||||||
|
const Map<Native>& sendData, \
|
||||||
|
/*! Message tag for the communication */ \
|
||||||
|
const int tag, \
|
||||||
|
const label communicator = worldComm \
|
||||||
|
) \
|
||||||
|
{ \
|
||||||
|
Map<Native> recvData; \
|
||||||
|
allToAllConsensus(sendData, recvData, tag, communicator); \
|
||||||
|
return recvData; \
|
||||||
|
}
|
||||||
|
|
||||||
//- Exchange \b non-zero integer data with all ranks in the communicator
|
Pstream_CommonRoutines(int32_t);
|
||||||
//- using non-blocking consensus exchange.
|
Pstream_CommonRoutines(int64_t);
|
||||||
// The \c sendData[proci] is the (non-zero) value to send to proci.
|
|
||||||
// After return recvData contains the non-zero values sent from the
|
|
||||||
// other processors. The recvData list is always assigned zero before
|
|
||||||
// receipt and values of zero are never transmitted.
|
|
||||||
// After return recvData contains the data from the other processors.
|
|
||||||
// \n
|
|
||||||
// For \b non-parallel : does a simple copy of sendData to recvData
|
|
||||||
//
|
|
||||||
// \note The message tag should be chosen to be a unique value
|
|
||||||
// since the implementation uses probing with ANY_SOURCE !!
|
|
||||||
// An initial barrier may help to avoid synchronisation problems
|
|
||||||
// caused elsewhere (See "nbx.tuning" opt switch)
|
|
||||||
static void allToAllConsensus
|
|
||||||
(
|
|
||||||
const UList<int32_t>& sendData,
|
|
||||||
UList<int32_t>& recvData,
|
|
||||||
const int tag,
|
|
||||||
const label communicator = worldComm
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Exchange \b non-zero integer data with all ranks in the communicator
|
#undef Pstream_CommonRoutines
|
||||||
//- using non-blocking consensus exchange.
|
|
||||||
// The \c sendData[proci] is the (non-zero) value to send to proci.
|
|
||||||
// After return recvData contains the non-zero values sent from the
|
|
||||||
// other processors. The recvData list is always assigned zero before
|
|
||||||
// receipt and values of zero are never transmitted.
|
|
||||||
// After return recvData contains the data from the other processors.
|
|
||||||
// \n
|
|
||||||
// For \b non-parallel : does a simple copy of sendData to recvData
|
|
||||||
//
|
|
||||||
// \note The message tag should be chosen to be a unique value
|
|
||||||
// since the implementation uses probing with ANY_SOURCE !!
|
|
||||||
// An initial barrier may help to avoid synchronisation problems
|
|
||||||
// caused elsewhere (See "nbx.tuning" opt switch)
|
|
||||||
static void allToAllConsensus
|
|
||||||
(
|
|
||||||
const UList<int64_t>& sendData,
|
|
||||||
UList<int64_t>& recvData,
|
|
||||||
const int tag,
|
|
||||||
const label communicator = worldComm
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Exchange \b non-zero integer data with all ranks in the communicator
|
|
||||||
//- using non-blocking consensus exchange.
|
|
||||||
// The \c sendData[proci] is the (non-zero) value to send to proci.
|
|
||||||
// After return recvData contains the non-zero values sent from the
|
|
||||||
// other processors. Since the recvData map always cleared before
|
|
||||||
// receipt and values of zero are never transmitted, a simple check
|
|
||||||
// of its keys is sufficient to determine connectivity.
|
|
||||||
// \n
|
|
||||||
// For \b non-parallel : copy own rank (if it exists and non-zero)
|
|
||||||
// from sendData to recvData.
|
|
||||||
//
|
|
||||||
// \note The message tag should be chosen to be a unique value
|
|
||||||
// since the implementation uses probing with ANY_SOURCE !!
|
|
||||||
// An initial barrier may help to avoid synchronisation problems
|
|
||||||
// caused elsewhere (See "nbx.tuning" opt switch)
|
|
||||||
static void allToAllConsensus
|
|
||||||
(
|
|
||||||
const Map<int32_t>& sendData,
|
|
||||||
Map<int32_t>& recvData,
|
|
||||||
const int tag,
|
|
||||||
const label communicator = worldComm
|
|
||||||
);
|
|
||||||
|
|
||||||
//- Exchange \b non-zero integer data with all ranks in the communicator
|
|
||||||
//- using non-blocking consensus exchange.
|
|
||||||
// The \c sendData[proci] is the (non-zero) value to send to proci.
|
|
||||||
// After return recvData contains the non-zero values sent from the
|
|
||||||
// other processors. Since the recvData map always cleared before
|
|
||||||
// receipt and values of zero are never transmitted, a simple check
|
|
||||||
// of its keys is sufficient to determine connectivity.
|
|
||||||
// \n
|
|
||||||
// For \b non-parallel : copy own rank (if it exists and non-zero)
|
|
||||||
// from sendData to recvData.
|
|
||||||
//
|
|
||||||
// \note The message tag should be chosen to be a unique value
|
|
||||||
// since the implementation uses probing with ANY_SOURCE !!
|
|
||||||
// An initial barrier may help to avoid synchronisation problems
|
|
||||||
// caused elsewhere (See "nbx.tuning" opt switch)
|
|
||||||
static void allToAllConsensus
|
|
||||||
(
|
|
||||||
const Map<int64_t>& sendData,
|
|
||||||
Map<int64_t>& recvData,
|
|
||||||
const int tag,
|
|
||||||
const label communicator = worldComm
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// Low-level gather/scatter routines
|
// Low-level gather/scatter routines
|
||||||
@ -1121,13 +1076,7 @@ public:
|
|||||||
/*! Number of send/recv data per rank. Globally consistent! */ \
|
/*! Number of send/recv data per rank. Globally consistent! */ \
|
||||||
int count, \
|
int count, \
|
||||||
const label communicator = worldComm \
|
const label communicator = worldComm \
|
||||||
);
|
); \
|
||||||
|
|
||||||
Pstream_CommonRoutines(char);
|
|
||||||
|
|
||||||
|
|
||||||
#undef Pstream_CommonRoutines
|
|
||||||
#define Pstream_CommonRoutines(Native) \
|
|
||||||
\
|
\
|
||||||
/*! \brief Receive variable length \c Native data from all ranks */ \
|
/*! \brief Receive variable length \c Native data from all ranks */ \
|
||||||
static void gather \
|
static void gather \
|
||||||
|
|||||||
@ -63,17 +63,9 @@ void Foam::UPstream::mpiAllGather \
|
|||||||
int count, \
|
int count, \
|
||||||
const label comm \
|
const label comm \
|
||||||
) \
|
) \
|
||||||
{}
|
{} \
|
||||||
|
\
|
||||||
Pstream_CommonRoutines(char);
|
\
|
||||||
|
|
||||||
#undef Pstream_CommonRoutines
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
#undef Pstream_CommonRoutines
|
|
||||||
#define Pstream_CommonRoutines(Native) \
|
|
||||||
void Foam::UPstream::gather \
|
void Foam::UPstream::gather \
|
||||||
( \
|
( \
|
||||||
const Native* sendData, \
|
const Native* sendData, \
|
||||||
|
|||||||
@ -79,17 +79,8 @@ void Foam::UPstream::mpiAllGather \
|
|||||||
allData, count, \
|
allData, count, \
|
||||||
TaggedType, comm \
|
TaggedType, comm \
|
||||||
); \
|
); \
|
||||||
}
|
} \
|
||||||
|
\
|
||||||
Pstream_CommonRoutines(char, MPI_BYTE);
|
|
||||||
|
|
||||||
#undef Pstream_CommonRoutines
|
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
|
||||||
|
|
||||||
#undef Pstream_CommonRoutines
|
|
||||||
#define Pstream_CommonRoutines(Native, TaggedType) \
|
|
||||||
void Foam::UPstream::gather \
|
void Foam::UPstream::gather \
|
||||||
( \
|
( \
|
||||||
const Native* sendData, \
|
const Native* sendData, \
|
||||||
|
|||||||
@ -507,7 +507,7 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
|
|
||||||
if (!UPstream::is_rank(comm))
|
if (!UPstream::is_rank(comm))
|
||||||
{
|
{
|
||||||
return;
|
return; // Process not in communicator
|
||||||
}
|
}
|
||||||
|
|
||||||
const label myProci = UPstream::myProcNo(comm);
|
const label myProci = UPstream::myProcNo(comm);
|
||||||
@ -539,11 +539,15 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
|
|
||||||
if (!UPstream::is_parallel(comm))
|
if (!UPstream::is_parallel(comm))
|
||||||
{
|
{
|
||||||
// deep copy
|
// Non-parallel : deep copy
|
||||||
recvData.deepCopy(sendData);
|
recvData.deepCopy(sendData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fake send/recv for myself
|
||||||
|
{
|
||||||
|
recvData[myProci] = sendData[myProci];
|
||||||
|
}
|
||||||
|
|
||||||
// Implementation description
|
// Implementation description
|
||||||
// --------------------------
|
// --------------------------
|
||||||
@ -562,7 +566,10 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
// This is because we are dealing with a flat list of entries to
|
// This is because we are dealing with a flat list of entries to
|
||||||
// send and not a sparse Map etc.
|
// send and not a sparse Map etc.
|
||||||
|
|
||||||
DynamicList<MPI_Request> sendRequests(sendData.size());
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Setup sends
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
profilingPstream::beginTiming();
|
profilingPstream::beginTiming();
|
||||||
|
|
||||||
@ -573,20 +580,16 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
MPI_Barrier(PstreamGlobals::MPICommunicators_[comm]);
|
MPI_Barrier(PstreamGlobals::MPICommunicators_[comm]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynamicList<MPI_Request> sendRequests(sendData.size());
|
||||||
|
|
||||||
// Start nonblocking synchronous send to process dest
|
// Start nonblocking synchronous send to destination rank
|
||||||
for (label proci = 0; proci < numProc; ++proci)
|
for (label proci = 0; proci < numProc; ++proci)
|
||||||
{
|
{
|
||||||
if (sendData[proci] == zeroValue)
|
if (sendData[proci] == zeroValue)
|
||||||
{
|
{
|
||||||
// Do not send/recv empty data
|
// Do not send/recv empty data
|
||||||
}
|
}
|
||||||
else if (proci == myProci)
|
else if (proci != myProci)
|
||||||
{
|
|
||||||
// Do myself
|
|
||||||
recvData[proci] = sendData[proci];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Has data to send
|
// Has data to send
|
||||||
|
|
||||||
@ -604,7 +607,9 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// Probe and receive
|
// Probe and receive
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
MPI_Request barrierRequest;
|
MPI_Request barrierRequest;
|
||||||
|
|
||||||
@ -721,22 +726,29 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial: clear out everything
|
// Initial: clear out everything
|
||||||
const Type zeroValue = pTraits<Type>::zero;
|
|
||||||
recvBufs.clear();
|
recvBufs.clear();
|
||||||
|
|
||||||
if (!UPstream::is_parallel(comm))
|
// Fake send/recv for myself - parallel or non-parallel
|
||||||
{
|
{
|
||||||
// Do myself
|
|
||||||
const auto iter = sendBufs.find(myProci);
|
const auto iter = sendBufs.find(myProci);
|
||||||
if (iter.good() && (iter.val() != zeroValue))
|
if (iter.good())
|
||||||
{
|
{
|
||||||
// Do myself: insert_or_assign
|
// Do myself: insert_or_assign
|
||||||
recvBufs(iter.key()) = iter.val();
|
recvBufs(iter.key()) = iter.val();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UPstream::is_parallel(comm))
|
||||||
|
{
|
||||||
|
// Nothing left to do
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Setup sends
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
// Algorithm NBX: Nonblocking consensus
|
// Algorithm NBX: Nonblocking consensus
|
||||||
// Implementation like above, but sending map data.
|
// Implementation like above, but sending map data.
|
||||||
|
|
||||||
@ -752,7 +764,7 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Start nonblocking synchronous send to process dest
|
// Start nonblocking synchronous send to destination ranks
|
||||||
|
|
||||||
// Same as forAllConstIters()
|
// Same as forAllConstIters()
|
||||||
const auto endIter = sendBufs.cend();
|
const auto endIter = sendBufs.cend();
|
||||||
@ -761,19 +773,8 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
const label proci = iter.key();
|
const label proci = iter.key();
|
||||||
const auto& sendData = iter.val();
|
const auto& sendData = iter.val();
|
||||||
|
|
||||||
if (sendData == zeroValue)
|
if (proci != myProci && proci >= 0 && proci < numProc)
|
||||||
{
|
{
|
||||||
// Do not send/recv empty/zero data
|
|
||||||
}
|
|
||||||
else if (proci == myProci)
|
|
||||||
{
|
|
||||||
// Do myself: insert_or_assign
|
|
||||||
recvBufs(proci) = sendData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Has data to send
|
|
||||||
|
|
||||||
MPI_Issend
|
MPI_Issend
|
||||||
(
|
(
|
||||||
&sendData,
|
&sendData,
|
||||||
@ -788,7 +789,9 @@ void Foam::PstreamDetail::allToAllConsensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
// Probe and receive
|
// Probe and receive
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
MPI_Request barrierRequest;
|
MPI_Request barrierRequest;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user