C/C++ API Reference
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
26
62#define PW_ALLOCATOR_METRICS_FOREACH(fn) \
63 fn(requested_bytes); \
64 fn(peak_requested_bytes); \
65 fn(cumulative_requested_bytes); \
66 fn(allocated_bytes); \
67 fn(peak_allocated_bytes); \
68 fn(cumulative_allocated_bytes); \
69 fn(num_allocations); \
70 fn(num_deallocations); \
71 fn(num_resizes); \
72 fn(num_reallocations); \
73 fn(num_free_blocks); \
74 fn(smallest_free_block_size); \
75 fn(largest_free_block_size); \
76 fn(num_failures); \
77 fn(unfulfilled_bytes)
78
79#define PW_ALLOCATOR_ABSORB_SEMICOLON() static_assert(true)
80
91#define PW_ALLOCATOR_METRICS_DECLARE(metric_name) \
92 static constexpr bool has_##metric_name() { return false; } \
93 ::pw::StatusWithSize get_##metric_name() const { \
94 return ::pw::StatusWithSize::NotFound(); \
95 } \
96 static constexpr bool metric_name##_enabled() { return false; } \
97 PW_ALLOCATOR_ABSORB_SEMICOLON()
98
104struct NoMetrics {
106
117};
118
119#undef PW_ALLOCATOR_METRICS_DECLARE
120
132#define PW_ALLOCATOR_METRICS_INCLUDE(metric_name) \
133 static_assert(!::pw::allocator::NoMetrics::has_##metric_name()); \
134 static constexpr bool has_##metric_name() { return true; } \
135 inline ::pw::StatusWithSize get_##metric_name() const { \
136 return ::pw::StatusWithSize(metric_name.value()); \
137 } \
138 PW_METRIC(metric_name, #metric_name, 0U)
139
162#define PW_ALLOCATOR_METRICS_ENABLE(metric_name) \
163 static constexpr bool metric_name##_enabled() { return true; } \
164 PW_ALLOCATOR_METRICS_INCLUDE(metric_name)
165
166namespace internal {
167
173struct AllMetrics : public NoMetrics {
175};
176
179template <typename MetricsType>
180constexpr bool AnyEnabled();
181
183template <typename MetricsType>
184void CopyMetrics(const MetricsType& src, MetricsType& dst);
185
194template <typename MetricsType>
195class Metrics final {
196 public:
197 Metrics(metric::Token token);
198 ~Metrics() = default;
199
200 const metric::Group& group() const { return group_; }
201 metric::Group& group() { return group_; }
202
203 const MetricsType& metrics() const { return metrics_; }
204
212 void ModifyRequested(size_t increase, size_t decrease);
213
228 void ModifyAllocated(size_t increase, size_t decrease);
229
232
235
238
241
249 void RecordFailure(size_t requested);
250
254 void UpdateDeferred(Allocator& allocator) {
255 metrics_.UpdateDeferred(allocator);
256 }
257
258 private:
259 metric::Group group_;
260 MetricsType metrics_;
261};
262
264inline uint32_t ClampU32(size_t size) {
265 return static_cast<uint32_t>(std::min(
266 size, static_cast<size_t>(std::numeric_limits<uint32_t>::max())));
267}
268
270
271// Template method implementations.
272
273template <typename MetricsType>
274constexpr bool AnyEnabled() {
275#define PW_ALLOCATOR_RETURN_IF_ENABLED(metric_name) \
276 if (MetricsType::metric_name##_enabled()) { \
277 return true; \
278 } \
279 PW_ALLOCATOR_ABSORB_SEMICOLON()
280
281 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_RETURN_IF_ENABLED);
282 return false;
283
284#undef PW_ALLOCATOR_RETURN_IF_ENABLED
285}
286
287template <typename MetricsType>
288void CopyMetrics(const MetricsType& src, MetricsType& dst) {
289#define PW_ALLOCATOR_COPY_METRIC(metric_name) \
290 if constexpr (MetricsType::has_##metric_name()) { \
291 dst.metric_name.Set(src.metric_name.value()); \
292 } \
293 PW_ALLOCATOR_ABSORB_SEMICOLON()
294
295 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_COPY_METRIC);
296
297#undef PW_ALLOCATOR_COPY_METRIC
298}
299
300template <typename MetricsType>
301Metrics<MetricsType>::Metrics(metric::Token token) : group_(token) {
302#define PW_ALLOCATOR_ADD_TO_GROUP(metric_name) \
303 if constexpr (MetricsType::has_##metric_name()) { \
304 group_.Add(metrics_.metric_name); \
305 } \
306 PW_ALLOCATOR_ABSORB_SEMICOLON()
307
308 PW_ALLOCATOR_METRICS_FOREACH(PW_ALLOCATOR_ADD_TO_GROUP);
309
310#undef PW_ALLOCATOR_ADD_TO_GROUP
311}
312
313template <typename MetricsType>
314void Metrics<MetricsType>::ModifyRequested(size_t increase, size_t decrease) {
315 if constexpr (MetricsType::requested_bytes_enabled()) {
316 metrics_.requested_bytes.Increment(internal::ClampU32(increase));
317 metrics_.requested_bytes.Decrement(internal::ClampU32(decrease));
318 if constexpr (MetricsType::peak_requested_bytes_enabled()) {
319 uint32_t requested_bytes = metrics_.requested_bytes.value();
320 if (metrics_.peak_requested_bytes.value() < requested_bytes) {
321 metrics_.peak_requested_bytes.Set(requested_bytes);
322 }
323 }
324 if constexpr (MetricsType::cumulative_requested_bytes_enabled()) {
325 if (increase > decrease) {
326 metrics_.cumulative_requested_bytes.Increment(
327 internal::ClampU32(increase - decrease));
328 }
329 }
330 }
331}
332
333template <typename MetricsType>
334void Metrics<MetricsType>::ModifyAllocated(size_t increase, size_t decrease) {
335 if constexpr (MetricsType::allocated_bytes_enabled()) {
336 metrics_.allocated_bytes.Increment(internal::ClampU32(increase));
337 metrics_.allocated_bytes.Decrement(internal::ClampU32(decrease));
338 if constexpr (MetricsType::peak_allocated_bytes_enabled()) {
339 uint32_t allocated_bytes = metrics_.allocated_bytes.value();
340 if (metrics_.peak_allocated_bytes.value() < allocated_bytes) {
341 metrics_.peak_allocated_bytes.Set(allocated_bytes);
342 }
343 }
344 if constexpr (MetricsType::cumulative_allocated_bytes_enabled()) {
345 if (increase > decrease) {
346 metrics_.cumulative_allocated_bytes.Increment(
347 internal::ClampU32(increase - decrease));
348 }
349 }
350 }
351}
352
353template <typename MetricsType>
355 if constexpr (MetricsType::num_allocations_enabled()) {
356 metrics_.num_allocations.Increment();
357 }
358}
359
360template <typename MetricsType>
362 if constexpr (MetricsType::num_deallocations_enabled()) {
363 metrics_.num_deallocations.Increment();
364 }
365}
366
367template <typename MetricsType>
369 if constexpr (MetricsType::num_resizes_enabled()) {
370 metrics_.num_resizes.Increment();
371 }
372}
373
374template <typename MetricsType>
376 if constexpr (MetricsType::num_reallocations_enabled()) {
377 metrics_.num_reallocations.Increment();
378 }
379}
380
381template <typename MetricsType>
383 if constexpr (MetricsType::num_failures_enabled()) {
384 metrics_.num_failures.Increment();
385 }
386 if constexpr (MetricsType::unfulfilled_bytes_enabled()) {
387 metrics_.unfulfilled_bytes.Increment(internal::ClampU32(requested));
388 }
389}
390
391#undef PW_ALLOCATOR_ABSORB_SEMICOLON
392
393} // namespace internal
394} // namespace pw::allocator
Definition: allocator.h:36
Definition: metrics.h:195
void IncrementDeallocations()
Records that a call to Deallocate was made.
Definition: metrics.h:361
void RecordFailure(size_t requested)
Definition: metrics.h:382
void ModifyRequested(size_t increase, size_t decrease)
Definition: metrics.h:314
void IncrementReallocations()
Records that a call to Reallocate was made.
Definition: metrics.h:375
void IncrementAllocations()
Records that a call to Allocate was made.
Definition: metrics.h:354
void UpdateDeferred(Allocator &allocator)
Definition: metrics.h:254
void IncrementResizes()
Records that a call to Resize was made.
Definition: metrics.h:368
void ModifyAllocated(size_t increase, size_t decrease)
Definition: metrics.h:334
constexpr bool AnyEnabled()
Definition: metrics.h:274
uint32_t ClampU32(size_t size)
Helper method for converting size_ts to uint32_ts.
Definition: metrics.h:264
#define PW_ALLOCATOR_METRICS_ENABLE(metric_name)
Definition: metrics.h:162
#define PW_ALLOCATOR_METRICS_DECLARE(metric_name)
Definition: metrics.h:91
void UpdateDeferred(Allocator &)
Definition: metrics.h:116
#define PW_ALLOCATOR_METRICS_FOREACH(fn)
Definition: metrics.h:62
void CopyMetrics(const MetricsType &src, MetricsType &dst)
Copies the values enabled for a given MetricsType from src to dst.
Definition: metrics.h:288
Definition: metrics.h:104
Definition: metrics.h:173