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
25#include "GPUCommonLogger.h"
26
27namespace o2::its
28{
29
31{
32 public:
33 class MemoryLimitExceeded final : public std::bad_alloc
34 {
35 public:
36 MemoryLimitExceeded(size_t attempted, size_t used, size_t max)
37 : mAttempted(attempted), mUsed(used), mMax(max) {}
38 const char* what() const noexcept final
39 {
40 static thread_local char msg[256];
41 if (mAttempted != 0) {
42 snprintf(msg, sizeof(msg),
43 "Reached set memory limit (attempted: %zu, used: %zu, max: %zu)",
44 mAttempted, mUsed, mMax);
45 } else {
46 snprintf(msg, sizeof(msg),
47 "New set maximum below current used (newMax: %zu, used: %zu)",
48 mMax, mUsed);
49 }
50 return msg;
51 }
52
53 private:
54 size_t mAttempted{0}, mUsed{0}, mMax{0};
55 };
56
57 BoundedMemoryResource(size_t maxBytes = std::numeric_limits<size_t>::max(), std::pmr::memory_resource* upstream = std::pmr::get_default_resource())
58 : mMaxMemory(maxBytes), mUpstream(upstream) {}
59
60 void* do_allocate(size_t bytes, size_t alignment) final
61 {
62 size_t new_used{0}, current_used{mUsedMemory.load(std::memory_order_relaxed)};
63 do {
64 new_used = current_used + bytes;
65 if (new_used > mMaxMemory) {
66 ++mCountThrow;
67 throw MemoryLimitExceeded(new_used, current_used, mMaxMemory);
68 }
69 } while (!mUsedMemory.compare_exchange_weak(current_used, new_used,
70 std::memory_order_acq_rel,
71 std::memory_order_relaxed));
72 return mUpstream->allocate(bytes, alignment);
73 }
74
75 void do_deallocate(void* p, size_t bytes, size_t alignment) final
76 {
77 mUpstream->deallocate(p, bytes, alignment);
78 mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed);
79 }
80
81 bool do_is_equal(const std::pmr::memory_resource& other) const noexcept final
82 {
83 return this == &other;
84 }
85
86 size_t getUsedMemory() const noexcept { return mUsedMemory.load(); }
87 size_t getMaxMemory() const noexcept { return mMaxMemory; }
88 void setMaxMemory(size_t max)
89 {
90 if (mUsedMemory > max) {
91 ++mCountThrow;
92 throw MemoryLimitExceeded(0, mUsedMemory, max);
93 }
94 mMaxMemory = max;
95 }
96
97 void print() const
98 {
99#if !defined(GPUCA_GPUCODE_DEVICE)
100 constexpr double GB{1024 * 1024 * 1024};
101 auto throw_ = mCountThrow.load(std::memory_order_relaxed);
102 auto used = static_cast<double>(mUsedMemory.load(std::memory_order_relaxed));
103 LOGP(info, "maxthrow={} maxmem={:.2f} GB used={:.2f} ({:.2f}%)",
104 throw_, (double)mMaxMemory / GB, used / GB, 100. * used / (double)mMaxMemory);
105#endif
106 }
107
108 private:
109 size_t mMaxMemory{std::numeric_limits<size_t>::max()};
110 std::atomic<size_t> mCountThrow{0};
111 std::atomic<size_t> mUsedMemory{0};
112 std::pmr::memory_resource* mUpstream;
113};
114
115template <typename T>
116using bounded_vector = std::pmr::vector<T>;
117
118template <typename T>
119void deepVectorClear(std::vector<T>& vec)
120{
121 std::vector<T>().swap(vec);
122}
123
124template <typename T>
126{
127 vec.~bounded_vector<T>();
128 if (bmr == nullptr) {
129 auto alloc = vec.get_allocator().resource();
130 new (&vec) bounded_vector<T>(alloc);
131 } else {
132 new (&vec) bounded_vector<T>(bmr);
133 }
134}
135
136template <typename T>
138{
139 for (auto& v : vec) {
140 deepVectorClear(v, bmr);
141 }
142}
143
144template <typename T, size_t S>
145void deepVectorClear(std::array<bounded_vector<T>, S>& arr, BoundedMemoryResource* bmr = nullptr)
146{
147 for (size_t i{0}; i < S; ++i) {
148 deepVectorClear(arr[i], bmr);
149 }
150}
151
152template <typename T>
154{
155 vec.~bounded_vector<T>();
156 new (&vec) bounded_vector<T>(size, def, bmr);
157}
158
159template <typename T>
161{
162 vec.clear();
163 vec.reserve(size);
164 for (size_t i{0}; i < size; ++i) {
165 vec.emplace_back(bmr);
166 }
167}
168
169template <typename T, size_t S>
170void clearResizeBoundedArray(std::array<bounded_vector<T>, S>& arr, size_t size, BoundedMemoryResource* bmr, T def = T())
171{
172 for (size_t i{0}; i < S; ++i) {
173 clearResizeBoundedVector(arr[i], size, bmr, def);
174 }
175}
176
177} // namespace o2::its
178
179#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
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
void deepVectorClear(std::vector< T > &vec)
std::pmr::vector< T > bounded_vector
void clearResizeBoundedArray(std::array< bounded_vector< T >, S > &arr, size_t size, BoundedMemoryResource *bmr, T def=T())
void clearResizeBoundedVector(bounded_vector< T > &vec, size_t size, BoundedMemoryResource *bmr, T def=T())
constexpr size_t max
VectorOfTObjectPtrs other
std::vector< o2::ctf::BufferType > vec
uint64_t const void const *restrict const msg
Definition x9.h:153