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_allocator/allocator.h"
20#include "pw_metric/metric.h"
21#include "pw_status/status_with_size.h"
22
23namespace pw::allocator {
24
60#define PW_ALLOCATOR_METRICS_FOREACH(fn) \
61 fn(requested_bytes); \
62 fn(peak_requested_bytes); \
63 fn(cumulative_requested_bytes); \
64 fn(allocated_bytes); \
65 fn(peak_allocated_bytes); \
66 fn(cumulative_allocated_bytes); \
67 fn(num_allocations); \
68 fn(num_deallocations); \
69 fn(num_resizes); \
70 fn(num_reallocations); \
71 fn(num_free_blocks); \
72 fn(smallest_free_block_size); \
73 fn(largest_free_block_size); \
74 fn(num_failures); \
75 fn(unfulfilled_bytes)
76
77#define PW_ALLOCATOR_ABSORB_SEMICOLON() static_assert(true)
78
89#define PW_ALLOCATOR_METRICS_DECLARE(metric_name) \
90 static constexpr bool has_##metric_name() { return false; } \
91 ::pw::StatusWithSize get_##metric_name() const { \
92 return ::pw::StatusWithSize::NotFound(); \
93 } \
94 static constexpr bool metric_name##_enabled() { return false; } \
95 PW_ALLOCATOR_ABSORB_SEMICOLON()
96
102struct NoMetrics {
103 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_METRICS_DECLARE);
104
115};
116
117#undef PW_ALLOCATOR_METRICS_DECLARE
118
130#define PW_ALLOCATOR_METRICS_INCLUDE(metric_name) \
131 static_assert(!::pw::allocator::NoMetrics::has_##metric_name()); \
132 static constexpr bool has_##metric_name() { return true; } \
133 inline ::pw::StatusWithSize get_##metric_name() const { \
134 return ::pw::StatusWithSize(metric_name.value()); \
135 } \
136 PW_METRIC(metric_name, #metric_name, 0U)
137
160#define PW_ALLOCATOR_METRICS_ENABLE(metric_name) \
161 static constexpr bool metric_name##_enabled() { return true; } \
162 PW_ALLOCATOR_METRICS_INCLUDE(metric_name)
163
164namespace internal {
165
171struct AllMetrics : public NoMetrics {
172 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_METRICS_ENABLE);
173};
174
177template <typename MetricsType>
178constexpr bool AnyEnabled();
179
181template <typename MetricsType>
182void CopyMetrics(const MetricsType& src, MetricsType& dst);
183
192template <typename MetricsType>
193class Metrics final {
194 public:
195 Metrics(metric::Token token);
196 ~Metrics() = default;
197
198 const metric::Group& group() const { return group_; }
199 metric::Group& group() { return group_; }
200
201 const MetricsType& metrics() const { return metrics_; }
202
210 void ModifyRequested(size_t increase, size_t decrease);
211
226 void ModifyAllocated(size_t increase, size_t decrease);
227
230
233
236
239
247 void RecordFailure(size_t requested);
248
252 void UpdateDeferred(Allocator& allocator) {
253 metrics_.UpdateDeferred(allocator);
254 }
255
256 private:
257 metric::Group group_;
258 MetricsType metrics_;
259};
260
262inline uint32_t ClampU32(size_t size) {
263 return static_cast<uint32_t>(std::min(
264 size, static_cast<size_t>(std::numeric_limits<uint32_t>::max())));
265}
266
267// Template method implementations.
268
269template <typename MetricsType>
270constexpr bool AnyEnabled() {
271#define PW_ALLOCATOR_RETURN_IF_ENABLED(metric_name) \
272 if (MetricsType::metric_name##_enabled()) { \
273 return true; \
274 } \
275 PW_ALLOCATOR_ABSORB_SEMICOLON()
276
277 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_RETURN_IF_ENABLED);
278 return false;
279
280#undef PW_ALLOCATOR_RETURN_IF_ENABLED
281}
282
283template <typename MetricsType>
284void CopyMetrics(const MetricsType& src, MetricsType& dst) {
285#define PW_ALLOCATOR_COPY_METRIC(metric_name) \
286 if constexpr (MetricsType::has_##metric_name()) { \
287 dst.metric_name.Set(src.metric_name.value()); \
288 } \
289 PW_ALLOCATOR_ABSORB_SEMICOLON()
290
291 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_COPY_METRIC);
292
293#undef PW_ALLOCATOR_COPY_METRIC
294}
295
296template <typename MetricsType>
297Metrics<MetricsType>::Metrics(metric::Token token) : group_(token) {
298#define PW_ALLOCATOR_ADD_TO_GROUP(metric_name) \
299 if constexpr (MetricsType::has_##metric_name()) { \
300 group_.Add(metrics_.metric_name); \
301 } \
302 PW_ALLOCATOR_ABSORB_SEMICOLON()
303
304 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_ADD_TO_GROUP);
305
306#undef PW_ALLOCATOR_ADD_TO_GROUP
307}
308
309template <typename MetricsType>
310void Metrics<MetricsType>::ModifyRequested(size_t increase, size_t decrease) {
311 if constexpr (MetricsType::requested_bytes_enabled()) {
312 metrics_.requested_bytes.Increment(internal::ClampU32(increase));
313 metrics_.requested_bytes.Decrement(internal::ClampU32(decrease));
314 if constexpr (MetricsType::peak_requested_bytes_enabled()) {
315 uint32_t requested_bytes = metrics_.requested_bytes.value();
316 if (metrics_.peak_requested_bytes.value() < requested_bytes) {
317 metrics_.peak_requested_bytes.Set(requested_bytes);
318 }
319 }
320 if constexpr (MetricsType::cumulative_requested_bytes_enabled()) {
321 if (increase > decrease) {
322 metrics_.cumulative_requested_bytes.Increment(
323 internal::ClampU32(increase - decrease));
324 }
325 }
326 }
327}
328
329template <typename MetricsType>
330void Metrics<MetricsType>::ModifyAllocated(size_t increase, size_t decrease) {
331 if constexpr (MetricsType::allocated_bytes_enabled()) {
332 metrics_.allocated_bytes.Increment(internal::ClampU32(increase));
333 metrics_.allocated_bytes.Decrement(internal::ClampU32(decrease));
334 if constexpr (MetricsType::peak_allocated_bytes_enabled()) {
335 uint32_t allocated_bytes = metrics_.allocated_bytes.value();
336 if (metrics_.peak_allocated_bytes.value() < allocated_bytes) {
337 metrics_.peak_allocated_bytes.Set(allocated_bytes);
338 }
339 }
340 if constexpr (MetricsType::cumulative_allocated_bytes_enabled()) {
341 if (increase > decrease) {
342 metrics_.cumulative_allocated_bytes.Increment(
343 internal::ClampU32(increase - decrease));
344 }
345 }
346 }
347}
348
349template <typename MetricsType>
351 if constexpr (MetricsType::num_allocations_enabled()) {
352 metrics_.num_allocations.Increment();
353 }
354}
355
356template <typename MetricsType>
358 if constexpr (MetricsType::num_deallocations_enabled()) {
359 metrics_.num_deallocations.Increment();
360 }
361}
362
363template <typename MetricsType>
365 if constexpr (MetricsType::num_resizes_enabled()) {
366 metrics_.num_resizes.Increment();
367 }
368}
369
370template <typename MetricsType>
372 if constexpr (MetricsType::num_reallocations_enabled()) {
373 metrics_.num_reallocations.Increment();
374 }
375}
376
377template <typename MetricsType>
379 if constexpr (MetricsType::num_failures_enabled()) {
380 metrics_.num_failures.Increment();
381 }
382 if constexpr (MetricsType::unfulfilled_bytes_enabled()) {
383 metrics_.unfulfilled_bytes.Increment(internal::ClampU32(requested));
384 }
385}
386
387#undef PW_ALLOCATOR_ABSORB_SEMICOLON
388
389} // namespace internal
390} // namespace pw::allocator
Definition: allocator.h:34
Definition: metrics.h:193
void IncrementDeallocations()
Records that a call to Deallocate was made.
Definition: metrics.h:357
void RecordFailure(size_t requested)
Definition: metrics.h:378
void ModifyRequested(size_t increase, size_t decrease)
Definition: metrics.h:310
void IncrementReallocations()
Records that a call to Reallocate was made.
Definition: metrics.h:371
void IncrementAllocations()
Records that a call to Allocate was made.
Definition: metrics.h:350
void UpdateDeferred(Allocator &allocator)
Definition: metrics.h:252
void IncrementResizes()
Records that a call to Resize was made.
Definition: metrics.h:364
void ModifyAllocated(size_t increase, size_t decrease)
Definition: metrics.h:330
Definition: metrics.h:102
void UpdateDeferred(Allocator &)
Definition: metrics.h:114
Definition: metrics.h:171