Project
Loading...
Searching...
No Matches
testBoundedAllocator.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 GenericTrackingBoundedAllocator
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15#include <boost/test/unit_test.hpp>
16
18
19#include <stdexcept>
20
21using namespace o2::gtrk;
22
23namespace
24{
26{
27 void* do_allocate(size_t, size_t) final { throw std::bad_alloc{}; }
28 void do_deallocate(void*, size_t, size_t) final {}
29 bool do_is_equal(const std::pmr::memory_resource& other) const noexcept final { return this == &other; }
30};
31
32struct ThrowingCopy {
33 static inline int copiesBeforeFailure = -1;
34 ThrowingCopy() = default;
35 ThrowingCopy(const ThrowingCopy&)
36 {
37 if (copiesBeforeFailure == 0) {
38 throw std::runtime_error{"copy"};
39 }
40 if (copiesBeforeFailure > 0) {
41 --copiesBeforeFailure;
42 }
43 }
44 ThrowingCopy& operator=(const ThrowingCopy&) = default;
45};
46} // namespace
47
48BOOST_AUTO_TEST_CASE(huge_request_cannot_wrap_past_budget)
49{
51 void* held = pool.allocate(8);
52 BOOST_CHECK_THROW(static_cast<void>(pool.allocate(std::numeric_limits<size_t>::max())), BoundedMemoryResource::MemoryLimitExceeded);
55 pool.deallocate(held, 8);
57}
58
59BOOST_AUTO_TEST_CASE(upstream_failure_rolls_back_reserved_bytes)
60{
61 ThrowingResource upstream;
62 BoundedMemoryResource pool{1024, &upstream};
63 BOOST_CHECK_THROW(static_cast<void>(pool.allocate(16)), std::bad_alloc);
64 BOOST_CHECK_EQUAL(pool.getUsedMemory(), 0u);
65 BOOST_CHECK_EQUAL(pool.getAllocationCount(), 0u);
66 BOOST_CHECK_EQUAL(pool.getAllocatedBytes(), 0u);
67}
68
69BOOST_AUTO_TEST_CASE(legacy_mutable_budget_and_stage_peak_are_preserved)
70{
71 BoundedMemoryResource pool{64};
72 void* first = pool.allocate(16);
73 BOOST_CHECK_THROW(pool.setMaxMemory(8), BoundedMemoryResource::MemoryLimitExceeded);
74 BOOST_CHECK_EQUAL(pool.getMaxMemory(), 64u);
75 const size_t previousPeak = pool.resetPeakMemory();
76 BOOST_CHECK_EQUAL(previousPeak, 16u);
77 BOOST_CHECK_EQUAL(pool.getPeakMemoryDelta(), 0u);
78 pool.setMaxMemory(24);
79 void* second = pool.allocate(8);
80 BOOST_CHECK_EQUAL(pool.getPeakMemoryDelta(), 8u);
81 BOOST_CHECK_THROW(static_cast<void>(pool.allocate(1)), BoundedMemoryResource::MemoryLimitExceeded);
82 pool.deallocate(second, 8);
83 pool.deallocate(first, 16);
84 BOOST_CHECK_EQUAL(pool.getAllocationCount(), 2u);
85 BOOST_CHECK_EQUAL(pool.getAllocatedBytes(), 24u);
86 BOOST_CHECK_EQUAL(pool.resetPeakMemory(), 24u);
87 pool.raisePeakMemory(24);
88 BOOST_CHECK_EQUAL(pool.getPeakMemory(), 24u);
89}
90
91BOOST_AUTO_TEST_CASE(failed_rebuild_leaves_valid_vector_on_requested_resource)
92{
93 BoundedMemoryResource pool{64};
95 values.assign(8, 7);
97 BOOST_CHECK(values.empty());
98 BOOST_CHECK_EQUAL(pool.getUsedMemory(), 0u);
99 BOOST_CHECK(values.get_allocator().resource() == &pool);
100 values.push_back(9);
101 BOOST_CHECK_EQUAL(values.front(), 9);
102}
103
104BOOST_AUTO_TEST_CASE(element_constructor_failure_leaves_vector_destructible)
105{
108 values.resize(2);
109 ThrowingCopy sample;
110 ThrowingCopy::copiesBeforeFailure = 1;
111 // The by-value default argument succeeds; assign throws after rebuilding.
112 BOOST_CHECK_THROW(clearResizeBoundedVector(values, 4, &pool, sample), std::runtime_error);
113 ThrowingCopy::copiesBeforeFailure = -1;
114 BOOST_CHECK(values.empty());
117 values.resize(1);
118}
119
120BOOST_AUTO_TEST_CASE(resize_reuses_capacity_and_honors_resource_changes)
121{
124 values.reserve(16);
125 const auto allocations = first.getAllocationCount();
126 auto* storage = values.data();
128 BOOST_CHECK(values.data() == storage);
129 BOOST_CHECK_EQUAL(first.getAllocationCount(), allocations);
130 resizeBoundedVector(values, 4, &second);
131 BOOST_CHECK(values.get_allocator().resource() == &second);
132 BOOST_CHECK_EQUAL(first.getUsedMemory(), 0u);
133}
134
135BOOST_AUTO_TEST_CASE(nested_vectors_and_arrays_retain_legacy_clear_semantics)
136{
138 std::vector<BoundedVector<int>> nested;
139 clearResizeBoundedVector(nested, 3, &first);
140 for (auto& values : nested) {
141 values.assign(4, 5);
142 }
143 deepVectorClear(nested, &second);
144 BOOST_CHECK_EQUAL(nested.size(), 3u);
145 BOOST_CHECK_EQUAL(first.getUsedMemory(), 0u);
146 for (const auto& values : nested) {
147 BOOST_CHECK(values.empty());
148 BOOST_CHECK(values.get_allocator().resource() == &second);
149 }
150 std::array<BoundedVector<int>, 2> array;
151 clearResizeBoundedArray(array, 4, &second, 7);
152 BOOST_CHECK_EQUAL(array[0][0], 7);
154 BOOST_CHECK_EQUAL(second.getUsedMemory(), 0u);
155 BOOST_CHECK(array[0].get_allocator().resource() == &first);
156}
Shared budgeted host allocation and bounded-vector utilities.
size_t getAllocationCount() const noexcept
size_t getThrowCount() const noexcept
size_t getUsedMemory() const noexcept
GLenum array
Definition glcorearb.h:4274
GLint first
Definition glcorearb.h:399
GLenum GLsizei GLsizei GLint * values
Definition glcorearb.h:1576
void clearResizeBoundedVector(bounded_vector< T > &vec, size_t sz, std::pmr::memory_resource *mr=nullptr, T def=T())
void resizeBoundedVector(BoundedVector< T > &vec, size_t sz, std::pmr::memory_resource *mr=nullptr)
void deepVectorClear(std::vector< T > &vec)
void clearResizeBoundedArray(std::array< bounded_vector< T >, S > &arr, size_t size, std::pmr::memory_resource *mr=nullptr, T def=T())
std::pmr::vector< T > BoundedVector
BOOST_AUTO_TEST_CASE(huge_request_cannot_wrap_past_budget)
VectorOfTObjectPtrs other
BOOST_CHECK(tree)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())