C/C++ API Reference
Loading...
Searching...
No Matches
size_report.h
1// Copyright 2024 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 <array>
17#include <cstddef>
18#include <cstdint>
19#include <cstring>
20
21#include "pw_allocator/allocator.h"
22#include "pw_allocator/block/small_block.h"
23#include "pw_allocator/block_allocator.h"
24#include "pw_bloat/bloat_this_binary.h"
25#include "pw_bytes/span.h"
26
27namespace pw::allocator::size_report {
28
30
33
35struct Foo final {
36 std::array<std::byte, 16> buffer;
37};
38
40struct Bar {
41 Foo foo;
42 size_t number;
43
44 Bar(size_t number_) : number(number_) {
45 std::memset(foo.buffer.data(), 0, foo.buffer.size());
46 }
47};
48
50struct Baz {
51 Foo foo;
52 uint16_t id;
53};
54
57
62int SetBaseline(uint32_t mask);
63
69template <typename BlockType>
70int MeasureBlock(uint32_t mask);
71
77template <typename BucketType>
78int MeasureBucket(BucketType& bucket, uint32_t mask);
79
85int MeasureAllocator(Allocator& allocator, uint32_t mask);
86
92int MeasureBlockAllocator(BlockAllocator<BlockType>& allocator, uint32_t mask);
93
95
96// Template method implementations.
97
98template <typename BlockType>
99int MeasureBlock(uint32_t mask) {
100 if (SetBaseline(mask) != 0) {
101 return 1;
102 }
103
104 // Measure `Init`.
105 auto result = BlockType::Init(GetBuffer());
106 BlockType* block = *result;
107
108 // Measure `UsableSpace`.
109 std::byte* bytes = block->UsableSpace();
110
111 // Measure `FromUsableSpace`.
112 block = BlockType::FromUsableSpace(bytes);
113
114 if constexpr (is_allocatable_v<BlockType>) {
115 // Measure `AllocFirst`.
116 Layout foo = Layout::Of<Foo>();
117 auto block_result = BlockType::AllocFirst(std::move(block), foo);
118 if (!block_result.ok()) {
119 return 1;
120 }
121
122 BlockType* first_block = block_result.block();
123 block = first_block->Next();
124
125 // Measure `AllocLast`.
126 if constexpr (is_alignable_v<BlockType>) {
127 constexpr Layout kOverlyAligned(128, 64);
128 block_result = BlockType::AllocLast(std::move(block), kOverlyAligned);
129 } else {
130 Layout baz = Layout::Of<Baz>();
131 block_result = BlockType::AllocLast(std::move(block), baz);
132 }
133 if (!block_result.ok()) {
134 return 1;
135 }
136
137 BlockType* last_block = block_result.block();
138 block = last_block->Prev();
139
140 // Measure `Resize`.
141 block_result = block->Resize(sizeof(Bar));
142 if (!block_result.ok()) {
143 return 1;
144 }
145
146 // Measure `Free`.
147 block_result = BlockType::Free(std::move(first_block));
148 return block_result.ok() ? 0 : 1;
149 }
150}
151
152template <typename BucketType>
153int MeasureBucket(BucketType& bucket, uint32_t mask) {
154 if (int rc = SetBaseline(mask); rc != 0) {
155 return rc;
156 }
157 if (int rc = MeasureBlock<BlockType>(mask); rc != 0) {
158 return rc;
159 }
160
161 auto result = BlockType::Init(GetBuffer());
162 BlockType* unallocated = *result;
163
164 // Exercise `Add`.
165 std::array<BlockType*, 4> blocks;
166 for (size_t i = 0; i < blocks.size(); ++i) {
167 Layout layout(16 * (i + 1), 1);
168 auto block_result = BlockType::AllocFirst(std::move(unallocated), layout);
169 blocks[i] = block_result.block();
170 unallocated = blocks[i]->Next();
171 PW_BLOAT_COND(bucket.Add(*blocks[i]), mask);
172 }
173
174 // Exercise `Remove`.
175 PW_BLOAT_COND(bucket.Remove(*blocks[0]), mask);
176
177 // Exercise `RemoveCompatible`.
178 BlockType* compatible = bucket.RemoveCompatible(Layout(32, 1));
179 PW_BLOAT_COND(compatible != nullptr, mask);
180
181 // Exercise `RemoveAny`.
182 BlockType* any_block = bucket.RemoveAny();
183 PW_BLOAT_COND(any_block != nullptr, mask);
184
185 // Exercise `empty` and `Clear`.
186 PW_BLOAT_COND(!bucket.empty(), mask);
187 PW_BLOAT_EXPR(bucket.Clear(), mask);
188 return bucket.empty() ? 0 : 1;
189}
190
191} // namespace pw::allocator::size_report
Definition: allocator.h:36
Definition: block_allocator.h:106
Definition: layout.h:58
Definition: small_block.h:30
int MeasureAllocator(Allocator &allocator, uint32_t mask)
int SetBaseline(uint32_t mask)
int MeasureBucket(BucketType &bucket, uint32_t mask)
Definition: size_report.h:153
ByteSpan GetBuffer()
Returns a view of a statically allocated array of bytes.
int MeasureBlock(uint32_t mask)
Definition: size_report.h:99
int MeasureBlockAllocator(BlockAllocator< BlockType > &allocator, uint32_t mask)
#define PW_BLOAT_EXPR(expr, mask)
Definition: bloat_this_binary.h:78
#define PW_BLOAT_COND(cond, mask)
Definition: bloat_this_binary.h:51
Type used for exercising an allocator.
Definition: size_report.h:40
Type used for exercising an allocator.
Definition: size_report.h:50
Type used for exercising an allocator.
Definition: size_report.h:35