ENH: reduces buffer use / blocking in Ensight output

- reuse single component buffer within an Ensight output method.
  Use direct UPstream read/write to avoid Pstream char buffers

- replace blocking transfer with scheduled for Ensight cloud output
This commit is contained in:
Mark Olesen
2021-10-29 14:17:56 +02:00
parent 33ff3201ea
commit 048166c3d8
5 changed files with 302 additions and 216 deletions

View File

@ -50,6 +50,7 @@ SourceFiles
#include "ListOps.H"
#include "ListListOps.H"
#include "IndirectList.H"
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -260,17 +261,27 @@ labelList getPolysNFaces(const polyMesh& mesh, const labelUList& addr);
labelList getPolysNPointsPerFace(const polyMesh& mesh, const labelUList& addr);
//- Copy specified field component into a scalarField
// works for various lists types
//- Copy specified field component into a scalar buffer
//- works for various lists types. Must be adequately sized before calling
template<template<typename> class FieldContainer, class Type>
void copyComponent
(
scalarField& res,
List<scalar>& cmptBuffer,
const FieldContainer<Type>& input,
const direction cmpt
);
//- Write field content (component-wise)
template<template<typename> class FieldContainer, class Type>
void writeFieldContent
(
ensightFile& os,
const FieldContainer<Type>& fld,
bool parallel //!< Collective write?
);
//- Write coordinates (component-wise) for the given part
template<template<typename> class FieldContainer>
bool writeCoordinates

View File

@ -27,20 +27,27 @@ License
#include "ensightOutput.H"
#include "ensightPTraits.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<template<typename> class FieldContainer, class Type>
void Foam::ensightOutput::Detail::copyComponent
(
scalarField& res,
List<scalar>& cmptBuffer,
const FieldContainer<Type>& input,
const direction cmpt
)
{
res.resize(input.size());
if (cmptBuffer.size() < input.size())
{
FatalErrorInFunction
<< "Component buffer too small: "
<< cmptBuffer.size() << " < " << input.size() << nl
<< exit(FatalError);
}
auto iter = res.begin();
auto iter = cmptBuffer.begin();
for (const Type& val : input)
{
@ -50,6 +57,80 @@ void Foam::ensightOutput::Detail::copyComponent
}
template<template<typename> class FieldContainer, class Type>
void Foam::ensightOutput::Detail::writeFieldContent
(
ensightFile& os,
const FieldContainer<Type>& fld,
bool parallel
)
{
// already checked prior to calling, but extra safety
parallel = parallel && Pstream::parRun();
// Size information (offsets are irrelevant)
globalIndex procAddr;
if (parallel)
{
procAddr.reset(UPstream::listGatherValues<label>(fld.size()));
}
else
{
// Master size
procAddr.reset(labelList(Foam::one{}, fld.size()));
}
if (Pstream::master())
{
DynamicList<scalar> cmptBuffer(procAddr.maxSize());
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt = ensightPTraits<Type>::componentOrder[d];
// Write master data
cmptBuffer.resize_nocopy(procAddr.localSize(0));
copyComponent(cmptBuffer, fld, cmpt);
os.writeList(cmptBuffer);
// Receive and write
for (const label proci : procAddr.subProcs())
{
cmptBuffer.resize_nocopy(procAddr.localSize(proci));
UIPstream::read
(
UPstream::commsTypes::scheduled,
proci,
cmptBuffer.data_bytes(),
cmptBuffer.size_bytes()
);
os.writeList(cmptBuffer);
}
}
}
else if (parallel)
{
// Send
List<scalar> cmptBuffer(fld.size());
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt = ensightPTraits<Type>::componentOrder[d];
copyComponent(cmptBuffer, fld, cmpt);
UOPstream::write
(
UPstream::commsTypes::scheduled,
Pstream::masterNo(),
cmptBuffer.cdata_bytes(),
cmptBuffer.size_bytes()
);
}
}
}
template<template<typename> class FieldContainer>
bool Foam::ensightOutput::Detail::writeCoordinates
(
@ -63,57 +144,13 @@ bool Foam::ensightOutput::Detail::writeCoordinates
{
parallel = parallel && Pstream::parRun();
const IntRange<int> senders =
(
parallel
? Pstream::subProcs()
: IntRange<int>()
);
// Using manual copyComponent(...) instead of fld.component() to support
// indirect lists etc.
scalarField send(fld.size());
if (Pstream::master())
{
os.beginPart(partId, partName);
os.beginCoordinates(nPoints);
for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
{
// Main
copyComponent(send, fld, cmpt);
os.writeList(send);
// Others
for (const int proci : senders)
{
IPstream fromOther(Pstream::commsTypes::scheduled, proci);
scalarField recv(fromOther);
os.writeList(recv);
}
}
}
else if (senders)
{
// Send from other (parallel)
for (direction cmpt=0; cmpt < point::nComponents; ++cmpt)
{
copyComponent(send, fld, cmpt);
OPstream toMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
toMaster << send;
}
}
ensightOutput::Detail::writeFieldContent(os, fld, parallel);
return true;
}
@ -130,14 +167,6 @@ bool Foam::ensightOutput::Detail::writeFieldComponents
{
parallel = parallel && Pstream::parRun();
const IntRange<int> senders =
(
parallel
? Pstream::subProcs()
: IntRange<int>()
);
// Preliminary checks
{
bool hasField = !fld.empty();
@ -152,52 +181,12 @@ bool Foam::ensightOutput::Detail::writeFieldComponents
}
// Using manual copyComponent(...) instead of fld.component() to support
// indirect lists etc.
scalarField send(fld.size());
if (Pstream::master())
{
os.writeKeyword(key);
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt = ensightPTraits<Type>::componentOrder[d];
// Main
copyComponent(send, fld, cmpt);
os.writeList(send);
// Others
for (const int proci : senders)
{
IPstream fromOther(Pstream::commsTypes::scheduled, proci);
scalarField recv(fromOther);
os.writeList(recv);
}
}
}
else if (senders)
{
// Send from other (parallel)
for (direction d=0; d < pTraits<Type>::nComponents; ++d)
{
const direction cmpt = ensightPTraits<Type>::componentOrder[d];
copyComponent(send, fld, cmpt);
OPstream toMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
toMaster << send;
}
}
ensightOutput::Detail::writeFieldContent(os, fld, parallel);
return true;
}
@ -294,6 +283,7 @@ bool Foam::ensightOutput::Detail::writeFaceLocalField
<< exit(FatalError);
}
if (Pstream::master())
{
os.beginPart(part.index());
@ -345,6 +335,7 @@ bool Foam::ensightOutput::writeField
if (!hasField) return false;
}
if (Pstream::master())
{
os.beginPart(part.index());