Pigweed
 
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
30using BlockType = SmallBlock;
31
33struct Foo final {
34 std::array<std::byte, 16> buffer;
35};
36
38struct Bar {
39 Foo foo;
40 size_t number;
41
42 Bar(size_t number_) : number(number_) {
43 std::memset(foo.buffer.data(), 0, foo.buffer.size());
44 }
45};
46
48struct Baz {
49 Foo foo;
50 uint16_t id;
51};
52
54ByteSpan GetBuffer();
55
60int SetBaseline(uint32_t mask);
61
67template <typename BlockType>
68int MeasureBlock(uint32_t mask);
69
75template <typename BucketType>
76int MeasureBucket(BucketType& bucket, uint32_t mask);
77
83int MeasureAllocator(Allocator& allocator, uint32_t mask);
84
90int MeasureBlockAllocator(BlockAllocator<BlockType>& allocator, uint32_t mask);
91
92// Template method implementations.
93
94template <typename BlockType>
95int MeasureBlock(uint32_t mask) {
96 if (SetBaseline(mask) != 0) {
97 return 1;
98 }
99
100 // Measure `Init`.
101 auto result = BlockType::Init(GetBuffer());
102 BlockType* block = *result;
103
104 // Measure `UsableSpace`.
105 std::byte* bytes = block->UsableSpace();
106
107 // Measure `FromUsableSpace`.
108 block = BlockType::FromUsableSpace(bytes);
109
110 if constexpr (is_allocatable_v<BlockType>) {
111 // Measure `AllocFirst`.
112 Layout foo = Layout::Of<Foo>();
113 auto block_result = BlockType::AllocFirst(std::move(block), foo);
114 if (!block_result.ok()) {
115 return 1;
116 }
117
118 BlockType* first_block = block_result.block();
119 block = first_block->Next();
120
121 // Measure `AllocLast`.
122 if constexpr (is_alignable_v<BlockType>) {
123 constexpr Layout kOverlyAligned(128, 64);
124 block_result = BlockType::AllocLast(std::move(block), kOverlyAligned);
125 } else {
126 Layout baz = Layout::Of<Baz>();
127 block_result = BlockType::AllocLast(std::move(block), baz);
128 }
129 if (!block_result.ok()) {
130 return 1;
131 }
132
133 BlockType* last_block = block_result.block();
134 block = last_block->Prev();
135
136 // Measure `Resize`.
137 block_result = block->Resize(sizeof(Bar));
138 if (!block_result.ok()) {
139 return 1;
140 }
141
142 // Measure `Free`.
143 block_result = BlockType::Free(std::move(first_block));
144 return block_result.ok() ? 0 : 1;
145 }
146}
147
148template <typename BucketType>
149int MeasureBucket(BucketType& bucket, uint32_t mask) {
150 if (int rc = SetBaseline(mask); rc != 0) {
151 return rc;
152 }
153 if (int rc = MeasureBlock<BlockType>(mask); rc != 0) {
154 return rc;
155 }
156
157 auto result = BlockType::Init(GetBuffer());
158 BlockType* unallocated = *result;
159
160 // Exercise `Add`.
161 std::array<BlockType*, 4> blocks;
162 for (size_t i = 0; i < blocks.size(); ++i) {
163 Layout layout(16 * (i + 1), 1);
164 auto block_result = BlockType::AllocFirst(std::move(unallocated), layout);
165 blocks[i] = block_result.block();
166 unallocated = blocks[i]->Next();
167 PW_BLOAT_COND(bucket.Add(*blocks[i]), mask);
168 }
169
170 // Exercise `Remove`.
171 PW_BLOAT_COND(bucket.Remove(*blocks[0]), mask);
172
173 // Exercise `RemoveCompatible`.
174 BlockType* compatible = bucket.RemoveCompatible(Layout(32, 1));
175 PW_BLOAT_COND(compatible != nullptr, mask);
176
177 // Exercise `RemoveAny`.
178 BlockType* any_block = bucket.RemoveAny();
179 PW_BLOAT_COND(any_block != nullptr, mask);
180
181 // Exercise `empty` and `Clear`.
182 PW_BLOAT_COND(!bucket.empty(), mask);
183 PW_BLOAT_EXPR(bucket.Clear(), mask);
184 return bucket.empty() ? 0 : 1;
185}
186
187} // namespace pw::allocator::size_report
Definition: allocator.h:34
Definition: block_allocator.h:104
Definition: layout.h:56
Type used for exercising an allocator.
Definition: size_report.h:38
Type used for exercising an allocator.
Definition: size_report.h:48
Type used for exercising an allocator.
Definition: size_report.h:33