Pigweed
C/C++ API Reference
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
testing.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 <mutex>
18
19#include "pw_allocator/allocator.h"
20#include "pw_allocator/buffer.h"
21#include "pw_allocator/first_fit.h"
22#include "pw_allocator/hardening.h"
23#include "pw_allocator/metrics.h"
24#include "pw_allocator/tracking_allocator.h"
25#include "pw_assert/assert.h"
26#include "pw_bytes/span.h"
27#include "pw_result/result.h"
28#include "pw_status/status.h"
29#include "pw_tokenizer/tokenize.h"
30#include "pw_unit_test/framework.h"
31
32namespace pw::allocator::test {
33
34static_assert(Hardening::kIncludesDebugChecks,
35 "Tests must use a config that enables strict validation");
36
37// A token that can be used in tests.
38inline constexpr pw::tokenizer::Token kToken = PW_TOKENIZE_STRING("test");
39
41template <typename BlockType>
42void FreeAll(typename BlockType::Range range) {
43 BlockType* block = *(range.begin());
44 if (block == nullptr) {
45 return;
46 }
47
48 // Rewind to the first block.
49 BlockType* prev = block->Prev();
50 while (prev != nullptr) {
51 block = prev;
52 prev = block->Prev();
53 }
54
55 // Free and merge blocks.
56 while (block != nullptr) {
57 if (!block->IsFree()) {
58 auto result = BlockType::Free(std::move(block));
59 block = result.block();
60 }
61 block = block->Next();
62 }
63}
64
66template <size_t kBufferSize,
67 typename BlockType_ = FirstFitBlock<uint32_t>,
68 typename MetricsType = internal::AllMetrics>
70 public:
71 using BlockType = BlockType_;
73
74 // Since the unbderlying first-fit allocator uses an intrusive free list, all
75 // allocations will be at least this size.
76 static constexpr size_t kMinSize = BlockType::kAlignment;
77
79 : Allocator(AllocatorType::kCapabilities), tracker_(kToken, *allocator_) {
81 allocator_->Init(allocator_.as_bytes());
82 }
83
84 ~AllocatorForTest() override { FreeAll<BlockType>(blocks()); }
85
86 typename BlockType::Range blocks() const { return allocator_->blocks(); }
87 typename BlockType::Range blocks() { return allocator_->blocks(); }
88
89 const metric::Group& metric_group() const { return tracker_.metric_group(); }
90 metric::Group& metric_group() { return tracker_.metric_group(); }
91
92 const MetricsType& metrics() const { return tracker_.metrics(); }
93
94 size_t allocate_size() const { return allocate_size_; }
95 void* deallocate_ptr() const { return deallocate_ptr_; }
96 size_t deallocate_size() const { return deallocate_size_; }
97 void* resize_ptr() const { return resize_ptr_; }
98 size_t resize_old_size() const { return resize_old_size_; }
99 size_t resize_new_size() const { return resize_new_size_; }
100
103 allocate_size_ = 0;
104 deallocate_ptr_ = nullptr;
105 deallocate_size_ = 0;
106 resize_ptr_ = nullptr;
107 resize_old_size_ = 0;
108 resize_new_size_ = 0;
109 }
110
112 void Exhaust() {
113 for (auto* block : allocator_->blocks()) {
114 if (block->IsFree()) {
115 auto result = BlockType::AllocLast(std::move(block),
116 Layout(block->InnerSize(), 1));
117 PW_ASSERT(result.status() == OkStatus());
118
119 using Prev = internal::GenericBlockResult::Prev;
120 PW_ASSERT(result.prev() == Prev::kUnchanged);
121
122 using Next = internal::GenericBlockResult::Next;
123 PW_ASSERT(result.next() == Next::kUnchanged);
124 }
125 }
126 }
127
130 return allocator_->MeasureFragmentation();
131 }
132
133 private:
135 void* DoAllocate(Layout layout) override {
136 allocate_size_ = layout.size();
137 void* ptr = tracker_.Allocate(layout);
138 return ptr;
139 }
140
142 void DoDeallocate(void* ptr) override {
143 Result<Layout> requested = GetRequestedLayout(ptr);
144 deallocate_ptr_ = ptr;
145 deallocate_size_ = requested.ok() ? requested->size() : 0;
146 tracker_.Deallocate(ptr);
147 }
148
150 void DoDeallocate(void* ptr, Layout) override { DoDeallocate(ptr); }
151
153 bool DoResize(void* ptr, size_t new_size) override {
154 Result<Layout> requested = GetRequestedLayout(ptr);
155 resize_ptr_ = ptr;
156 resize_old_size_ = requested.ok() ? requested->size() : 0;
157 resize_new_size_ = new_size;
158 return tracker_.Resize(ptr, new_size);
159 }
160
162 size_t DoGetAllocated() const override { return tracker_.GetAllocated(); }
163
165 Result<Layout> DoGetInfo(InfoType info_type, const void* ptr) const override {
166 return GetInfo(tracker_, info_type, ptr);
167 }
168
171 size_t allocate_size_;
172 void* deallocate_ptr_;
173 size_t deallocate_size_;
174 void* resize_ptr_;
175 size_t resize_old_size_;
176 size_t resize_new_size_;
177};
178
179} // namespace pw::allocator::test
Definition: allocator.h:34
constexpr Allocator()=default
TODO(b/326509341): Remove when downstream consumers migrate.
Definition: first_fit.h:39
Definition: layout.h:56
Definition: tracking_allocator.h:47
Definition: buffer.h:52
An AllocatorForTest that is automatically initialized on construction.
Definition: testing.h:69
size_t DoGetAllocated() const override
Definition: testing.h:162
Result< Layout > DoGetInfo(InfoType info_type, const void *ptr) const override
Definition: testing.h:165
void * DoAllocate(Layout layout) override
Definition: testing.h:135
Fragmentation MeasureFragmentation() const
Returns fragmentation information for the block allocator's memory region.
Definition: testing.h:129
void ResetParameters()
Resets the recorded parameters to an initial state.
Definition: testing.h:102
void DoDeallocate(void *ptr) override
Definition: testing.h:142
void Exhaust()
Allocates all the memory from this object.
Definition: testing.h:112
bool DoResize(void *ptr, size_t new_size) override
Definition: testing.h:153
void DoDeallocate(void *ptr, Layout) override
Definition: testing.h:150
constexpr Status OkStatus()
Definition: status.h:234
Definition: fragmentation.h:44