ENH: support UOPstream and UIPstream as formatters with an external buffer
- can split serialise/de-serialise and send/recv actions
This commit is contained in:
parent
70d310329c
commit
add61ca273
3
applications/test/parallel-nbx2/Make/files
Normal file
3
applications/test/parallel-nbx2/Make/files
Normal file
@ -0,0 +1,3 @@
|
||||
Test-parallel-nbx2.C
|
||||
|
||||
EXE = $(FOAM_USER_APPBIN)/Test-parallel-nbx2
|
2
applications/test/parallel-nbx2/Make/options
Normal file
2
applications/test/parallel-nbx2/Make/options
Normal file
@ -0,0 +1,2 @@
|
||||
/* EXE_INC = */
|
||||
/* EXE_LIBS = */
|
227
applications/test/parallel-nbx2/Test-parallel-nbx2.C
Normal file
227
applications/test/parallel-nbx2/Test-parallel-nbx2.C
Normal file
@ -0,0 +1,227 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Application
|
||||
Test-parallel-nbx2
|
||||
|
||||
Description
|
||||
Test for send/receive data
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "List.H"
|
||||
#include "argList.H"
|
||||
#include "Time.H"
|
||||
#include "IPstream.H"
|
||||
#include "OPstream.H"
|
||||
#include "IOstreams.H"
|
||||
#include "Random.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
argList::noCheckProcessorDirectories();
|
||||
argList::addBoolOption("non-blocking", "Test with non-blocking receives");
|
||||
|
||||
#include "setRootCase.H"
|
||||
|
||||
const bool optNonBlocking = args.found("non-blocking");
|
||||
|
||||
if (!Pstream::parRun())
|
||||
{
|
||||
Info<< "\nWarning: not parallel - skipping further tests\n" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Info<< "\nTesting with non-blocking receives: " << optNonBlocking << nl;
|
||||
|
||||
|
||||
const int tag = (UPstream::msgType() + 314159);
|
||||
const label comm = UPstream::worldComm;
|
||||
|
||||
Random rnd(20*UPstream::myProcNo());
|
||||
|
||||
// Looks a bit like a DIY PstreamBuffers...
|
||||
Map<DynamicList<char>> sendBufs;
|
||||
Map<DynamicList<char>> recvBufs;
|
||||
|
||||
DynamicList<UPstream::Request> sendRequests(10);
|
||||
DynamicList<UPstream::Request> recvRequests(10);
|
||||
|
||||
if (!Pstream::master())
|
||||
{
|
||||
// Send some random length to master
|
||||
|
||||
const int toProci = UPstream::masterNo();
|
||||
|
||||
label len = rnd.position<label>(10, 20);
|
||||
if (UPstream::myProcNo() && (UPstream::myProcNo() % 3) == 0) len = 0;
|
||||
|
||||
scalarField fld(len, scalar(UPstream::myProcNo()));
|
||||
|
||||
// Format for sending
|
||||
if (!fld.empty())
|
||||
{
|
||||
auto& buf = sendBufs(toProci);
|
||||
UOPstream os(buf);
|
||||
os << fld;
|
||||
}
|
||||
|
||||
// Start nonblocking synchronous send to process dest
|
||||
|
||||
if (sendBufs.found(toProci) && !sendBufs[toProci].empty())
|
||||
{
|
||||
Pout<< "send: [" << sendBufs[toProci].size() << " bytes] "
|
||||
<< flatOutput(fld) << endl;
|
||||
|
||||
// Has data to send
|
||||
UOPstream::write
|
||||
(
|
||||
sendRequests.emplace_back(),
|
||||
UPstream::masterNo(),
|
||||
sendBufs[toProci],
|
||||
tag,
|
||||
comm,
|
||||
UPstream::sendModes::sync
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Probe and receive
|
||||
|
||||
UPstream::Request barrierReq;
|
||||
|
||||
for (bool barrier_active = false, done = false; !done; /*nil*/)
|
||||
{
|
||||
std::pair<int, int> probed =
|
||||
UPstream::probeMessage
|
||||
(
|
||||
UPstream::commsTypes::nonBlocking,
|
||||
-1, // ANY_SOURCE
|
||||
tag,
|
||||
comm
|
||||
);
|
||||
|
||||
if (probed.second > 0)
|
||||
{
|
||||
// Message found and had size: receive it
|
||||
|
||||
const label proci = probed.first;
|
||||
const label count = probed.second;
|
||||
|
||||
if (optNonBlocking)
|
||||
{
|
||||
recvBufs(proci).resize_nocopy(count);
|
||||
|
||||
// Non-blocking read
|
||||
UIPstream::read
|
||||
(
|
||||
recvRequests.emplace_back(),
|
||||
proci,
|
||||
recvBufs[proci],
|
||||
tag,
|
||||
comm
|
||||
);
|
||||
// Pout<< "Done: "
|
||||
// << UPstream::finishedRequests(recvRequests) << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
IPstream is
|
||||
(
|
||||
UPstream::commsTypes::scheduled,
|
||||
probed.first,
|
||||
probed.second,
|
||||
tag,
|
||||
comm
|
||||
);
|
||||
|
||||
scalarField fld(is);
|
||||
|
||||
Info<< "from [" << probed.first
|
||||
<< "] : " << flatOutput(fld) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (barrier_active)
|
||||
{
|
||||
// Test barrier for completion
|
||||
if (UPstream::finishedRequest(barrierReq))
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if all sends have arrived
|
||||
if (UPstream::finishedRequests(sendRequests))
|
||||
{
|
||||
UPstream::barrier(comm, &barrierReq);
|
||||
barrier_active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pout<< "pending receives: " << recvRequests.size() << endl;
|
||||
|
||||
// Wait for receives to complete
|
||||
UPstream::waitRequests(recvRequests);
|
||||
|
||||
// It could be we need this type of synchronization point
|
||||
// if the receives are non-blocking
|
||||
if (optNonBlocking)
|
||||
{
|
||||
UPstream::barrier(comm);
|
||||
}
|
||||
|
||||
if (!recvBufs.empty())
|
||||
{
|
||||
Pout<< "Receives from: " << flatOutput(recvBufs.sortedToc()) << endl;
|
||||
|
||||
forAllConstIters(recvBufs, iter)
|
||||
{
|
||||
Pout<< "proc:" << iter.key() << " len:" << iter.val().size() << nl;
|
||||
|
||||
if (!iter.val().empty())
|
||||
{
|
||||
UIPstream is(iter.val());
|
||||
scalarField fld(is);
|
||||
|
||||
Pout<< "recv:" << iter.key()
|
||||
<< " : " << flatOutput(fld) << nl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info<< "\nEnd\n" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
Copyright (C) 2022-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -75,13 +75,12 @@ Foam::IPBstream::IPBstream
|
||||
commsType,
|
||||
fromProcNo,
|
||||
Pstream::transferBuf_,
|
||||
transferBufPosition_,
|
||||
UIPstreamBase::storedRecvBufPos_, // Internal only
|
||||
tag,
|
||||
comm,
|
||||
false, // Do not clear Pstream::transferBuf_ if at end
|
||||
fmt
|
||||
),
|
||||
transferBufPosition_(0)
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -56,11 +56,6 @@ class IPstream
|
||||
public Pstream,
|
||||
public UIPstream
|
||||
{
|
||||
// Private Data
|
||||
|
||||
//- Receive index into Pstream::transferBuf_
|
||||
label transferBufPosition_;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
@ -90,11 +85,6 @@ class IPBstream
|
||||
public Pstream,
|
||||
public UIPBstream
|
||||
{
|
||||
// Private Data
|
||||
|
||||
//- Receive index into Pstream::transferBuf_
|
||||
label transferBufPosition_;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
Copyright (C) 2022-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -91,6 +91,16 @@ Foam::UIPstream::UIPstream(const int fromProcNo, PstreamBuffers& buffers)
|
||||
}
|
||||
|
||||
|
||||
Foam::UIPstream::UIPstream
|
||||
(
|
||||
const DynamicList<char>& recvBuf,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
UIPstreamBase(recvBuf, fmt)
|
||||
{}
|
||||
|
||||
|
||||
Foam::IPstream::IPstream
|
||||
(
|
||||
const UPstream::commsTypes commsType,
|
||||
@ -107,13 +117,12 @@ Foam::IPstream::IPstream
|
||||
commsType,
|
||||
fromProcNo,
|
||||
Pstream::transferBuf_,
|
||||
transferBufPosition_,
|
||||
UIPstreamBase::storedRecvBufPos_, // Internal only
|
||||
tag,
|
||||
comm,
|
||||
false, // Do not clear Pstream::transferBuf_ if at end
|
||||
fmt
|
||||
),
|
||||
transferBufPosition_(0)
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -52,6 +52,16 @@ Foam::UOPstream::UOPstream(const int toProcNo, PstreamBuffers& buffers)
|
||||
{}
|
||||
|
||||
|
||||
Foam::UOPstream::UOPstream
|
||||
(
|
||||
DynamicList<char>& sendBuf,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
UOPstreamBase(sendBuf, fmt)
|
||||
{}
|
||||
|
||||
|
||||
Foam::OPstream::OPstream
|
||||
(
|
||||
const UPstream::commsTypes commsType,
|
||||
|
@ -85,19 +85,30 @@ protected:
|
||||
|
||||
// Protected Data
|
||||
|
||||
int fromProcNo_;
|
||||
|
||||
DynamicList<char>& recvBuf_;
|
||||
|
||||
label& recvBufPos_;
|
||||
//- Source rank for the data
|
||||
const int fromProcNo_;
|
||||
|
||||
//- Message tag for communication
|
||||
const int tag_;
|
||||
|
||||
const label comm_;
|
||||
//- The communicator index
|
||||
const int comm_;
|
||||
|
||||
//- The message size, read on bufferIPCrecv or set directly
|
||||
int messageSize_;
|
||||
|
||||
//- Receive position in buffer data, if ony
|
||||
//- If there is no external location for recvBufPos_
|
||||
label storedRecvBufPos_;
|
||||
|
||||
//- Clear the receive buffer on termination (in the destructor)
|
||||
const bool clearAtEnd_;
|
||||
|
||||
int messageSize_;
|
||||
//- Reference to the receive buffer data
|
||||
DynamicList<char>& recvBuf_;
|
||||
|
||||
//- Reference to the receive position in buffer data
|
||||
label& recvBufPos_;
|
||||
|
||||
|
||||
// Protected Constructors
|
||||
@ -120,10 +131,17 @@ protected:
|
||||
//- Construct given buffers
|
||||
UIPstreamBase(const int fromProcNo, PstreamBuffers& buffers);
|
||||
|
||||
//- Construct for an externally obtained buffer.
|
||||
// The parameter is allowed to be const (since reading will not
|
||||
// affect it), but must reference a concrete variable.
|
||||
UIPstreamBase
|
||||
(
|
||||
const DynamicList<char>& receiveBuf,
|
||||
IOstreamOption::streamFormat fmt
|
||||
);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
//- Destructor. Optionally clears external receive buffer.
|
||||
virtual ~UIPstreamBase();
|
||||
|
||||
@ -238,6 +256,16 @@ public:
|
||||
//- Construct given buffers
|
||||
UIPstream(const int fromProcNo, PstreamBuffers& buffers);
|
||||
|
||||
//- Construct for reading from a standalone buffer that has
|
||||
//- been obtained externally by the caller.
|
||||
// The parameter is allowed to be const (since reading will not
|
||||
// affect it), but must reference a concrete variable.
|
||||
explicit UIPstream
|
||||
(
|
||||
const DynamicList<char>& recvBuf,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~UIPstream() = default;
|
||||
|
@ -159,12 +159,13 @@ Foam::UIPstreamBase::UIPstreamBase
|
||||
UPstream(commsType),
|
||||
Istream(fmt),
|
||||
fromProcNo_(fromProcNo),
|
||||
recvBuf_(receiveBuf),
|
||||
recvBufPos_(receiveBufPosition),
|
||||
tag_(tag),
|
||||
comm_(comm),
|
||||
messageSize_(0),
|
||||
storedRecvBufPos_(0),
|
||||
clearAtEnd_(clearAtEnd),
|
||||
messageSize_(0)
|
||||
recvBuf_(receiveBuf),
|
||||
recvBufPos_(receiveBufPosition)
|
||||
{
|
||||
setOpened();
|
||||
setGood();
|
||||
@ -180,12 +181,13 @@ Foam::UIPstreamBase::UIPstreamBase
|
||||
UPstream(buffers.commsType()),
|
||||
Istream(buffers.format()),
|
||||
fromProcNo_(fromProcNo),
|
||||
recvBuf_(buffers.accessRecvBuffer(fromProcNo)),
|
||||
recvBufPos_(buffers.accessRecvPosition(fromProcNo)),
|
||||
tag_(buffers.tag()),
|
||||
comm_(buffers.comm()),
|
||||
messageSize_(0),
|
||||
storedRecvBufPos_(0),
|
||||
clearAtEnd_(buffers.allowClearRecv()),
|
||||
messageSize_(0)
|
||||
recvBuf_(buffers.accessRecvBuffer(fromProcNo)),
|
||||
recvBufPos_(buffers.accessRecvPosition(fromProcNo))
|
||||
{
|
||||
if
|
||||
(
|
||||
@ -205,6 +207,32 @@ Foam::UIPstreamBase::UIPstreamBase
|
||||
}
|
||||
|
||||
|
||||
Foam::UIPstreamBase::UIPstreamBase
|
||||
(
|
||||
const DynamicList<char>& receiveBuf,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
UPstream(UPstream::commsTypes::nonBlocking), // placeholder
|
||||
Istream(fmt),
|
||||
fromProcNo_(UPstream::masterNo()), // placeholder
|
||||
tag_(UPstream::msgType()), // placeholder
|
||||
comm_(UPstream::selfComm), // placeholder
|
||||
messageSize_(receiveBuf.size()), // Message == buffer
|
||||
storedRecvBufPos_(0),
|
||||
clearAtEnd_(false), // Do not clear recvBuf if at end!!
|
||||
recvBuf_
|
||||
(
|
||||
// The receive buffer is never modified with this code path
|
||||
const_cast<DynamicList<char>&>(receiveBuf)
|
||||
),
|
||||
recvBufPos_(storedRecvBufPos_) // Internal reference
|
||||
{
|
||||
setOpened();
|
||||
setGood();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::UIPstreamBase::~UIPstreamBase()
|
||||
@ -517,8 +545,7 @@ void Foam::UIPstreamBase::print(Ostream& os) const
|
||||
{
|
||||
os << "Reading from processor " << fromProcNo_
|
||||
<< " using communicator " << comm_
|
||||
<< " and tag " << tag_
|
||||
<< Foam::endl;
|
||||
<< " and tag " << tag_ << Foam::endl;
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,16 +92,21 @@ protected:
|
||||
|
||||
// Protected Data
|
||||
|
||||
int toProcNo_;
|
||||
|
||||
DynamicList<char>& sendBuf_;
|
||||
//- Destination rank for the data
|
||||
const int toProcNo_;
|
||||
|
||||
//- Message tag for communication
|
||||
const int tag_;
|
||||
|
||||
const label comm_;
|
||||
//- The communicator index
|
||||
const int comm_;
|
||||
|
||||
//- Call bufferIPCsend on termination (in the destructor)
|
||||
const bool sendAtDestruct_;
|
||||
|
||||
//- Reference to the send buffer data
|
||||
DynamicList<char>& sendBuf_;
|
||||
|
||||
|
||||
// Protected Constructors
|
||||
|
||||
@ -122,6 +127,12 @@ protected:
|
||||
//- Construct given buffers
|
||||
UOPstreamBase(const int toProcNo, PstreamBuffers& buffers);
|
||||
|
||||
//- Construct for externally obtained buffers
|
||||
UOPstreamBase
|
||||
(
|
||||
DynamicList<char>& sendBuf,
|
||||
IOstreamOption::streamFormat fmt
|
||||
);
|
||||
|
||||
public:
|
||||
|
||||
@ -310,6 +321,14 @@ public:
|
||||
//- Construct given buffers
|
||||
UOPstream(const int toProcNo, PstreamBuffers& buffers);
|
||||
|
||||
//- Construct for writing into a standalone buffer.
|
||||
//- Data transfer is handled externally by the caller.
|
||||
explicit UOPstream
|
||||
(
|
||||
DynamicList<char>& sendBuf,
|
||||
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
|
||||
);
|
||||
|
||||
|
||||
//- Destructor, usually sends buffer on destruct.
|
||||
virtual ~UOPstream();
|
||||
|
@ -145,10 +145,10 @@ Foam::UOPstreamBase::UOPstreamBase
|
||||
UPstream(commsType),
|
||||
Ostream(fmt),
|
||||
toProcNo_(toProcNo),
|
||||
sendBuf_(sendBuf),
|
||||
tag_(tag),
|
||||
comm_(comm),
|
||||
sendAtDestruct_(sendAtDestruct)
|
||||
sendAtDestruct_(sendAtDestruct),
|
||||
sendBuf_(sendBuf)
|
||||
{
|
||||
setOpened();
|
||||
setGood();
|
||||
@ -160,16 +160,36 @@ Foam::UOPstreamBase::UOPstreamBase(const int toProcNo, PstreamBuffers& buffers)
|
||||
UPstream(buffers.commsType()),
|
||||
Ostream(buffers.format()),
|
||||
toProcNo_(toProcNo),
|
||||
sendBuf_(buffers.accessSendBuffer(toProcNo)),
|
||||
tag_(buffers.tag()),
|
||||
comm_(buffers.comm()),
|
||||
sendAtDestruct_(buffers.commsType() != UPstream::commsTypes::nonBlocking)
|
||||
sendAtDestruct_(buffers.commsType() != UPstream::commsTypes::nonBlocking),
|
||||
sendBuf_(buffers.accessSendBuffer(toProcNo))
|
||||
{
|
||||
setOpened();
|
||||
setGood();
|
||||
}
|
||||
|
||||
|
||||
Foam::UOPstreamBase::UOPstreamBase
|
||||
(
|
||||
DynamicList<char>& sendBuf,
|
||||
IOstreamOption::streamFormat fmt
|
||||
)
|
||||
:
|
||||
UPstream(UPstream::commsTypes::nonBlocking), // placeholder
|
||||
Ostream(fmt),
|
||||
toProcNo_(UPstream::masterNo()), // placeholder
|
||||
tag_(UPstream::msgType()), // placeholder
|
||||
comm_(UPstream::selfComm), // placeholder
|
||||
sendAtDestruct_(false), // Never sendAtDestruct!!
|
||||
sendBuf_(sendBuf)
|
||||
{
|
||||
sendBuf_.clear(); // Overwrite into buffer
|
||||
setOpened();
|
||||
setGood();
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::UOPstreamBase::~UOPstreamBase()
|
||||
@ -394,8 +414,8 @@ void Foam::UOPstreamBase::rewind()
|
||||
|
||||
void Foam::UOPstreamBase::print(Ostream& os) const
|
||||
{
|
||||
os << "Writing from processor " << toProcNo_
|
||||
<< " to processor " << myProcNo() << " in communicator " << comm_
|
||||
os << "Writing to processor " << toProcNo_
|
||||
<< " from processor " << myProcNo() << " in communicator " << comm_
|
||||
<< " and tag " << tag_ << Foam::endl;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user