Skip to content

Commit 3c384a8

Browse files
committed
minimize save/restore allocations
1 parent 2fa9a75 commit 3c384a8

File tree

5 files changed

+142
-42
lines changed

5 files changed

+142
-42
lines changed

src/amr/solvers/solver_ppc.hpp

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <SAMRAI/hier/Patch.h>
77

8+
#include "core/vector.hpp"
89

910
#include "amr/messengers/hybrid_messenger.hpp"
1011
#include "amr/messengers/hybrid_messenger_info.hpp"
@@ -18,12 +19,13 @@
1819
#include "core/numerics/faraday/faraday.hpp"
1920
#include "core/numerics/ohm/ohm.hpp"
2021

22+
#include "core/utilities/cellmap.hpp"
2123
#include "core/data/vecfield/vecfield.hpp"
2224
#include "core/data/grid/gridlayout_utils.hpp"
2325

24-
2526
#include <iomanip>
2627
#include <sstream>
28+
#include <tuple>
2729

2830
namespace PHARE::solver
2931
{
@@ -130,7 +132,7 @@ class SolverPPC : public ISolver<AMR_Types>
130132
double const currentTime, double const newTime, core::UpdaterMode mode);
131133

132134

133-
void saveState_(level_t& level, ModelViews_t& views);
135+
void saveState_(level_t const& level, ModelViews_t const& views);
134136
void restoreState_(level_t& level, ModelViews_t& views);
135137

136138

@@ -148,26 +150,32 @@ class SolverPPC : public ISolver<AMR_Types>
148150
};
149151

150152

151-
// extend lifespan
152-
std::unordered_map<std::string, ParticleArray> tmpDomain;
153-
std::unordered_map<std::string, ParticleArray> patchGhost;
154-
155-
template<typename Map>
156-
static void add_to(Map& map, std::string const& key, ParticleArray const& ps)
153+
struct SaveState
157154
{
158-
// vector copy drops the capacity (over allocation of the source)
159-
// we want to keep the overallocation somewhat - how much to be assessed
160-
ParticleArray empty{ps.box()};
161-
162-
if (!map.count(key))
163-
map.emplace(key, empty);
164-
else
165-
map.at(key) = empty;
166-
167-
auto& v = map.at(key);
168-
v.reserve(ps.capacity());
169-
v.replace_from(ps);
170-
}
155+
bool constexpr static copy_old = false;
156+
using box_t = core::Box<int, dimension>;
157+
using CellMap_t = core::CellMap<dimension, int>;
158+
using Particle_t = typename ParticleArray::value_type;
159+
using ParticleVec_t = core::MinimizingVector<Particle_t, copy_old>;
160+
161+
using SizeVec_t = core::MinimizingVector<std::size_t, copy_old>;
162+
using CellMapVec_t = core::MinimizingVector<CellMap_t, copy_old>;
163+
164+
auto operator()() { return std::forward_as_tuple(particles(), sizes(), maps()); }
165+
auto operator()(std::size_t const& nparts, std::size_t narrays)
166+
{
167+
if (narrays < sizes.capacity())
168+
narrays += narrays * .01;
169+
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays));
170+
}
171+
172+
ParticleVec_t particles;
173+
SizeVec_t sizes;
174+
CellMapVec_t maps;
175+
};
176+
177+
// extend lifespan
178+
SaveState domainState, patchGhostState;
171179

172180
}; // end solverPPC
173181

@@ -214,19 +222,42 @@ void SolverPPC<HybridModel, AMR_Types>::fillMessengerInfo(
214222

215223

216224
template<typename HybridModel, typename AMR_Types>
217-
void SolverPPC<HybridModel, AMR_Types>::saveState_(level_t& level, ModelViews_t& views)
225+
void SolverPPC<HybridModel, AMR_Types>::saveState_(level_t const& level, ModelViews_t const& views)
218226
{
219227
PHARE_LOG_SCOPE(1, "SolverPPC::saveState_");
220228

229+
std::size_t arrays = 0, dcount = 0, pcount = 0;
221230
for (auto& state : views)
222-
{
223-
std::stringstream ss;
224-
ss << state.patch->getGlobalId();
225231
for (auto& pop : state.ions)
226232
{
227-
std::string const key = ss.str() + "_" + pop.name();
228-
add_to(tmpDomain, key, pop.domainParticles());
229-
add_to(patchGhost, key, pop.patchGhostParticles());
233+
++arrays;
234+
dcount += pop.domainParticles().capacity();
235+
pcount += pop.patchGhostParticles().capacity();
236+
}
237+
238+
auto [dParts, dSizes, dMaps] = domainState(dcount, arrays);
239+
auto [pParts, pSizes, pMaps] = patchGhostState(pcount, arrays);
240+
241+
std::size_t arr_idx = 0, doff = 0, poff = 0;
242+
for (auto const& state : views)
243+
{
244+
for (auto const& pop : state.ions)
245+
{
246+
auto& dInParts = pop.domainParticles();
247+
auto& pInParts = pop.patchGhostParticles();
248+
249+
dMaps[arr_idx] = dInParts.map();
250+
pMaps[arr_idx] = pInParts.map();
251+
252+
dSizes[arr_idx] = dInParts.size();
253+
pSizes[arr_idx] = pInParts.size();
254+
255+
std::copy(dInParts.data(), dInParts.data() + dSizes[arr_idx], dParts.data() + doff);
256+
std::copy(pInParts.data(), pInParts.data() + pSizes[arr_idx], pParts.data() + poff);
257+
258+
doff += dSizes[arr_idx];
259+
poff += pSizes[arr_idx];
260+
++arr_idx;
230261
}
231262
}
232263
}
@@ -236,15 +267,22 @@ void SolverPPC<HybridModel, AMR_Types>::restoreState_(level_t& level, ModelViews
236267
{
237268
PHARE_LOG_SCOPE(1, "SolverPPC::restoreState_");
238269

270+
auto const [dInParts, dSizes, dMaps] = domainState();
271+
auto const [pInParts, pSizes, pMaps] = patchGhostState();
272+
273+
std::size_t arr_idx = 0, doff = 0, poff = 0;
239274
for (auto& state : views)
240275
{
241-
std::stringstream ss;
242-
ss << state.patch->getGlobalId();
243-
244276
for (auto& pop : state.ions)
245277
{
246-
pop.domainParticles() = std::move(tmpDomain.at(ss.str() + "_" + pop.name()));
247-
pop.patchGhostParticles() = std::move(patchGhost.at(ss.str() + "_" + pop.name()));
278+
pop.domainParticles().replace_from(dInParts.data() + doff, dSizes[arr_idx],
279+
dMaps[arr_idx]);
280+
pop.patchGhostParticles().replace_from(pInParts.data() + poff, pSizes[arr_idx],
281+
pMaps[arr_idx]);
282+
283+
doff += dSizes[arr_idx];
284+
poff += pSizes[arr_idx];
285+
++arr_idx;
248286
}
249287
}
250288
}

src/core/data/particles/particle_array.hpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,7 @@ class ParticleArray
4141

4242

4343
public:
44-
ParticleArray(box_t box)
45-
: box_{box}
46-
, cellMap_{box_}
47-
{
48-
assert(box_.size() > 0);
49-
}
50-
51-
ParticleArray(box_t box, std::size_t size)
44+
ParticleArray(box_t box = box_t{}, std::size_t size = 0)
5245
: particles_(size)
5346
, box_{box}
5447
, cellMap_{box_}
@@ -80,6 +73,9 @@ class ParticleArray
8073
return (this->particles_ == that.particles_);
8174
}
8275

76+
NO_DISCARD auto data() const { return particles_.data(); }
77+
NO_DISCARD auto data() { return particles_.data(); }
78+
8379
NO_DISCARD auto begin() const { return particles_.begin(); }
8480
NO_DISCARD auto begin() { return particles_.begin(); }
8581

@@ -235,6 +231,7 @@ class ParticleArray
235231
NO_DISCARD auto& vector() const { return particles_; }
236232

237233
auto& box() const { return box_; }
234+
auto& map() const { return cellMap_; }
238235

239236

240237
auto& replace_from(ParticleArray const& that)
@@ -247,6 +244,14 @@ class ParticleArray
247244
this->cellMap_ = that.cellMap_;
248245
return *this;
249246
}
247+
auto& replace_from(Particle_t const* particles, std::size_t size, CellMap_t const& map)
248+
{
249+
this->resize(size);
250+
this->cellMap_ = map;
251+
this->box_ = map.box();
252+
std::copy(particles, particles + size, particles_.data());
253+
return *this;
254+
}
250255

251256

252257
private:

src/core/def.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ NO_DISCARD bool isSettable(auto const&... args)
4444
return (check(args) && ...);
4545
}
4646

47+
48+
4749
} // namespace PHARE::core
4850

4951
#endif // PHARE_CORE_DEF_HPP

src/core/utilities/cellmap.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class CellMap
3131

3232

3333
public:
34-
CellMap(Box<cell_index_t, dim> box)
34+
CellMap(Box<cell_index_t, dim> box = {})
3535
: box_{box}
3636
, cellIndexes_{box.shape().template toArray<std::uint32_t>()}
3737
{

src/core/vector.hpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef PHARE_CORE_VECTOR_HPP
2+
#define PHARE_CORE_VECTOR_HPP
3+
4+
#include <vector>
5+
#include <cstdint>
6+
#include "core/utilities/span.hpp"
7+
8+
namespace PHARE::core
9+
{
10+
11+
12+
template<typename T, bool copy_old_ = true>
13+
struct MinimizingVector
14+
{
15+
template<bool copy_old = copy_old_>
16+
auto& get(std::size_t const& s)
17+
{
18+
if (s < v.capacity() * percentile)
19+
++_c;
20+
else
21+
_c = 0;
22+
23+
if (_c == period)
24+
{
25+
std::vector<T> r(v.capacity() * realloc_to);
26+
if constexpr (copy_old)
27+
r = v;
28+
v = std::move(r);
29+
_c = 0;
30+
}
31+
32+
v.resize(s);
33+
return v;
34+
}
35+
36+
auto size() const { return v.size(); }
37+
auto capacity() const { return v.capacity(); }
38+
auto& operator()() { return v; }
39+
auto& operator()() const { return v; }
40+
auto& operator()(std::size_t const& s) { return get(s); }
41+
42+
double const percentile = .80;
43+
double const realloc_to = .90;
44+
std::size_t const period = 100;
45+
46+
std::vector<T> v{};
47+
std::uint16_t _c = 0;
48+
};
49+
50+
51+
52+
53+
} // namespace PHARE::core
54+
55+
#endif // PHARE_CORE_VECTOR_HPP

0 commit comments

Comments
 (0)