Skip to content

Commit f54bcfa

Browse files
authored
PODVector: Add extra capacity (#4734)
Add some extra room when we call `PODVector::resize` and `reserve`. The extra capacity is computed as 3*sqrt(capacity) suggested by @AlexanderSinn, and is capped at 10%. This might help particle codes avoid memory re-allocation.
1 parent 0c4bc54 commit f54bcfa

File tree

1 file changed

+55
-26
lines changed

1 file changed

+55
-26
lines changed

Src/Base/AMReX_PODVector.H

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <AMReX_MemPool.H>
1111
#include <AMReX_TypeTraits.H>
1212

13+
#include <cmath>
1314
#include <iterator>
1415
#include <type_traits>
1516
#include <utility>
@@ -257,6 +258,19 @@ namespace amrex
257258
void Initialize ();
258259
}
259260

261+
inline std::size_t grow_podvector_capacity (std::size_t s)
262+
{
263+
if (s <= 900) {
264+
// 3*sqrt(900) = 900/10. Note that we don't need to be precise
265+
// here. Even if later we change the else block to
266+
// 4*std::sqrt(s), it's not really an issue to still use 900
267+
// here.
268+
return s + s/10;
269+
} else {
270+
return s + std::size_t(3*std::sqrt(s));
271+
}
272+
}
273+
260274
template <class T, class Allocator = std::allocator<T> >
261275
class PODVector : public Allocator
262276
{
@@ -295,48 +309,57 @@ namespace amrex
295309
{}
296310

297311
explicit PODVector (size_type a_size)
298-
: m_size(a_size), m_capacity(a_size)
312+
: m_size(a_size), m_capacity(grow_podvector_capacity(a_size))
299313
{
300-
if (a_size != 0) {
301-
m_data = allocate(m_size);
302-
detail::maybe_init_snan(m_data, m_size, (Allocator const&)(*this));
314+
if (m_capacity != 0) {
315+
m_data = allocate(m_capacity);
316+
if (a_size != 0) {
317+
detail::maybe_init_snan(m_data, m_size, (Allocator const&)(*this));
318+
}
303319
}
304320
}
305321

306322
PODVector (size_type a_size, const value_type& a_value,
307323
const allocator_type& a_allocator = Allocator())
308-
: Allocator(a_allocator), m_size(a_size), m_capacity(a_size)
309-
{
310-
if (a_size != 0) {
311-
m_data = allocate(m_size);
312-
detail::uninitializedFillNImpl(m_data, a_size, a_value,
313-
(Allocator const&)(*this));
324+
: Allocator(a_allocator), m_size(a_size),
325+
m_capacity(grow_podvector_capacity(a_size))
326+
{
327+
if (m_capacity != 0) {
328+
m_data = allocate(m_capacity);
329+
if (a_size != 0) {
330+
detail::uninitializedFillNImpl(m_data, a_size, a_value,
331+
(Allocator const&)(*this));
332+
}
314333
}
315334
}
316335

317336
PODVector (std::initializer_list<T> a_initializer_list,
318337
const allocator_type& a_allocator = Allocator())
319338
: Allocator(a_allocator),
320339
m_size (a_initializer_list.size()),
321-
m_capacity(a_initializer_list.size())
340+
m_capacity(grow_podvector_capacity(a_initializer_list.size()))
322341
{
323-
if (a_initializer_list.size() != 0) {
324-
m_data = allocate(m_size);
325-
detail::initFromListImpl(m_data, a_initializer_list,
326-
(Allocator const&)(*this));
342+
if (m_capacity != 0) {
343+
m_data = allocate(m_capacity);
344+
if (a_initializer_list.size() != 0) {
345+
detail::initFromListImpl(m_data, a_initializer_list,
346+
(Allocator const&)(*this));
347+
}
327348
}
328349
}
329350

330351
PODVector (const PODVector<T, Allocator>& a_vector)
331352
: Allocator(a_vector),
332353
m_size (a_vector.size()),
333-
m_capacity(a_vector.size())
354+
m_capacity(a_vector.capacity())
334355
{
335-
if (a_vector.size() != 0) {
336-
m_data = allocate(m_size);
337-
detail::memCopyImpl(m_data, a_vector.m_data, a_vector.nBytes(),
338-
(Allocator const&)(*this),
339-
(Allocator const&)a_vector);
356+
if (m_capacity != 0) {
357+
m_data = allocate(m_capacity);
358+
if (a_vector.size() != 0) {
359+
detail::memCopyImpl(m_data, a_vector.m_data, a_vector.nBytes(),
360+
(Allocator const&)(*this),
361+
(Allocator const&)a_vector);
362+
}
340363
}
341364
}
342365

@@ -378,7 +401,7 @@ namespace amrex
378401
const auto other_size = a_vector.size();
379402
if ( other_size > m_capacity ) {
380403
clear();
381-
reserve(other_size);
404+
reserve_doit(other_size);
382405
}
383406

384407
m_size = other_size;
@@ -592,7 +615,7 @@ namespace amrex
592615

593616
[[nodiscard]] size_type capacity () const noexcept { return m_capacity; }
594617

595-
[[nodiscard]] bool empty () const noexcept { return m_size == 0; }
618+
[[nodiscard]] bool empty () const noexcept { return m_size == 0 || m_data == nullptr; } // test m_data to avoid compiler warning
596619

597620
[[nodiscard]] T& operator[] (size_type a_index) noexcept { return m_data[a_index]; }
598621

@@ -663,9 +686,7 @@ namespace amrex
663686
void reserve (size_type a_capacity)
664687
{
665688
if (m_capacity < a_capacity) {
666-
auto fp = detail::allocate_in_place(m_data, a_capacity, a_capacity,
667-
(Allocator&)(*this));
668-
UpdateDataPtr(fp);
689+
reserve_doit(grow_podvector_capacity(a_capacity));
669690
}
670691
}
671692

@@ -701,6 +722,14 @@ namespace amrex
701722

702723
private:
703724

725+
void reserve_doit (size_type a_capacity) {
726+
if (m_capacity < a_capacity) {
727+
auto fp = detail::allocate_in_place(m_data, a_capacity, a_capacity,
728+
(Allocator&)(*this));
729+
UpdateDataPtr(fp);
730+
}
731+
}
732+
704733
[[nodiscard]] size_type nBytes () const noexcept
705734
{
706735
return m_size*sizeof(T);

0 commit comments

Comments
 (0)