Project
Loading...
Searching...
No Matches
BoundedAllocator.h
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.
15
16#ifndef TRACKINGITSU_INCLUDE_BOUNDEDALLOCATOR_H_
17#define TRACKINGITSU_INCLUDE_BOUNDEDALLOCATOR_H_
18
19#include <limits>
20#include <memory_resource>
21#include <atomic>
22#include <new>
23#include <vector>
24
26
27#include "GPUCommonLogger.h"
28
29namespace o2::its
30{
31
33{
34 public:
35 class MemoryLimitExceeded final : public std::bad_alloc
36 {
37 public:
38 MemoryLimitExceeded(size_t attempted, size_t used, size_t max)
39 : mAttempted(attempted), mUsed(used), mMax(max) {}
40 const char* what() const noexcept final
41 {
42 static thread_local char msg[256];
43 if (mAttempted != 0) {
44 snprintf(msg, sizeof(msg),
45 "Reached set memory limit (attempted: %zu, used: %zu, max: %zu)",
46 mAttempted, mUsed, mMax);
47 } else {
48 snprintf(msg, sizeof(msg),
49 "New set maximum below current used (newMax: %zu, used: %zu)",
50 mMax, mUsed);
51 }
52 return msg;
53 }
54
55 private:
56 size_t mAttempted{0}, mUsed{0}, mMax{0};
57 };
58
59 BoundedMemoryResource(size_t maxBytes = std::numeric_limits<size_t>::max(), std::pmr::memory_resource* upstream = std::pmr::get_default_resource())
60 : mMaxMemory(maxBytes), mUpstream(upstream) {}
61 BoundedMemoryResource(ExternalAllocator* alloc) : mAdaptor(std::make_unique<ExternalAllocatorAdaptor>(alloc)), mUpstream(mAdaptor.get()) {}
62
63 void* do_allocate(size_t bytes, size_t alignment) final
64 {
65 size_t new_used{0}, current_used{mUsedMemory.load(std::memory_order_relaxed)};
66 do {
67 new_used = current_used + bytes;
68 if (new_used > mMaxMemory) {
69 ++mCountThrow;
70 throw MemoryLimitExceeded(new_used, current_used, mMaxMemory);
71 }
72 } while (!mUsedMemory.compare_exchange_weak(current_used, new_used,
73 std::memory_order_acq_rel,
74 std::memory_order_relaxed));
75 void* p{nullptr};
76 try {
77 p = mUpstream->allocate(bytes, alignment);
78 } catch (...) {
79 mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed);
80 throw;
81 }
82 return p;
83 }
84
85 void do_deallocate(void* p, size_t bytes, size_t alignment) final
86 {
87 mUpstream->deallocate(p, bytes, alignment);
88 mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed);
89 }
90
91 bool do_is_equal(const std::pmr::memory_resource& other) const noexcept final
92 {
93 return this == &other;
94 }
95
96 size_t getUsedMemory() const noexcept { return mUsedMemory.load(); }
97 size_t getMaxMemory() const noexcept { return mMaxMemory; }
98 void setMaxMemory(size_t max)
99 {
100 size_t used = mUsedMemory.load(std::memory_order_acquire);
101 if (used > max) {
102 ++mCountThrow;
103 throw MemoryLimitExceeded(0, used, max);
104 }
105 mMaxMemory.store(max, std::memory_order_release);
106 }
107
108 void print() const
109 {
110#if !defined(GPUCA_GPUCODE_DEVICE)
111 constexpr double GB{1024 * 1024 * 1024};
112 auto throw_ = mCountThrow.load(std::memory_order_relaxed);
113 auto used = static_cast<double>(mUsedMemory.load(std::memory_order_relaxed));
114 LOGP(info, "maxthrow={} maxmem={:.2f} GB used={:.2f} ({:.2f}%)",
115 throw_, (double)mMaxMemory / GB, used / GB, 100. * used / (double)mMaxMemory);
116#endif
117 }
118
119 private:
120 std::atomic<size_t> mMaxMemory{std::numeric_limits<size_t>::max()};
121 std::atomic<size_t> mCountThrow{0};
122 std::atomic<size_t> mUsedMemory{0};
123 std::unique_ptr<ExternalAllocatorAdaptor> mAdaptor{nullptr};
124 std::pmr::memory_resource* mUpstream{nullptr};
125};
126
127template <typename T>
128using bounded_vector = std::pmr::vector<T>;
129
130template <typename T>
131inline void deepVectorClear(std::vector<T>& vec)
132{
133 std::vector<T>().swap(vec);
134}
135
136template <typename T>
138{
139 std::pmr::memory_resource* tmr = (mr != nullptr) ? mr : vec.get_allocator().resource();
140 vec.~bounded_vector<T>();
141 new (&vec) bounded_vector<T>(std::pmr::polymorphic_allocator<T>{tmr});
142}
143
144template <typename T>
145inline void deepVectorClear(std::vector<bounded_vector<T>>& vec, std::pmr::memory_resource* mr = nullptr)
146{
147 for (auto& v : vec) {
148 deepVectorClear(v, mr);
149 }
150}
151
152template <typename T, size_t S>
153inline void deepVectorClear(std::array<bounded_vector<T>, S>& arr, std::pmr::memory_resource* mr = nullptr)
154{
155 for (size_t i{0}; i < S; ++i) {
156 deepVectorClear(arr[i], mr);
157 }
158}
159
160template <typename T>
161inline void clearResizeBoundedVector(bounded_vector<T>& vec, size_t sz, std::pmr::memory_resource* mr = nullptr, T def = T())
162{
163 std::pmr::memory_resource* tmr = (mr != nullptr) ? mr : vec.get_allocator().resource();
164 vec.~bounded_vector<T>();
165 new (&vec) bounded_vector<T>(sz, def, std::pmr::polymorphic_allocator<T>{tmr});
166}
167
168template <typename T>
170{
171 vec.clear();
172 vec.reserve(size);
173 for (size_t i = 0; i < size; ++i) {
174 vec.emplace_back(std::pmr::polymorphic_allocator<bounded_vector<T>>{mr});
175 }
176}
177
178template <typename T, size_t S>
179inline void clearResizeBoundedArray(std::array<bounded_vector<T>, S>& arr, size_t size, std::pmr::memory_resource* mr = nullptr, T def = T())
180{
181 for (size_t i{0}; i < S; ++i) {
182 clearResizeBoundedVector(arr[i], size, mr, def);
183 }
184}
185
186template <typename T>
187inline std::vector<T> toSTDVector(const bounded_vector<T>& b)
188{
189 std::vector<T> t(b.size());
190 std::copy(b.cbegin(), b.cend(), t.begin());
191 return t;
192}
193
194} // namespace o2::its
195
196#endif
int32_t i
#define GB
Definition Utils.h:40
MemoryLimitExceeded(size_t attempted, size_t used, size_t max)
void * do_allocate(size_t bytes, size_t alignment) final
BoundedMemoryResource(ExternalAllocator *alloc)
void do_deallocate(void *p, size_t bytes, size_t alignment) final
size_t getMaxMemory() const noexcept
bool do_is_equal(const std::pmr::memory_resource &other) const noexcept final
BoundedMemoryResource(size_t maxBytes=std::numeric_limits< size_t >::max(), std::pmr::memory_resource *upstream=std::pmr::get_default_resource())
size_t getUsedMemory() const noexcept
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
void deepVectorClear(std::vector< T > &vec)
std::pmr::vector< T > bounded_vector
std::vector< T > toSTDVector(const bounded_vector< T > &b)
void clearResizeBoundedArray(std::array< bounded_vector< T >, S > &arr, size_t size, std::pmr::memory_resource *mr=nullptr, T def=T())
void clearResizeBoundedVector(bounded_vector< T > &vec, size_t sz, std::pmr::memory_resource *mr=nullptr, T def=T())
Defining DataPointCompositeObject explicitly as copiable.
constexpr size_t max
VectorOfTObjectPtrs other
std::vector< o2::ctf::BufferType > vec
uint64_t const void const *restrict const msg
Definition x9.h:153