xref: /aosp_15_r20/external/pigweed/pw_allocator/public/pw_allocator/size_reporter.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 #include <type_traits>
21 
22 #include "pw_assert/assert.h"
23 #include "pw_bloat/bloat_this_binary.h"
24 #include "pw_bytes/span.h"
25 
26 #ifndef PW_ALLOCATOR_SIZE_REPORTER_BASE
27 #include "pw_allocator/allocator.h"
28 #include "pw_allocator/null_allocator.h"
29 #endif  // PW_ALLOCATOR_SIZE_REPORTER_BASE
30 
31 namespace pw::allocator {
32 
33 /// Utility class for generating allocator size reports.
34 ///
35 /// The `pw_bloat` module can be used to compare the size of binaries. This
36 /// class facilitates creating binaries with and without a given allocator type.
37 ///
38 /// To create a size report:
39 ///   1. Make a copy of //pw_allocator/size_report/base.cc
40 ///   2. Instantiate your allocator and pass it to `MeasureAllocator`.
41 ///   3. Create build target(s) for your binary, and a `pw_size_diff` target
42 ///      that compares it to "$dir_pw_allocator/size_report:base".
43 class SizeReporter final {
44  public:
45   /// Nested type used for exercising an allocator.
46   struct Foo final {
47     std::array<std::byte, 16> buffer;
48   };
49 
50   /// Nested type used for exercising an allocator.
51   struct Bar {
52     Foo foo;
53     size_t number;
54 
BarBar55     Bar(size_t number_) : number(number_) {
56       std::memset(foo.buffer.data(), 0, foo.buffer.size());
57     }
58   };
59 
60   /// Nested type used for exercising an allocator.
61   struct Baz {
62     Foo foo;
63     uint16_t id;
64   };
65 
SetBaseline()66   void SetBaseline() {
67     pw::bloat::BloatThisBinary();
68     ByteSpan bytes = buffer();
69     Bar* bar = new (bytes.data()) Bar(0);
70     PW_ASSERT(bar != nullptr);
71     std::destroy_at(bar);
72 #ifndef PW_ALLOCATOR_SIZE_REPORTER_BASE
73     // Include the NullAllocator to bake in the costs of the base `Allocator`.
74     Allocator& allocator = GetNullAllocator();
75     PW_ASSERT(allocator.Allocate(Layout::Of<Foo>()) == nullptr);
76 #endif  // PW_ALLOCATOR_SIZE_REPORTER_BASE
77   }
78 
buffer()79   ByteSpan buffer() { return buffer_; }
80 
81 #ifndef PW_ALLOCATOR_SIZE_REPORTER_BASE
82   /// Exercises an allocator as part of a size report.
83   ///
84   /// @param[in]  allocator   The allocator to exercise. Will be ignored if not
85   ///                         derived from `Allocator`.
Measure(Allocator & allocator)86   void Measure(Allocator& allocator) {
87     // Measure `Layout::Of`.
88     Layout layout = Layout::Of<Foo>();
89 
90     // Measure `Allocate`.
91     void* ptr = allocator.Allocate(layout);
92 
93     // Measure `Reallocate`.
94     allocator.Resize(ptr, sizeof(Bar));
95 
96     // Measure `Reallocate`.
97     ptr = allocator.Reallocate(ptr, Layout::Of<Baz>());
98 
99     // Measure `Deallocate`.
100     allocator.Deallocate(ptr);
101 
102     // Measure `New`.
103     Foo* foo = allocator.template New<Foo>();
104 
105     // Measure `Delete`.
106     allocator.Delete(foo);
107 
108     // Measure `MakeUnique`.
109     UniquePtr<Foo> unique_foo = allocator.template MakeUnique<Foo>();
110     PW_ASSERT(ptr == nullptr || unique_foo != nullptr);
111   }
112 #endif  // PW_ALLOCATOR_SIZE_REPORTER_BASE
113 
114  private:
115   std::array<std::byte, 0x400> buffer_;
116 };
117 
118 }  // namespace pw::allocator
119