Project
Loading...
Searching...
No Matches
testBoundedMemoryResource.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#define BOOST_TEST_MODULE Test Flags
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15
16#include <boost/test/unit_test.hpp>
17#include <random>
19
20using namespace o2::its;
22auto getRandomInt(int min = -100, int max = 100)
23{
24 static std::mt19937 gen(std::random_device{}()); // static generator, seeded once
25 std::uniform_int_distribution<> dist(min, max);
26 return [&, dist]() mutable {
27 return dist(gen);
28 };
29}
30
31// -------- Throwing upstream resource for testing rollback --------
33{
34 protected:
35 void* do_allocate(size_t, size_t) final
36 {
37 throw std::bad_alloc(); // always fail
38 }
39 void do_deallocate(void*, size_t, size_t) noexcept final
40 {
41 // nothing
42 }
43 bool do_is_equal(const std::pmr::memory_resource& other) const noexcept final
44 {
45 return this == &other;
46 }
47};
48
49// -------- Upstream resource with empty deallocate --------
51{
52 public:
53 NoDeallocateResource(std::pmr::memory_resource* upstream = std::pmr::get_default_resource())
54 : mUpstream(upstream) {}
55
56 protected:
57 void* do_allocate(size_t bytes, size_t alignment) final
58 {
59 return mUpstream->allocate(bytes, alignment);
60 }
61 void do_deallocate(void*, size_t, size_t) noexcept final
62 {
63 // nothing
64 }
65 bool do_is_equal(const std::pmr::memory_resource& other) const noexcept final
66 {
67 return this == &other;
68 }
69
70 private:
72};
73
74// -------- Tests --------
75BOOST_AUTO_TEST_CASE(allocation_and_clear_updates_used_memory)
76{
77 BoundedMemoryResource bmr(10 * 1024 * 1024); // 10 MB cap
78
79 Vec v(std::pmr::polymorphic_allocator<int>{&bmr});
81
82 const size_t count = 128;
83 v.reserve(count);
84 const size_t expected = count * sizeof(int);
85 BOOST_CHECK_GE(bmr.getUsedMemory(), expected);
86 BOOST_CHECK_LE(bmr.getUsedMemory(), expected + 64);
87
88 deepVectorClear(v, &bmr);
90}
91
92BOOST_AUTO_TEST_CASE(clearResizeBoundedVector_resizes_and_tracks_memory)
93{
94 BoundedMemoryResource bmr(1024 * 1024); // 1 MB cap
95
96 Vec v(std::pmr::polymorphic_allocator<int>{&bmr});
97 v.reserve(200);
98 const size_t used_before = bmr.getUsedMemory();
99 BOOST_CHECK_GT(used_before, 0u);
100
101 clearResizeBoundedVector(v, 50, &bmr, 7);
102 const size_t used_after = bmr.getUsedMemory();
103 BOOST_CHECK_GE(used_after, 50 * sizeof(int));
104 BOOST_CHECK_LT(used_after, used_before);
105
106 clearResizeBoundedVector(v, 300, &bmr, 3);
107 BOOST_CHECK_GE(bmr.getUsedMemory(), 300 * sizeof(int));
108}
109
110BOOST_AUTO_TEST_CASE(upstream_throw_rolls_back_reservation)
111{
112 ThrowingResource upstream;
113 BoundedMemoryResource bmr(std::numeric_limits<size_t>::max(), &upstream);
114 const size_t bytes = 1024;
115 bool threw = false;
116 void* p{nullptr};
117 try {
118 p = bmr.allocate(bytes, alignof(std::max_align_t));
119 } catch (const std::bad_alloc&) {
120 threw = true;
121 }
122 BOOST_CHECK(threw);
123 BOOST_CHECK_EQUAL(p, nullptr);
125}
126
127BOOST_AUTO_TEST_CASE(vector_of_bounded_vectors_deep_clear_releases_all)
128{
129 BoundedMemoryResource bmr(10 * 1024 * 1024); // 10 MB
130 std::vector<Vec> outer;
131 outer.reserve(5);
132 for (int i = 0; i < 5; ++i) {
133 outer.emplace_back(std::pmr::polymorphic_allocator<int>{&bmr});
134 outer.back().reserve(100);
135 }
136 BOOST_CHECK_GT(bmr.getUsedMemory(), 0u);
137 deepVectorClear(outer, &bmr); // deep clear outer
139}
140
141BOOST_AUTO_TEST_CASE(array_of_bounded_vectors_clear_resize_works)
142{
143 BoundedMemoryResource bmr(10 * 1024 * 1024);
144 std::array<Vec, 3> arr{{Vec(std::pmr::polymorphic_allocator<int>{&bmr}),
145 Vec(std::pmr::polymorphic_allocator<int>{&bmr}),
146 Vec(std::pmr::polymorphic_allocator<int>{&bmr})}};
147 clearResizeBoundedVector(arr[0], 10, &bmr, 1);
148 clearResizeBoundedVector(arr[1], 20, &bmr, 2);
149 clearResizeBoundedVector(arr[2], 30, &bmr, 3);
150 BOOST_CHECK_GT(bmr.getUsedMemory(), 0u);
151 deepVectorClear(arr, &bmr); // now clear all recursively
153}
154
155BOOST_AUTO_TEST_CASE(deepVectorClear_releases_and_reuses_resource)
156{
157 // Use a small bounded memory resource
158 BoundedMemoryResource bmr(1024);
159 bounded_vector<int> vec{std::pmr::polymorphic_allocator<int>{&bmr}};
160 vec.resize(100, 42);
161 BOOST_TEST(bmr.getUsedMemory() > 0);
162 deepVectorClear(vec, &bmr);
163 BOOST_TEST(vec.empty());
164 BOOST_TEST(vec.get_allocator().resource() == &bmr);
165 auto usedAfter = bmr.getUsedMemory();
167 vec.push_back(7);
168 BOOST_TEST(vec.size() == 1);
169 BOOST_TEST(vec[0] == 7);
170 BOOST_TEST(vec.get_allocator().resource() == &bmr);
171}
172
173BOOST_AUTO_TEST_CASE(clear_with_memory_resource_without_deallocator)
174{
176 Vec v(std::pmr::polymorphic_allocator<int>{&dmr});
177
178 for (int shift{0}; shift < 12; ++shift) {
179 const int c{1 << shift};
180 v.resize(100);
181 std::generate(v.begin(), v.end(), getRandomInt());
182 // allocate different sizes, which is actually a no-op now
183 clearResizeBoundedVector(v, c / 2, &dmr, 999);
184 for (size_t i{0}; i < c / 2; ++i) { // now only the first c/2 elements should be set
185 BOOST_CHECK_EQUAL(v[i], 999);
186 }
187 // try to deepclear
189 }
190}
default_random_engine gen(dev())
int32_t i
uint32_t c
Definition RawData.h:2
NoDeallocateResource(std::pmr::memory_resource *upstream=std::pmr::get_default_resource())
void * do_allocate(size_t bytes, size_t alignment) final
bool do_is_equal(const std::pmr::memory_resource &other) const noexcept final
void do_deallocate(void *, size_t, size_t) noexcept final
void do_deallocate(void *, size_t, size_t) noexcept final
void * do_allocate(size_t, size_t) final
bool do_is_equal(const std::pmr::memory_resource &other) const noexcept final
size_t getUsedMemory() const noexcept
GLint GLsizei count
Definition glcorearb.h:399
const GLdouble * v
Definition glcorearb.h:832
BOOST_AUTO_TEST_CASE(Descriptor_test)
void deepVectorClear(std::vector< T > &vec)
std::pmr::vector< T > bounded_vector
void clearResizeBoundedVector(bounded_vector< T > &vec, size_t sz, std::pmr::memory_resource *mr=nullptr, T def=T())
auto getRandomInt(int min=-100, int max=100)
bounded_vector< int > Vec
std::map< std::string, ID > expected
constexpr size_t min
constexpr size_t max
VectorOfTObjectPtrs other
std::vector< o2::ctf::BufferType > vec
BOOST_CHECK(tree)
BOOST_TEST(digits==digitsD, boost::test_tools::per_element())
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())