Pigweed
Loading...
Searching...
No Matches
metrics.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
19#include "pw_metric/metric.h"
20
21namespace pw::allocator {
22
33#define PW_ALLOCATOR_METRICS_DECLARE(metric_name) \
34 template <typename MetricsType, typename = void> \
35 struct has_##metric_name : std::false_type {}; \
36 template <typename MetricsType> \
37 struct has_##metric_name<MetricsType, \
38 std::void_t<decltype(MetricsType::metric_name)>> \
39 : std::true_type {}
40
41// Tracks the current, peak, and cumulative number of bytes requested to be
42// allocated, respectively.
43PW_ALLOCATOR_METRICS_DECLARE(requested_bytes);
44PW_ALLOCATOR_METRICS_DECLARE(peak_requested_bytes);
45PW_ALLOCATOR_METRICS_DECLARE(cumulative_requested_bytes);
46
47// Tracks the current, peak, and cumulative number of bytes actually allocated,
48// respectively.
49PW_ALLOCATOR_METRICS_DECLARE(allocated_bytes);
50PW_ALLOCATOR_METRICS_DECLARE(peak_allocated_bytes);
51PW_ALLOCATOR_METRICS_DECLARE(cumulative_allocated_bytes);
52
53// Tracks the number of successful calls to each interface method.
54PW_ALLOCATOR_METRICS_DECLARE(num_allocations);
55PW_ALLOCATOR_METRICS_DECLARE(num_deallocations);
56PW_ALLOCATOR_METRICS_DECLARE(num_resizes);
57PW_ALLOCATOR_METRICS_DECLARE(num_reallocations);
58
59// Tracks the number of interface calls that failed, and the number of bytes
60// requested in those calls.
61PW_ALLOCATOR_METRICS_DECLARE(num_failures);
62PW_ALLOCATOR_METRICS_DECLARE(unfulfilled_bytes);
63
64#undef PW_ALLOCATOR_METRICS_DECLARE
65
86#define PW_ALLOCATOR_METRICS_ENABLE(metric_name) \
87 static_assert(!::pw::allocator::has_##metric_name<void>::value); \
88 PW_METRIC(metric_name, #metric_name, 0U)
89
91struct NoMetrics {};
92
93namespace internal {
94
101 PW_ALLOCATOR_METRICS_ENABLE(requested_bytes);
102 PW_ALLOCATOR_METRICS_ENABLE(peak_requested_bytes);
103 PW_ALLOCATOR_METRICS_ENABLE(cumulative_requested_bytes);
104 PW_ALLOCATOR_METRICS_ENABLE(allocated_bytes);
105 PW_ALLOCATOR_METRICS_ENABLE(peak_allocated_bytes);
106 PW_ALLOCATOR_METRICS_ENABLE(cumulative_allocated_bytes);
107 PW_ALLOCATOR_METRICS_ENABLE(num_allocations);
108 PW_ALLOCATOR_METRICS_ENABLE(num_deallocations);
109 PW_ALLOCATOR_METRICS_ENABLE(num_resizes);
110 PW_ALLOCATOR_METRICS_ENABLE(num_reallocations);
111 PW_ALLOCATOR_METRICS_ENABLE(num_failures);
112 PW_ALLOCATOR_METRICS_ENABLE(unfulfilled_bytes);
113};
114
123template <typename MetricsType>
124class Metrics final {
125 public:
126 Metrics(metric::Token token);
127 ~Metrics() = default;
128
129 const metric::Group& group() const { return group_; }
130 metric::Group& group() { return group_; }
131
132 const MetricsType& metrics() const { return metrics_; }
133
141 void ModifyRequested(size_t increase, size_t decrease);
142
157 void ModifyAllocated(size_t increase, size_t decrease);
158
161
164
167
170
178 void RecordFailure(size_t requested);
179
180 private:
181 metric::Group group_;
182 MetricsType metrics_;
183};
184
185// Helper method for converting `size_t`s to `uint32_t`s.
186inline uint32_t ClampU32(size_t size) {
187 return static_cast<uint32_t>(std::min(
188 size, static_cast<size_t>(std::numeric_limits<uint32_t>::max())));
189}
190
191// Template method implementation.
192
193template <typename MetricsType>
194Metrics<MetricsType>::Metrics(metric::Token token) : group_(token) {
196 group_.Add(metrics_.requested_bytes);
197 }
198 if constexpr (has_peak_requested_bytes<MetricsType>::value) {
199 group_.Add(metrics_.peak_requested_bytes);
200 }
201 if constexpr (has_cumulative_requested_bytes<MetricsType>::value) {
202 group_.Add(metrics_.cumulative_requested_bytes);
203 }
204 if constexpr (has_allocated_bytes<MetricsType>::value) {
205 group_.Add(metrics_.allocated_bytes);
206 }
207 if constexpr (has_peak_allocated_bytes<MetricsType>::value) {
208 group_.Add(metrics_.peak_allocated_bytes);
209 }
210 if constexpr (has_cumulative_allocated_bytes<MetricsType>::value) {
211 group_.Add(metrics_.cumulative_allocated_bytes);
212 }
213 if constexpr (has_num_allocations<MetricsType>::value) {
214 group_.Add(metrics_.num_allocations);
215 }
216 if constexpr (has_num_deallocations<MetricsType>::value) {
217 group_.Add(metrics_.num_deallocations);
218 }
219 if constexpr (has_num_resizes<MetricsType>::value) {
220 group_.Add(metrics_.num_resizes);
221 }
222 if constexpr (has_num_reallocations<MetricsType>::value) {
223 group_.Add(metrics_.num_reallocations);
224 }
225 if constexpr (has_num_failures<MetricsType>::value) {
226 group_.Add(metrics_.num_failures);
227 }
228 if constexpr (has_unfulfilled_bytes<MetricsType>::value) {
229 group_.Add(metrics_.unfulfilled_bytes);
230 }
231}
232
233template <typename MetricsType>
234void Metrics<MetricsType>::ModifyRequested(size_t increase, size_t decrease) {
236 metrics_.requested_bytes.Increment(internal::ClampU32(increase));
237 metrics_.requested_bytes.Decrement(internal::ClampU32(decrease));
239 uint32_t requested_bytes = metrics_.requested_bytes.value();
240 if (metrics_.peak_requested_bytes.value() < requested_bytes) {
241 metrics_.peak_requested_bytes.Set(requested_bytes);
242 }
243 }
245 if (increase > decrease) {
246 metrics_.cumulative_requested_bytes.Increment(
247 internal::ClampU32(increase - decrease));
248 }
249 }
250 }
251}
252
253template <typename MetricsType>
254void Metrics<MetricsType>::ModifyAllocated(size_t increase, size_t decrease) {
256 metrics_.allocated_bytes.Increment(internal::ClampU32(increase));
257 metrics_.allocated_bytes.Decrement(internal::ClampU32(decrease));
259 uint32_t allocated_bytes = metrics_.allocated_bytes.value();
260 if (metrics_.peak_allocated_bytes.value() < allocated_bytes) {
261 metrics_.peak_allocated_bytes.Set(allocated_bytes);
262 }
263 }
265 if (increase > decrease) {
266 metrics_.cumulative_allocated_bytes.Increment(
267 internal::ClampU32(increase - decrease));
268 }
269 }
270 }
271}
272
273template <typename MetricsType>
276 metrics_.num_allocations.Increment();
277 }
278}
279
280template <typename MetricsType>
283 metrics_.num_deallocations.Increment();
284 }
285}
286
287template <typename MetricsType>
290 metrics_.num_resizes.Increment();
291 }
292}
293
294template <typename MetricsType>
297 metrics_.num_reallocations.Increment();
298 }
299}
300
301template <typename MetricsType>
304 metrics_.num_failures.Increment();
305 }
307 metrics_.unfulfilled_bytes.Increment(internal::ClampU32(requested));
308 }
309}
310
311} // namespace internal
312} // namespace pw::allocator
Definition: metrics.h:124
void IncrementDeallocations()
Records that a call to Deallocate was made.
Definition: metrics.h:281
void RecordFailure(size_t requested)
Definition: metrics.h:302
void ModifyRequested(size_t increase, size_t decrease)
Definition: metrics.h:234
void IncrementReallocations()
Records that a call to Reallocate was made.
Definition: metrics.h:295
void IncrementAllocations()
Records that a call to Allocate was made.
Definition: metrics.h:274
void IncrementResizes()
Records that a call to Resize was made.
Definition: metrics.h:288
void ModifyAllocated(size_t increase, size_t decrease)
Definition: metrics.h:254
A predefined metric struct that enables no allocator metrics.
Definition: metrics.h:91
Definition: metrics.h:49
Definition: metrics.h:54
Definition: metrics.h:55
Definition: metrics.h:61
Definition: metrics.h:57
Definition: metrics.h:56
Definition: metrics.h:43
Definition: metrics.h:62
Definition: metrics.h:100