Skip to content

Commit 5e17686

Browse files
committed
Add RoundRobinOfSourceRanks strategy
1 parent b45ae23 commit 5e17686

File tree

4 files changed

+79
-5
lines changed

4 files changed

+79
-5
lines changed

include/openPMD/ChunkInfo.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "openPMD/Dataset.hpp" // Offset, Extent
2626
#include "openPMD/benchmark/mpi/BlockSlicer.hpp"
27+
#include <memory>
2728

2829
#if openPMD_HAVE_MPI
2930
#include <mpi.h>
@@ -224,6 +225,16 @@ namespace chunk_assignment
224225
virtual std::unique_ptr<Strategy> clone() const override;
225226
};
226227

228+
struct RoundRobinOfSourceRanks : Strategy
229+
{
230+
Assignment assign(
231+
PartialAssignment,
232+
RankMeta const &in,
233+
RankMeta const &out) override;
234+
235+
virtual std::unique_ptr<Strategy> clone() const override;
236+
};
237+
227238
/**
228239
* @brief Strategy that assigns chunks to be read by processes within
229240
* the same host that produced the chunk.

src/ChunkInfo.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
#include "openPMD/auxiliary/Mpi.hpp"
2525

2626
#include <algorithm> // std::sort
27+
#include <deque>
2728
#include <iostream>
29+
#include <iterator>
2830
#include <list>
2931
#include <map>
3032
#include <optional>
33+
#include <set>
3134
#include <utility>
3235

3336
#ifdef _WIN32
@@ -195,10 +198,10 @@ namespace chunk_assignment
195198

196199
namespace
197200
{
198-
std::map<std::string, std::list<unsigned int> >
201+
std::map<std::string, std::list<unsigned int>>
199202
ranksPerHost(RankMeta const &rankMeta)
200203
{
201-
std::map<std::string, std::list<unsigned int> > res;
204+
std::map<std::string, std::list<unsigned int>> res;
202205
for (auto const &pair : rankMeta)
203206
{
204207
auto &list = res[pair.second];
@@ -294,6 +297,44 @@ namespace chunk_assignment
294297
return std::unique_ptr<Strategy>(new RoundRobin);
295298
}
296299

300+
Assignment RoundRobinOfSourceRanks::assign(
301+
PartialAssignment partialAssignment,
302+
RankMeta const &, // ignored parameter
303+
RankMeta const &out)
304+
{
305+
std::map<unsigned int, std::deque<WrittenChunkInfo>>
306+
sortSourceChunksBySourceRank;
307+
for (auto &chunk : partialAssignment.notAssigned)
308+
{
309+
auto sourceID = chunk.sourceID;
310+
sortSourceChunksBySourceRank[sourceID].push_back(std::move(chunk));
311+
}
312+
partialAssignment.notAssigned.clear();
313+
auto source_it = sortSourceChunksBySourceRank.begin();
314+
auto sink_it = out.begin();
315+
for (; source_it != sortSourceChunksBySourceRank.end();
316+
++source_it, ++sink_it)
317+
{
318+
if (sink_it == out.end())
319+
{
320+
sink_it = out.begin();
321+
}
322+
auto &chunks_go_here = partialAssignment.assigned[sink_it->first];
323+
chunks_go_here.reserve(
324+
partialAssignment.assigned.size() + source_it->second.size());
325+
for (auto &chunk : source_it->second)
326+
{
327+
chunks_go_here.push_back(std::move(chunk));
328+
}
329+
}
330+
return partialAssignment.assigned;
331+
}
332+
333+
std::unique_ptr<Strategy> RoundRobinOfSourceRanks::clone() const
334+
{
335+
return std::unique_ptr<Strategy>(new RoundRobinOfSourceRanks);
336+
}
337+
297338
ByHostname::ByHostname(std::unique_ptr<Strategy> withinNode)
298339
: m_withinNode(std::move(withinNode))
299340
{}
@@ -332,7 +373,7 @@ namespace chunk_assignment
332373
// the ranks are the source ranks
333374

334375
// which ranks live on host <string> in the sink?
335-
std::map<std::string, std::list<unsigned int> > ranksPerHostSink =
376+
std::map<std::string, std::list<unsigned int>> ranksPerHostSink =
336377
ranksPerHost(out);
337378
for (auto &chunkGroup : chunkGroups)
338379
{

src/binding/python/ChunkInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ void init_Chunk(py::module &m)
298298
}));
299299

300300
py::class_<RoundRobin, Strategy>(m, "RoundRobin").def(py::init<>());
301+
py::class_<RoundRobinOfSourceRanks, Strategy>(m, "RoundRobinOfSourceRanks")
302+
.def(py::init<>());
301303

302304
py::class_<ByHostname, PartialStrategy>(m, "ByHostname")
303305
.def(

test/ParallelIOTest.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Running this test in parallel with MPI requires MPI::Init.
22
* To guarantee a correct call to Init, launch the tests manually.
33
*/
4+
#include "openPMD/ChunkInfo.hpp"
45
#include "openPMD/IO/ADIOS/macros.hpp"
56
#include "openPMD/IO/Access.hpp"
67
#include "openPMD/auxiliary/Environment.hpp"
@@ -2213,11 +2214,13 @@ void adios2_chunk_distribution()
22132214
series.setRankTable(writingRanksHostnames.at(mpi_rank));
22142215

22152216
auto E_x = series.iterations[0].meshes["E"]["x"];
2216-
openPMD::Dataset ds(openPMD::Datatype::INT, {unsigned(mpi_size), 10});
2217+
openPMD::Dataset ds(
2218+
openPMD::Datatype::INT, {unsigned(mpi_size * 2), 10});
22172219
E_x.resetDataset(ds);
22182220
std::vector<int> data(10, 0);
22192221
std::iota(data.begin(), data.end(), 0);
2220-
E_x.storeChunk(data, {unsigned(mpi_rank), 0}, {1, 10});
2222+
E_x.storeChunk(data, {unsigned(mpi_rank * 2), 0}, {1, 10});
2223+
E_x.storeChunk(data, {unsigned(mpi_rank * 2 + 1), 0}, {1, 10});
22212224
series.flush();
22222225
}
22232226

@@ -2276,6 +2279,23 @@ void adios2_chunk_distribution()
22762279
byHostnamePartialAssignment.notAssigned,
22772280
rankMetaIn);
22782281

2282+
/*
2283+
* Same as above, but use RoundRobinOfSourceRanks this time, a strategy
2284+
* which ensures that each source rank's data is uniquely mapped to one
2285+
* sink rank. Needed in some domains.
2286+
*/
2287+
ByHostname byHostname2(std::make_unique<RoundRobinOfSourceRanks>());
2288+
auto byHostnamePartialAssignment2 =
2289+
byHostname2.assign(chunkTable, rankMetaIn, readingRanksHostnames);
2290+
printAssignment(
2291+
"HOSTNAME2, ASSIGNED",
2292+
byHostnamePartialAssignment2.assigned,
2293+
readingRanksHostnames);
2294+
printChunktable(
2295+
"HOSTNAME2, LEFTOVER",
2296+
byHostnamePartialAssignment2.notAssigned,
2297+
rankMetaIn);
2298+
22792299
/*
22802300
* Assign chunks by hostnames, once more.
22812301
* This time, apply a secondary distribution strategy to assign

0 commit comments

Comments
 (0)