C/C++ API Reference
Loading...
Searching...
No Matches
tracking_allocator.h
1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17#include <cstdint>
18#include <cstring>
19
20#include "pw_allocator/allocator.h"
21#include "pw_allocator/capability.h"
22#include "pw_allocator/metrics.h"
23#include "pw_assert/assert.h"
24#include "pw_metric/metric.h"
25#include "pw_preprocessor/compiler.h"
26#include "pw_result/result.h"
27#include "pw_status/status.h"
28#include "pw_status/status_with_size.h"
29
30namespace pw::allocator {
31
33
37static constexpr struct AddTrackingAllocatorAsChild {
38} kAddTrackingAllocatorAsChild = {};
39
54template <typename MetricsType>
56 public:
57 TrackingAllocator(metric::Token token, Allocator& allocator)
58 : Allocator(allocator.capabilities() | kImplementsGetRequestedLayout),
59 allocator_(allocator),
60 metrics_(token) {}
61
62 template <typename OtherMetrics>
63 TrackingAllocator(metric::Token token,
66 : TrackingAllocator(token, parent) {
67 parent.metric_group().Add(metric_group());
68 }
69
70 const metric::Group& metric_group() const { return metrics_.group(); }
71 metric::Group& metric_group() { return metrics_.group(); }
72
73 const MetricsType& metrics() const { return metrics_.metrics(); }
74
78 void UpdateDeferred() const { metrics_.UpdateDeferred(allocator_); }
79
80 private:
82 void* DoAllocate(Layout layout) override;
83
85 void DoDeallocate(void* ptr) override;
86
88 void DoDeallocate(void* ptr, Layout) override { DoDeallocate(ptr); }
89
91 bool DoResize(void* ptr, size_t new_size) override;
92
94 void* DoReallocate(void* ptr, Layout new_layout) override;
95
97 size_t DoGetAllocated() const override { return allocator_.GetAllocated(); }
98
100 std::optional<allocator::Fragmentation> DoMeasureFragmentation()
101 const override {
102 return allocator_.MeasureFragmentation();
103 }
104
106 Result<Layout> DoGetInfo(InfoType info_type, const void* ptr) const override {
107 return GetInfo(allocator_, info_type, ptr);
108 }
109
110 Allocator& allocator_;
111 mutable internal::Metrics<MetricsType> metrics_;
112};
113
114// Template method implementation.
115
116template <typename MetricsType>
118 if constexpr (internal::AnyEnabled<MetricsType>()) {
119 Layout requested = layout;
120 size_t allocated = allocator_.GetAllocated();
121 void* new_ptr = allocator_.Allocate(requested);
122 if (new_ptr == nullptr) {
123 metrics_.RecordFailure(requested.size());
124 return nullptr;
125 }
126 metrics_.IncrementAllocations();
127 metrics_.ModifyRequested(requested.size(), 0);
128 metrics_.ModifyAllocated(allocator_.GetAllocated(), allocated);
129 return new_ptr;
130 } else {
131 return allocator_.Allocate(layout);
132 }
133}
134
135template <typename MetricsType>
137 if constexpr (internal::AnyEnabled<MetricsType>()) {
138 Layout requested = Layout::Unwrap(GetRequestedLayout(ptr));
139 size_t allocated = allocator_.GetAllocated();
140 allocator_.Deallocate(ptr);
141 metrics_.IncrementDeallocations();
142 metrics_.ModifyRequested(0, requested.size());
143 metrics_.ModifyAllocated(allocator_.GetAllocated(), allocated);
144 } else {
145 allocator_.Deallocate(ptr);
146 }
147}
148
149template <typename MetricsType>
150bool TrackingAllocator<MetricsType>::DoResize(void* ptr, size_t new_size) {
151 if constexpr (internal::AnyEnabled<MetricsType>()) {
152 Layout requested = Layout::Unwrap(GetRequestedLayout(ptr));
153 size_t allocated = allocator_.GetAllocated();
154 if (!allocator_.Resize(ptr, new_size)) {
155 metrics_.RecordFailure(new_size);
156 return false;
157 }
158 metrics_.IncrementResizes();
159 metrics_.ModifyRequested(new_size, requested.size());
160 metrics_.ModifyAllocated(allocator_.GetAllocated(), allocated);
161 return true;
162 } else {
163 return allocator_.Resize(ptr, new_size);
164 }
165}
166
167template <typename MetricsType>
169 Layout new_layout) {
170 if constexpr (internal::AnyEnabled<MetricsType>()) {
171 // Check if possible to resize in place with no additional overhead.
172 Layout requested = Layout::Unwrap(GetRequestedLayout(ptr));
173 size_t allocated = allocator_.GetAllocated();
174 size_t new_size = new_layout.size();
175 if (allocator_.Resize(ptr, new_size)) {
176 metrics_.IncrementReallocations();
177 metrics_.ModifyRequested(new_size, requested.size());
178 metrics_.ModifyAllocated(allocator_.GetAllocated(), allocated);
179 return ptr;
180 }
181
182 // Retrieve the allocated layout of the old pointer to calculate the peak
183 // memory usage during reallocation if a move occurs. Note that if the
184 // underlying allocator does not have the `kImplementsGetAllocatedLayout`
185 // capability, this will return an error and the peak metric may be lower
186 // than the actual peak allocation value.
187 Result<Layout> old_allocated_layout = GetAllocatedLayout(ptr);
188
189 void* new_ptr = allocator_.Reallocate(ptr, new_layout);
190 if (new_ptr == nullptr) {
191 metrics_.RecordFailure(new_size);
192 return nullptr;
193 }
194 metrics_.IncrementReallocations();
195 metrics_.ModifyRequested(new_size, requested.size());
196
197 size_t current_allocated = allocator_.GetAllocated();
198 if (new_ptr != ptr && old_allocated_layout.ok()) {
199 size_t peak_allocated = current_allocated + old_allocated_layout->size();
200 metrics_.ModifyAllocated(peak_allocated, allocated);
201 metrics_.ModifyAllocated(current_allocated, peak_allocated);
202 } else {
203 metrics_.ModifyAllocated(current_allocated, allocated);
204 }
205 return new_ptr;
206 } else {
207 return allocator_.Reallocate(ptr, new_layout);
208 }
209}
210
211// TODO(b/326509341): This is an interim alias to facilitate refactoring
212// downstream consumers of `TrackingAllocator` to add a template parameter.
213//
214// The following migration steps are complete:
215// 1. Downstream consumers will be updated to use `TrackingAllocatorImpl<...>`.
216// 2. The iterim `TrackingAllocator` class will be removed.
217// 3. `TrackingAllocatorImpl<...>` will be renamed to `TrackingAllocator<...>`,
218// with a `TrackingAllocatorImpl<...>` alias pointing to it.
219//
220// The following migration steps remain:
221// 4. Downstream consumers will be updated to use `TrackingAllocator<...>`.
222// 5. The `TrackingAllocatorImpl<...>` alias will be removed.
223template <typename MetricsType>
225
227
228} // namespace pw::allocator
Definition: allocator.h:45
std::optional< allocator::Fragmentation > MeasureFragmentation() const
Returns fragmentation information for the allocator's memory region.
Definition: allocator.h:360
constexpr Allocator()=default
TODO(b/326509341): Remove when downstream consumers migrate.
size_t GetAllocated() const
Definition: allocator.h:355
Definition: result.h:143
constexpr bool ok() const
Definition: result.h:447
Definition: layout.h:58
Definition: tracking_allocator.h:55
void UpdateDeferred() const
Definition: tracking_allocator.h:78
std::optional< allocator::Fragmentation > DoMeasureFragmentation() const override
Definition: tracking_allocator.h:100
size_t DoGetAllocated() const override
Definition: tracking_allocator.h:97
Result< Layout > DoGetInfo(InfoType info_type, const void *ptr) const override
Definition: tracking_allocator.h:106
void DoDeallocate(void *ptr, Layout) override
Definition: tracking_allocator.h:88
Definition: metrics.h:195
bool DoResize(void *ptr, size_t new_size) override
Definition: tracking_allocator.h:150
void DoDeallocate(void *ptr) override
Definition: tracking_allocator.h:136
void * DoReallocate(void *ptr, Layout new_layout) override
Definition: tracking_allocator.h:168
void * DoAllocate(Layout layout) override
Definition: tracking_allocator.h:117
Definition: tracking_allocator.h:37