Skip to content

Commit d98599b

Browse files
committed
Cleanup
1 parent b69abc5 commit d98599b

File tree

3 files changed

+112
-56
lines changed

3 files changed

+112
-56
lines changed

include/openPMD/IO/ADIOS/ADIOS2PreloadAttributes.hpp

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2020-2021 Franz Poeschel
1+
/* Copyright 2020-2025 Franz Poeschel
22
*
33
* This file is part of openPMD-api.
44
*
@@ -20,16 +20,16 @@
2020
*/
2121
#pragma once
2222

23-
#include "openPMD/auxiliary/Variant.hpp"
2423
#include "openPMD/config.hpp"
25-
#include <optional>
26-
#include <variant>
2724
#if openPMD_HAVE_ADIOS2
2825

2926
#include <adios2.h>
3027
#include <map>
28+
#include <optional>
29+
#include <variant>
3130

3231
#include "openPMD/Datatype.hpp"
32+
#include "openPMD/auxiliary/Variant.hpp"
3333

3434
namespace openPMD::detail
3535
{
@@ -46,24 +46,21 @@ struct AttributeWithShape
4646
};
4747

4848
/**
49-
* Class that is responsible for scheduling and buffering openPMD attribute
50-
* loads from ADIOS2, if using ADIOS variables to store openPMD attributes.
49+
* Class that is responsible for buffering loaded openPMD attributes from
50+
* ADIOS2.
5151
*
52-
* Reasoning: ADIOS variables can be of any shape and size, and ADIOS cannot
53-
* know which variables to buffer. While it will preload and buffer scalar
54-
* variables, openPMD also stores vector-type attributes which are not
55-
* preloaded. Since in Streaming setups, every variable load requires full
56-
* communication back to the writer, this can quickly become very expensive.
57-
* Hence, do this manually.
52+
* This is used for reading variable-encoded files in random-access mode.
53+
* Random-access mode in ADIOS2 has the restriction that modifiable attributes
54+
* can only be recovered in normal non-random-access read mode, so we open the
55+
* file first in that mode, store all attribute metadata in this class and only
56+
* then continue in random-access mode.
5857
*
5958
*/
6059
class PreloadAdiosAttributes
6160
{
6261
public:
6362
/**
64-
* Internally used struct to store meta information on a buffered
65-
* attribute. Public for simplicity (helper struct in the
66-
* implementation uses it).
63+
* Meta information on a buffered attribute.
6764
*/
6865
struct AttributeLocation
6966
{
@@ -106,11 +103,7 @@ class PreloadAdiosAttributes
106103
PreloadAdiosAttributes &operator=(PreloadAdiosAttributes &&other) = default;
107104

108105
/**
109-
* @brief Schedule attributes for preloading.
110-
*
111-
* This will invalidate all previously buffered attributes.
112-
* This will *not* flush the scheduled loads. This way, attributes can
113-
* be loaded along with the next adios2::Engine flush.
106+
* @brief Load attributes from the current step into the buffer.
114107
*
115108
* @param IO
116109
*/
@@ -131,45 +124,27 @@ class PreloadAdiosAttributes
131124

132125
Datatype attributeType(std::string const &name) const;
133126

134-
std::map<std::string, AttributeLocation> const &
135-
availableAttributes() const &
136-
{
137-
return m_offsets;
138-
}
127+
std::map<std::string, AttributeLocation> const &availableAttributes() const;
139128
};
140129

141130
template <typename T>
142131
struct AttributeWithShapeAndResource : AttributeWithShape<T>
143132
{
144-
AttributeWithShapeAndResource(AttributeWithShape<T> parent)
145-
: AttributeWithShape<T>(std::move(parent))
146-
{}
133+
AttributeWithShapeAndResource(AttributeWithShape<T> parent);
147134
AttributeWithShapeAndResource(
148135
size_t len_in,
149136
T const *data_in,
150-
std::optional<std::vector<T>> resource_in)
151-
: AttributeWithShape<T>{len_in, data_in}
152-
, resource{std::move(resource_in)}
153-
{}
154-
explicit AttributeWithShapeAndResource() : AttributeWithShape<T>(0, nullptr)
155-
{}
156-
AttributeWithShapeAndResource(adios2::Attribute<T> attr)
157-
{
158-
if (!attr)
159-
{
160-
this->data = nullptr;
161-
this->len = 0;
162-
return;
163-
}
164-
auto vec = attr.Data();
165-
this->len = vec.size();
166-
this->data = vec.data();
167-
this->resource = std::move(vec);
168-
}
169-
operator bool() const
170-
{
171-
return this->data;
172-
}
137+
std::optional<std::vector<T>> resource_in);
138+
AttributeWithShapeAndResource(adios2::Attribute<T> attr);
139+
operator bool() const;
140+
141+
private:
142+
/*
143+
* Users should still use the API of AttributeWithShape (parent type), we
144+
* just need somewhere to store the std::vector<T> returned by
145+
* Attribute<T>::Data(). This field will not be used when using preparsing,
146+
* because the data pointer will go right into the preparse buffer.
147+
*/
173148
std::optional<std::vector<T>> resource;
174149
};
175150

@@ -178,12 +153,34 @@ struct AdiosAttributes
178153
using RandomAccess_t = std::vector<PreloadAdiosAttributes>;
179154
struct StreamAccess_t
180155
{
156+
/*
157+
* These are only buffered for performance reasons.
158+
* IO::AvailableAttributes() returns by value, so we should avoid
159+
* calling it too often. Instead, store the returned value along with
160+
* the step, so we know when we need to update again (i.e. when the
161+
* current step changes).
162+
*/
181163
size_t m_currentStep = 0;
182164
std::optional<std::map<std::string, adios2::Params>> m_attributes;
183165
};
184166

167+
/*
168+
* Variant RandomAcces_t has to be initialized explicitly by
169+
* ADIOS2IOHandlerImpl::readAttributeAllsteps(), so we use StreamAccess_t by
170+
* default.
171+
*/
185172
std::variant<RandomAccess_t, StreamAccess_t> m_data = StreamAccess_t{};
186173

174+
/*
175+
* Needs to be this somewhat ugly API since the AvailableAttributes map has
176+
* a different type depending if we use preparsing or not. If we don't use
177+
* preparsing, we just use the returned std::map<std::string,
178+
* adios2::Params> from IO::AvailableAttributes(). Otherwise, we use the
179+
* std::map<std::string, AttributeLocation> map from the
180+
* PreloadAdiosAttributes class. The functor f will be called either with
181+
* the one or the other, so needs to be written such that the mapped-to type
182+
* does not matter.
183+
*/
187184
template <typename Functor>
188185
auto withAvailableAttributes(size_t step, adios2::IO &IO, Functor &&f)
189186
-> decltype(std::forward<Functor>(f)(

src/IO/ADIOS/ADIOS2IOHandler.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,9 @@ namespace
12521252
/* Used by both readAttribute() and readAttributeAllsteps() tasks.
12531253
Functor fun will be called with the value of the retrieved attribute;
12541254
both functions use different logic for processing the retrieved values.
1255+
Functor getAttribute is called for retrieving an attribute (Different
1256+
wrappers around IO::InquireAttribute<>()::Data(), together with
1257+
buffering).
12551258
*/
12561259
template <typename T, typename Functor, typename GetAttribute>
12571260
Datatype genericReadAttribute(
@@ -1364,6 +1367,7 @@ namespace
13641367
struct GetAttribute
13651368
{
13661369
detail::PreloadAdiosAttributes const &p;
1370+
13671371
template <typename AdiosType>
13681372
[[nodiscard]] auto call(std::string const &name) const
13691373
-> detail::AttributeWithShapeAndResource<AdiosType>
@@ -1533,9 +1537,15 @@ void ADIOS2IOHandlerImpl::listPaths(
15331537
auto tablePrefix = adios_defaults::str_activeTablePrefix + myName;
15341538
std::vector attrs =
15351539
fileData.availableAttributesPrefixed(tablePrefix);
1536-
if (fileData.streamStatus ==
1540+
if (
1541+
// either a step is currently active...
1542+
fileData.streamStatus ==
15371543
detail::ADIOS2File::StreamStatus::DuringStep ||
1544+
// ...or a step selection is currently active
15381545
(fileData.stepSelection().has_value() &&
1546+
// This check is currently redundant, but may be relevant if we
1547+
// (re-)introduce a RandomAccessMode lite that does no
1548+
// preparsing of attributes.
15391549
std::holds_alternative<
15401550
detail::AdiosAttributes::RandomAccess_t>(
15411551
fileData.attributes().m_data)))

src/IO/ADIOS/ADIOS2PreloadAttributes.cpp

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright 2020-2021 Franz Poeschel
1+
/* Copyright 2020-2025 Franz Poeschel
22
*
33
* This file is part of openPMD-api.
44
*
@@ -20,16 +20,17 @@
2020
*/
2121

2222
#include "openPMD/config.hpp"
23-
#include <algorithm>
2423
#if openPMD_HAVE_ADIOS2
2524

2625
#include "openPMD/IO/ADIOS/ADIOS2PreloadAttributes.hpp"
2726

2827
#include "openPMD/Datatype.hpp"
2928
#include "openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp"
3029

30+
#include <algorithm>
3131
#include <cstddef>
3232
#include <cstdlib>
33+
#include <optional>
3334

3435
namespace openPMD::detail
3536
{
@@ -176,7 +177,7 @@ PreloadAdiosAttributes::AttributeLocation::~AttributeLocation()
176177
void PreloadAdiosAttributes::preloadAttributes(adios2::IO &IO)
177178
{
178179
m_offsets.clear();
179-
std::map<Datatype, std::vector<std::string> > attributesByType;
180+
std::map<Datatype, std::vector<std::string>> attributesByType;
180181
auto addAttribute = [&attributesByType](Datatype dt, std::string name) {
181182
constexpr size_t reserve = 10;
182183
auto it = attributesByType.find(dt);
@@ -271,6 +272,12 @@ Datatype PreloadAdiosAttributes::attributeType(std::string const &name) const
271272
return it->second.dt;
272273
}
273274

275+
std::map<std::string, AttributeLocation> const &
276+
PreloadAdiosAttributes::availableAttributes() const
277+
{
278+
return m_offsets;
279+
}
280+
274281
template <typename T>
275282
auto AdiosAttributes::getAttribute(
276283
size_t step, adios2::IO &IO, std::string const &name) const
@@ -291,12 +298,54 @@ auto AdiosAttributes::getAttribute(
291298
m_data);
292299
}
293300

301+
template <typename T>
302+
AttributeWithShapeAndResource<T>::AttributeWithShapeAndResource(
303+
AttributeWithShape<T> parent)
304+
: AttributeWithShape<T>(std::move(parent))
305+
{}
306+
template <typename T>
307+
AttributeWithShapeAndResource<T>::AttributeWithShapeAndResource(
308+
size_t len_in, T const *data_in, std::optional<std::vector<T>> resource_in)
309+
: AttributeWithShape<T>{len_in, data_in}, resource{std::move(resource_in)}
310+
{}
311+
template <typename T>
312+
AttributeWithShapeAndResource<T>::AttributeWithShapeAndResource(
313+
adios2::Attribute<T> attr)
314+
{
315+
if (!attr)
316+
{
317+
this->data = nullptr;
318+
this->len = 0;
319+
return;
320+
}
321+
auto vec = attr.Data();
322+
this->len = vec.size();
323+
this->data = vec.data();
324+
this->resource = std::move(vec);
325+
}
326+
template <typename T>
327+
AttributeWithShapeAndResource<T>::operator bool() const
328+
{
329+
return this->data;
330+
}
331+
294332
#define OPENPMD_INSTANTIATE_GETATTRIBUTE(type) \
295333
template AttributeWithShape<type> PreloadAdiosAttributes::getAttribute( \
296334
std::string const &name) const; \
297335
template auto AdiosAttributes::getAttribute( \
298336
size_t step, adios2::IO &IO, std::string const &name) const \
299-
-> AttributeWithShapeAndResource<type>;
337+
-> AttributeWithShapeAndResource<type>; \
338+
template AttributeWithShapeAndResource< \
339+
type>::AttributeWithShapeAndResource(AttributeWithShape<type> parent); \
340+
template AttributeWithShapeAndResource<type>:: \
341+
AttributeWithShapeAndResource( \
342+
size_t len_in, \
343+
type const \
344+
*data_in, /* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
345+
std::optional<std::vector<type>> resource_in); \
346+
template AttributeWithShapeAndResource< \
347+
type>::AttributeWithShapeAndResource(adios2::Attribute<type> attr); \
348+
template AttributeWithShapeAndResource<type>::operator bool() const;
300349
ADIOS2_FOREACH_TYPE_1ARG(OPENPMD_INSTANTIATE_GETATTRIBUTE)
301350
#undef OPENPMD_INSTANTIATE_GETATTRIBUTE
302351
} // namespace openPMD::detail

0 commit comments

Comments
 (0)