Skip to content

Commit c128403

Browse files
gujpre-commit-ci[bot]franzpoeschel
authored
Cache Iteration indexes instead of computing them on the spot (#1860)
* attempt to fix issue #1859 by caching the index and avoid indexOf() call for iterations --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Franz Pöschel <franz.poeschel@gmail.com>
1 parent cf3e1c5 commit c128403

5 files changed

Lines changed: 70 additions & 14 deletions

File tree

include/openPMD/Iteration.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@ namespace internal
129129
*/
130130
StepStatus m_stepStatus = StepStatus::NoStep;
131131

132+
/**
133+
* Cached copy of the key under which this Iteration lives in
134+
* <code>Series::iterations</code>. Populated when the iteration
135+
* object is created/inserted. This allows constant-time lookup
136+
* of the owning map entry instead of a linear scan in
137+
* <code>Series::indexOf()</code>.
138+
*/
139+
std::optional<uint64_t> m_iterationIndex = 0;
140+
132141
/**
133142
* Information on a parsing request that has not yet been executed.
134143
* Otherwise empty.
@@ -153,6 +162,8 @@ class Iteration : public Attributable
153162
friend class Writable;
154163
friend class StatefulIterator;
155164
friend class StatefulSnapshotsContainer;
165+
template <typename>
166+
friend struct traits::GenerationPolicy;
156167

157168
public:
158169
Iteration(Iteration const &) = default;
@@ -276,6 +287,16 @@ class Iteration : public Attributable
276287
private:
277288
Iteration();
278289

290+
/**
291+
* @brief Get the cached iteration index.
292+
* This is the key under which this iteration is stored in the
293+
* Series::iterations map. Used internally for testing the index
294+
* caching optimization.
295+
*
296+
* @return The cached iteration index.
297+
*/
298+
uint64_t getCachedIterationIndex() const;
299+
279300
using Data_t = internal::IterationData;
280301
std::shared_ptr<Data_t> m_iterationData;
281302

@@ -431,6 +452,20 @@ class Iteration : public Attributable
431452
void runDeferredParseAccess();
432453
}; // Iteration
433454

455+
namespace traits
456+
{
457+
template <>
458+
struct GenerationPolicy<Iteration>
459+
{
460+
constexpr static bool is_noop = false;
461+
template <typename Iterator>
462+
void operator()(Iterator &it)
463+
{
464+
it->second.get().m_iterationIndex = it->first;
465+
}
466+
};
467+
} // namespace traits
468+
434469
extern template float Iteration::time<float>() const;
435470

436471
extern template double Iteration::time<double>() const;

include/openPMD/ParticleSpecies.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ namespace traits
6262
{
6363
constexpr static bool is_noop = false;
6464
template <typename T>
65-
void operator()(T &ret)
65+
void operator()(T &it)
6666
{
67-
ret.particlePatches.linkHierarchy(ret.writable());
67+
it->second.particlePatches.linkHierarchy(it->second.writable());
6868
}
6969
};
7070
} // namespace traits

include/openPMD/backend/ContainerImpl.tpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ auto Container<T, T_key, T_container>::operator[](key_type const &key)
140140

141141
T t = T();
142142
t.linkHierarchy(writable());
143-
auto &ret = container().insert({key, std::move(t)}).first->second;
143+
auto inserted_iterator = container().insert({key, std::move(t)}).first;
144+
auto &ret = inserted_iterator->second;
144145
if constexpr (std::is_same_v<T_key, std::string>)
145146
{
146147
ret.writable().ownKeyWithinParent = key;
@@ -150,7 +151,7 @@ auto Container<T, T_key, T_container>::operator[](key_type const &key)
150151
ret.writable().ownKeyWithinParent = std::to_string(key);
151152
}
152153
traits::GenerationPolicy<T> gen;
153-
gen(ret);
154+
gen(inserted_iterator);
154155
return ret;
155156
}
156157
}
@@ -172,7 +173,8 @@ auto Container<T, T_key, T_container>::operator[](key_type &&key)
172173

173174
T t = T();
174175
t.linkHierarchy(writable());
175-
auto &ret = container().insert({key, std::move(t)}).first->second;
176+
auto inserted_iterator = container().insert({key, std::move(t)}).first;
177+
auto &ret = inserted_iterator->second;
176178
if constexpr (std::is_same_v<T_key, std::string>)
177179
{
178180
ret.writable().ownKeyWithinParent = std::move(key);
@@ -182,7 +184,7 @@ auto Container<T, T_key, T_container>::operator[](key_type &&key)
182184
ret.writable().ownKeyWithinParent = std::to_string(std::move(key));
183185
}
184186
traits::GenerationPolicy<T> gen;
185-
gen(ret);
187+
gen(inserted_iterator);
186188
return ret;
187189
}
188190
}

src/Iteration.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ Iteration::Iteration() : Attributable(NoInit())
5959
particles.writable().ownKeyWithinParent = "particles";
6060
}
6161

62+
uint64_t Iteration::getCachedIterationIndex() const
63+
{
64+
auto idx = get().m_iterationIndex;
65+
if (!idx.has_value())
66+
{
67+
throw error::Internal("Iteration index not known.");
68+
}
69+
return *idx;
70+
}
71+
6272
template <typename T>
6373
Iteration &Iteration::setTime(T newTime)
6474
{

src/Series.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,16 +2604,25 @@ std::string Series::iterationFilename(IterationIndex_t i)
26042604
Series::iterations_iterator Series::indexOf(Iteration const &iteration)
26052605
{
26062606
auto &series = get();
2607-
for (auto it = series.iterations.begin(); it != series.iterations.end();
2608-
++it)
2607+
// first try the cached index; if it points to the correct entry return it
2608+
auto idx = iteration.get().m_iterationIndex;
2609+
if (!idx.has_value())
26092610
{
2610-
if (&it->second.Attributable::get() == &iteration.Attributable::get())
2611-
{
2612-
return it;
2613-
}
2611+
throw error::Internal("Iteration index not known.");
2612+
}
2613+
2614+
auto it = series.iterations.find(*idx);
2615+
if (it != series.iterations.end() &&
2616+
&it->second.Attributable::get() == &iteration.Attributable::get())
2617+
{
2618+
return it;
2619+
}
2620+
else
2621+
{
2622+
throw error::Internal(
2623+
"Iteration " + std::to_string(*idx) +
2624+
" no longer known by the Series?");
26142625
}
2615-
throw std::runtime_error(
2616-
"[Iteration::close] Iteration not found in Series.");
26172626
}
26182627

26192628
AdvanceStatus Series::advance(

0 commit comments

Comments
 (0)