Skip to content

Commit 3341e4b

Browse files
committed
BP5+groupbased: allow only up to 100 steps (openPMD#1732)
* BP5+groupbased: allow only up to 1000 steps * Configure this via env variable OPENPMD_BP5_GROUPENCODING_MAX_STEPS=1000 * Add documentation * Lower limit to 100
1 parent 6494854 commit 3341e4b

3 files changed

Lines changed: 99 additions & 17 deletions

File tree

docs/source/backends/adios2.rst

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,24 @@ The ADIOS2 SST engine for streaming can be picked by specifying the ending ``.ss
7878
The following environment variables control ADIOS2 I/O behavior at runtime.
7979
Fine-tuning these is especially useful when running at large scale.
8080

81-
===================================== ========== ================================================================================
82-
environment variable default description
83-
===================================== ========== ================================================================================
84-
``OPENPMD_ADIOS2_HAVE_PROFILING`` ``1`` Turns on/off profiling information right after a run.
85-
``OPENPMD_ADIOS2_HAVE_METADATA_FILE`` ``1`` Online creation of the adios journal file (``1``: yes, ``0``: no).
86-
``OPENPMD_ADIOS2_NUM_SUBSTREAMS`` ``0`` Number of files to be created, 0 indicates maximum number possible.
87-
``OPENPMD_ADIOS2_ENGINE`` ``File`` `ADIOS2 engine <https://adios2.readthedocs.io/en/latest/engines/engines.html>`_
88-
``OPENPMD_ADIOS2_PRETEND_ENGINE`` *empty* Pretend that an (unknown) ADIOS2 engine is in fact another one (also see the ``adios2.pretend_engine`` :ref:`parameter <backendconfig-adios2>`).
89-
``OPENPMD2_ADIOS2_USE_GROUP_TABLE`` ``0`` Use group table (see below)
90-
``OPENPMD_ADIOS2_STATS_LEVEL`` ``0`` whether to generate statistics for variables in ADIOS2. (``1``: yes, ``0``: no).
91-
``OPENPMD_ADIOS2_ASYNC_WRITE`` ``0`` ADIOS2 BP5 engine: 1 means setting "AsyncWrite" in ADIOS2 to "on". Flushes will go to the buffer by default (see ``preferred_flush_target``).
92-
``OPENPMD_ADIOS2_BP5_BufferChunkMB`` ``0`` ADIOS2 BP5 engine: applies when using either EveryoneWrites or EveryoneWritesSerial aggregation
93-
``OPENPMD_ADIOS2_BP5_MaxShmMB`` ``0`` ADIOS2 BP5 engine: applies when using TwoLevelShm aggregation
94-
``OPENPMD_ADIOS2_BP5_NumSubFiles`` ``0`` ADIOS2 BP5 engine: num of subfiles
95-
``OPENPMD_ADIOS2_BP5_NumAgg`` ``0`` ADIOS2 BP5 engine: num of aggregators
96-
``OPENPMD_ADIOS2_BP5_TypeAgg`` *empty* ADIOS2 BP5 engine: aggregation type. (EveryoneWrites, EveryoneWritesSerial, TwoLevelShm)
97-
===================================== ========== ================================================================================
81+
======================================= ========== ================================================================================
82+
environment variable default description
83+
======================================= ========== ================================================================================
84+
``OPENPMD_ADIOS2_HAVE_PROFILING`` ``1`` Turns on/off profiling information right after a run.
85+
``OPENPMD_ADIOS2_HAVE_METADATA_FILE`` ``1`` Online creation of the adios journal file (``1``: yes, ``0``: no).
86+
``OPENPMD_ADIOS2_NUM_SUBSTREAMS`` ``0`` Number of files to be created, 0 indicates maximum number possible.
87+
``OPENPMD_ADIOS2_ENGINE`` ``File`` `ADIOS2 engine <https://adios2.readthedocs.io/en/latest/engines/engines.html>`_
88+
``OPENPMD_ADIOS2_PRETEND_ENGINE`` *empty* Pretend that an (unknown) ADIOS2 engine is in fact another one (also see the ``adios2.pretend_engine`` :ref:`parameter <backendconfig-adios2>`).
89+
``OPENPMD2_ADIOS2_USE_GROUP_TABLE`` ``0`` Use group table (see below)
90+
``OPENPMD_ADIOS2_STATS_LEVEL`` ``0`` whether to generate statistics for variables in ADIOS2. (``1``: yes, ``0``: no).
91+
``OPENPMD_ADIOS2_ASYNC_WRITE`` ``0`` ADIOS2 BP5 engine: 1 means setting "AsyncWrite" in ADIOS2 to "on". Flushes will go to the buffer by default (see ``preferred_flush_target``).
92+
``OPENPMD_ADIOS2_BP5_BufferChunkMB`` ``0`` ADIOS2 BP5 engine: applies when using either EveryoneWrites or EveryoneWritesSerial aggregation
93+
``OPENPMD_ADIOS2_BP5_MaxShmMB`` ``0`` ADIOS2 BP5 engine: applies when using TwoLevelShm aggregation
94+
``OPENPMD_ADIOS2_BP5_NumSubFiles`` ``0`` ADIOS2 BP5 engine: num of subfiles
95+
``OPENPMD_ADIOS2_BP5_NumAgg`` ``0`` ADIOS2 BP5 engine: num of aggregators
96+
``OPENPMD_ADIOS2_BP5_TypeAgg`` *empty* ADIOS2 BP5 engine: aggregation type. (EveryoneWrites, EveryoneWritesSerial, TwoLevelShm)
97+
``OPENPMD_BP5_GROUPENCODING_MAX_STEPS`` ``100`` ADIOS2 BP5 engine: max number of allowed output steps in group encoding.
98+
======================================= ========== ================================================================================
9899

99100
Please refer to the `ADIOS2 documentation <https://adios2.readthedocs.io/en/latest/engines/engines.html>`_ for details on I/O tuning.
100101

@@ -315,6 +316,21 @@ Rather than by reallocation as in BP4, this is done by appending a new chunk, le
315316
The default is to flush to disk (except when specifying ``OPENPMD_ADIOS2_ASYNC_WRITE=1``), but the default ``preferred_flush_target`` can also be specified via JSON/TOML at the ``Series`` level.
316317

317318

319+
The BP5 engine is known to perform extremely bad for group-based encoding with many Iterations, since its design assumes that the metadata structure will be constant across output steps, while group-based encoding will add new variables and attributes for each Iteration.
320+
The openPMD-api will hence cancel operation after 100 written Iterations in group-based encoding for BP5.
321+
Experiments with PIConGPU show that the metadata (!) size grows from 10MB to 1GB when going from 100 to 1000 output steps in this setup.
322+
The environment variable ``OPENPMD_BP5_GROUPENCODING_MAX_STEPS`` may be used to change this limit (specifying the limit as ``0`` will disable the check).
323+
324+
For workarounds you may follow these guidelines:
325+
326+
* Use file encoding by including an expansion pattern ``%T`` in the filename.
327+
* If output to a single file is required, then:
328+
329+
* Use another ADIOS2 engine, recommended is the BP4 engine by selecting file ending ``.bp4``.
330+
* Use another openPMD backend, recommended is HDF5 by selecting file ending ``.h5``.
331+
* (experimental) use variable encoding with BP5, either by using the API call ``Series::setIterationEncoding(IterationEncoding::variableBased)`` / ``Series.iteration_encoding = Iteration_Encoding.variable_based`` or by using the JSON/TOML configuration ``{"iteration_encoding": "variable_based"}`` / ``iteration_encoding = "variable_based"``.
332+
Note that there is at this point no complete read support for variable-encoded outputs.
333+
318334

319335

320336
Known Issues

include/openPMD/IO/ADIOS/ADIOS2File.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "openPMD/IO/IOTask.hpp"
2626
#include "openPMD/IO/InvalidatableFile.hpp"
2727
#include "openPMD/config.hpp"
28+
#include <optional>
2829

2930
#if openPMD_HAVE_ADIOS2
3031
#include <adios2.h>
@@ -419,6 +420,7 @@ class ADIOS2File
419420
* implement this manually.
420421
*/
421422
size_t m_currentStep = 0;
423+
std::optional<size_t> m_max_steps_bp5 = std::make_optional<size_t>(100);
422424

423425
/*
424426
* ADIOS2 does not give direct access to its internal attribute and

src/IO/ADIOS/ADIOS2File.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,70 @@ AdvanceStatus ADIOS2File::advance(AdvanceMode mode)
12001200
case AdvanceMode::BEGINSTEP: {
12011201
adios2::StepStatus adiosStatus{};
12021202

1203+
auto check_bp5 = [&]() -> bool {
1204+
std::string engineType = getEngine().Type();
1205+
std::transform(
1206+
engineType.begin(),
1207+
engineType.end(),
1208+
engineType.begin(),
1209+
[](unsigned char c) { return std::tolower(c); });
1210+
return engineType == "bp5writer";
1211+
};
1212+
1213+
if (this->m_currentStep == 0)
1214+
{
1215+
int max_steps_from_env =
1216+
auxiliary::getEnvNum("OPENPMD_BP5_GROUPENCODING_MAX_STEPS", -1);
1217+
if (max_steps_from_env == 0)
1218+
{
1219+
m_max_steps_bp5 = std::nullopt;
1220+
}
1221+
else if (max_steps_from_env != -1)
1222+
{
1223+
m_max_steps_bp5 =
1224+
std::make_optional<size_t>(size_t(max_steps_from_env));
1225+
}
1226+
}
1227+
1228+
// Check some conditions on which to now cancel operation due to
1229+
// unwieldy metadata sizes in BP5 with group encoding
1230+
if (this->m_impl->m_handler->m_encoding ==
1231+
IterationEncoding::groupBased &&
1232+
this->m_max_steps_bp5.has_value() &&
1233+
this->m_currentStep >= *this->m_max_steps_bp5 &&
1234+
(this->m_mode == adios2::Mode::Write ||
1235+
this->m_mode == adios2::Mode::Append) &&
1236+
check_bp5())
1237+
{
1238+
throw error::OperationUnsupportedInBackend(
1239+
"ADIOS2",
1240+
R"(
1241+
Trying to create group-based output with more than )" +
1242+
std::to_string(*this->m_max_steps_bp5) +
1243+
R"( steps in BP5 engine.
1244+
As this engine is not adequate for group encoding, this will create immense
1245+
metadata sizes. For more context, check:
1246+
1247+
* https://github.com/openPMD/openPMD-api/discussions/1724
1248+
* https://github.com/openPMD/openPMD-api/issues/1457
1249+
1250+
Since this is likely to create unreadable data due to the sheer amount of
1251+
metadata, we will cancel the writer now.
1252+
Please consider using either of the following instead:
1253+
1254+
* file encoding (by including an expansion pattern %T in the filename)
1255+
* another ADIOS2 engine (e.g. by selecting file extension .bp4)
1256+
* another openPMD backend (e.g. by selecting file extension .h5)
1257+
* (experimental) variable encoding (e.g. by `Series::setIterationEncoding()`
1258+
or by the JSON config {"iteration_encoding": "variable_based"}).
1259+
Note that there is at this point no complete read support for variable-encoded
1260+
outputs.
1261+
1262+
Use the environment variable OPENPMD_BP5_GROUPENCODING_MAX_STEPS to adjust the
1263+
number of allowed steps. Set the value as 0 to disable this check.
1264+
Be aware of the performance implications described above.)");
1265+
}
1266+
12031267
if (streamStatus != StreamStatus::DuringStep)
12041268
{
12051269
adiosStatus = getEngine().BeginStep();

0 commit comments

Comments
 (0)