xref: /aosp_15_r20/external/pigweed/seed/0110.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _seed-0110:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker==================================
4*61c4878aSAndroid Build Coastguard Worker0110: Memory Allocation Interfaces
5*61c4878aSAndroid Build Coastguard Worker==================================
6*61c4878aSAndroid Build Coastguard Worker.. seed::
7*61c4878aSAndroid Build Coastguard Worker   :number: 110
8*61c4878aSAndroid Build Coastguard Worker   :name: Memory Allocation Interfaces
9*61c4878aSAndroid Build Coastguard Worker   :status: Accepted
10*61c4878aSAndroid Build Coastguard Worker   :proposal_date: 2023-09-06
11*61c4878aSAndroid Build Coastguard Worker   :cl: 168772
12*61c4878aSAndroid Build Coastguard Worker   :authors: Alexei Frolov
13*61c4878aSAndroid Build Coastguard Worker   :facilitator: Taylor Cramer
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker-------
16*61c4878aSAndroid Build Coastguard WorkerSummary
17*61c4878aSAndroid Build Coastguard Worker-------
18*61c4878aSAndroid Build Coastguard WorkerWith dynamic memory allocation becoming more common in embedded devices, Pigweed
19*61c4878aSAndroid Build Coastguard Workershould provide standardized interfaces for working with different memory
20*61c4878aSAndroid Build Coastguard Workerallocators, giving both upstream and downstream developers the flexibility to
21*61c4878aSAndroid Build Coastguard Workermove beyond manually sizing their modules' resource pools.
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker----------
24*61c4878aSAndroid Build Coastguard WorkerMotivation
25*61c4878aSAndroid Build Coastguard Worker----------
26*61c4878aSAndroid Build Coastguard WorkerTraditionally, most embedded firmware have laid out their systems' memory usage
27*61c4878aSAndroid Build Coastguard Workerstatically, with every component's buffers and resources set at compile time.
28*61c4878aSAndroid Build Coastguard WorkerAs systems grow larger and more complex, the ability to dynamically allocate
29*61c4878aSAndroid Build Coastguard Workermemory has become more desirable by firmware authors.
30*61c4878aSAndroid Build Coastguard Worker
31*61c4878aSAndroid Build Coastguard WorkerPigweed has made basic explorations into dynamic allocation in the past: the
32*61c4878aSAndroid Build Coastguard Worker``pw_allocator`` provides basic building blocks which projects can use to
33*61c4878aSAndroid Build Coastguard Workerassemble their own allocators. ``pw_allocator`` also provides a proof-of-concept
34*61c4878aSAndroid Build Coastguard Workerallocator (``FreeListHeap``) based off of these building blocks.
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard WorkerSince then, Pigweed has become a part of more complex projects and has
37*61c4878aSAndroid Build Coastguard Workerdeveloped more advanced capabilities into its own modules. As the project has
38*61c4878aSAndroid Build Coastguard Workerprogressed, several developers --- both on the core and customer teams --- have
39*61c4878aSAndroid Build Coastguard Workernoted areas where dynamic allocation would simplify code and improve memory
40*61c4878aSAndroid Build Coastguard Workerusage by enabling sharing and eliminating large reservations.
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker--------
43*61c4878aSAndroid Build Coastguard WorkerProposal
44*61c4878aSAndroid Build Coastguard Worker--------
45*61c4878aSAndroid Build Coastguard Worker
46*61c4878aSAndroid Build Coastguard WorkerAllocator Interfaces
47*61c4878aSAndroid Build Coastguard Worker====================
48*61c4878aSAndroid Build Coastguard WorkerThe core of the ``pw_allocator`` module will define abstract interfaces for
49*61c4878aSAndroid Build Coastguard Workermemory allocation. Several interfaces are provided with different allocator
50*61c4878aSAndroid Build Coastguard Workerproperties, all of which inherit from a base generic ``Allocator``.
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard WorkerCore Allocators
53*61c4878aSAndroid Build Coastguard Worker---------------
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard WorkerAllocator
56*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard Worker   class Allocator {
61*61c4878aSAndroid Build Coastguard Worker    public:
62*61c4878aSAndroid Build Coastguard Worker     class Layout {
63*61c4878aSAndroid Build Coastguard Worker      public:
64*61c4878aSAndroid Build Coastguard Worker       constexpr Layout(
65*61c4878aSAndroid Build Coastguard Worker           size_t size, std::align_val_t alignment = alignof(std::max_align_t))
66*61c4878aSAndroid Build Coastguard Worker           : size_(size), alignment_(alignment) {}
67*61c4878aSAndroid Build Coastguard Worker
68*61c4878aSAndroid Build Coastguard Worker       // Creates a Layout for the given type.
69*61c4878aSAndroid Build Coastguard Worker       template <typename T>
70*61c4878aSAndroid Build Coastguard Worker       static constexpr Layout Of() {
71*61c4878aSAndroid Build Coastguard Worker         return Layout(sizeof(T), alignof(T));
72*61c4878aSAndroid Build Coastguard Worker       }
73*61c4878aSAndroid Build Coastguard Worker
74*61c4878aSAndroid Build Coastguard Worker       size_t size() const { return size_; }
75*61c4878aSAndroid Build Coastguard Worker       size_t alignment() const { return alignment_; }
76*61c4878aSAndroid Build Coastguard Worker
77*61c4878aSAndroid Build Coastguard Worker      private:
78*61c4878aSAndroid Build Coastguard Worker       size_t size_;
79*61c4878aSAndroid Build Coastguard Worker       size_t alignment_;
80*61c4878aSAndroid Build Coastguard Worker     };
81*61c4878aSAndroid Build Coastguard Worker
82*61c4878aSAndroid Build Coastguard Worker     template <typename T, typename... Args>
83*61c4878aSAndroid Build Coastguard Worker     T* New(Args&&... args);
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker     template <typename T>
86*61c4878aSAndroid Build Coastguard Worker     void Delete(T* obj);
87*61c4878aSAndroid Build Coastguard Worker
88*61c4878aSAndroid Build Coastguard Worker     template <typename T, typename... Args>
89*61c4878aSAndroid Build Coastguard Worker     std::optional<UniquePtr<T>> MakeUnique(Args&&... args);
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker     void* Allocate(Layout layout) {
92*61c4878aSAndroid Build Coastguard Worker       return DoAllocate(layout);
93*61c4878aSAndroid Build Coastguard Worker     }
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard Worker     void Deallocate(void* ptr, Layout layout) {
96*61c4878aSAndroid Build Coastguard Worker       return DoDeallocate(layout);
97*61c4878aSAndroid Build Coastguard Worker     }
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker     bool Resize(void* ptr, Layout old_layout, size_t new_size) {
100*61c4878aSAndroid Build Coastguard Worker       if (ptr == nullptr) {
101*61c4878aSAndroid Build Coastguard Worker         return false;
102*61c4878aSAndroid Build Coastguard Worker       }
103*61c4878aSAndroid Build Coastguard Worker       return DoResize(ptr, old_layout, new_size);
104*61c4878aSAndroid Build Coastguard Worker     }
105*61c4878aSAndroid Build Coastguard Worker
106*61c4878aSAndroid Build Coastguard Worker     void* Reallocate(void* ptr, Layout old_layout, size_t new_size) {
107*61c4878aSAndroid Build Coastguard Worker       return DoReallocate(void* ptr, Layout old_layout, size_t new_size);
108*61c4878aSAndroid Build Coastguard Worker     }
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard Worker    protected:
111*61c4878aSAndroid Build Coastguard Worker     virtual void* DoAllocate(Layout layout) = 0;
112*61c4878aSAndroid Build Coastguard Worker     virtual void DoDeallocate(void* ptr, Layout layout) = 0;
113*61c4878aSAndroid Build Coastguard Worker
114*61c4878aSAndroid Build Coastguard Worker     virtual bool DoResize(void* ptr, Layout old_layout, size_t new_size) {
115*61c4878aSAndroid Build Coastguard Worker       return false;
116*61c4878aSAndroid Build Coastguard Worker     }
117*61c4878aSAndroid Build Coastguard Worker
118*61c4878aSAndroid Build Coastguard Worker     virtual void* DoReallocate(void* ptr, Layout old_layout, size_t new_size) {
119*61c4878aSAndroid Build Coastguard Worker       if (new_size == 0) {
120*61c4878aSAndroid Build Coastguard Worker         DoDeallocate(ptr, old_layout);
121*61c4878aSAndroid Build Coastguard Worker         return nullptr;
122*61c4878aSAndroid Build Coastguard Worker       }
123*61c4878aSAndroid Build Coastguard Worker
124*61c4878aSAndroid Build Coastguard Worker       if (DoResize(ptr, old_layout, new_size)) {
125*61c4878aSAndroid Build Coastguard Worker         return ptr;
126*61c4878aSAndroid Build Coastguard Worker       }
127*61c4878aSAndroid Build Coastguard Worker
128*61c4878aSAndroid Build Coastguard Worker       void* new_ptr = DoAllocate(new_layout);
129*61c4878aSAndroid Build Coastguard Worker       if (new_ptr == nullptr) {
130*61c4878aSAndroid Build Coastguard Worker         return nullptr;
131*61c4878aSAndroid Build Coastguard Worker       }
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard Worker       if (ptr != nullptr && old_layout.size() != 0) {
134*61c4878aSAndroid Build Coastguard Worker         std::memcpy(new_ptr, ptr, std::min(old_layout.size(), new_size));
135*61c4878aSAndroid Build Coastguard Worker         DoDeallocate(ptr, old_layout);
136*61c4878aSAndroid Build Coastguard Worker       }
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker       return new_ptr;
139*61c4878aSAndroid Build Coastguard Worker     }
140*61c4878aSAndroid Build Coastguard Worker   };
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker``Allocator`` is the most generic and fundamental interface provided by the
143*61c4878aSAndroid Build Coastguard Workermodule, representing any object capable of dynamic memory allocation.
144*61c4878aSAndroid Build Coastguard Worker
145*61c4878aSAndroid Build Coastguard WorkerThe ``Allocator`` interface makes no guarantees about its implementation.
146*61c4878aSAndroid Build Coastguard WorkerConsumers of the generic interface must not make any assumptions around
147*61c4878aSAndroid Build Coastguard Workerallocator behavior, thread safety, or performance.
148*61c4878aSAndroid Build Coastguard Worker
149*61c4878aSAndroid Build Coastguard Worker**Layout**
150*61c4878aSAndroid Build Coastguard Worker
151*61c4878aSAndroid Build Coastguard WorkerAllocation parameters are passed to the allocator through a ``Layout`` object.
152*61c4878aSAndroid Build Coastguard WorkerThis object ensures that the values provided to the allocator are valid, as well
153*61c4878aSAndroid Build Coastguard Workeras providing some convenient helper functions for common allocation use cases,
154*61c4878aSAndroid Build Coastguard Workersuch as allocating space for a specific type of object.
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker**Virtual functions**
157*61c4878aSAndroid Build Coastguard Worker
158*61c4878aSAndroid Build Coastguard WorkerImplementers of the allocator interface are responsible for providing the
159*61c4878aSAndroid Build Coastguard Workerfollowing operations:
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard Worker* ``DoAllocate`` (required): Obtains a block of memory from the allocator with a
162*61c4878aSAndroid Build Coastguard Worker  requested size and power-of-two alignment. Returns ``nullptr`` if the
163*61c4878aSAndroid Build Coastguard Worker  allocation cannot be performed.
164*61c4878aSAndroid Build Coastguard Worker
165*61c4878aSAndroid Build Coastguard Worker  The size and alignment values in the provided layout are guaranteed to be
166*61c4878aSAndroid Build Coastguard Worker  valid.
167*61c4878aSAndroid Build Coastguard Worker
168*61c4878aSAndroid Build Coastguard Worker  Memory returned from ``DoAllocate`` is uninitialized.
169*61c4878aSAndroid Build Coastguard Worker
170*61c4878aSAndroid Build Coastguard Worker* ``DoDeallocate`` (required): Releases a block of memory back to the allocator.
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard Worker  If ``ptr`` is ``nullptr``, does nothing.
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker  If ``ptr`` was not previously obtained from this allocator the behavior is
175*61c4878aSAndroid Build Coastguard Worker  undefined.
176*61c4878aSAndroid Build Coastguard Worker
177*61c4878aSAndroid Build Coastguard Worker* ``DoResize`` (optional): Extends or shrinks a previously-allocated block of
178*61c4878aSAndroid Build Coastguard Worker  memory in place. If this operation cannot be performed, returns ``false``.
179*61c4878aSAndroid Build Coastguard Worker
180*61c4878aSAndroid Build Coastguard Worker  ``ptr`` is guaranteed to be non-null. If ``ptr`` was not previously obtained
181*61c4878aSAndroid Build Coastguard Worker  from this allocator the behavior is undefined.
182*61c4878aSAndroid Build Coastguard Worker
183*61c4878aSAndroid Build Coastguard Worker  If the allocated block is grown, the memory in the extended region is
184*61c4878aSAndroid Build Coastguard Worker  uninitialized.
185*61c4878aSAndroid Build Coastguard Worker
186*61c4878aSAndroid Build Coastguard Worker* ``DoReallocate`` (optional): Extends or shrinks a previously-allocated block
187*61c4878aSAndroid Build Coastguard Worker  of memory, potentially copying its data to a different location. A default
188*61c4878aSAndroid Build Coastguard Worker  implementation is provided, which first attempts to call ``Resize``, falling
189*61c4878aSAndroid Build Coastguard Worker  back to allocating a new block and copying data if it fails.
190*61c4878aSAndroid Build Coastguard Worker
191*61c4878aSAndroid Build Coastguard Worker  If ``ptr`` is ``nullptr``, behaves identically to ``Allocate(new_layout)``.
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard Worker  If the new block cannot be allocated, returns ``nullptr``, leaving the
194*61c4878aSAndroid Build Coastguard Worker  original allocation intact.
195*61c4878aSAndroid Build Coastguard Worker
196*61c4878aSAndroid Build Coastguard Worker  If ``new_layout.size == 0``, frees the old block and returns ``nullptr``.
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard Worker  If the allocated block is grown, the memory in the extended region is
199*61c4878aSAndroid Build Coastguard Worker  uninitialized.
200*61c4878aSAndroid Build Coastguard Worker
201*61c4878aSAndroid Build Coastguard Worker**Provided functions**
202*61c4878aSAndroid Build Coastguard Worker
203*61c4878aSAndroid Build Coastguard Worker* ``New``: Allocates memory for an object from the allocator and constructs it.
204*61c4878aSAndroid Build Coastguard Worker
205*61c4878aSAndroid Build Coastguard Worker* ``Delete``: Destructs and releases memory for a previously-allocated object.
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker* ``MakeUnique``: Allocates and constructs an object wrapped in a ``UniquePtr``
208*61c4878aSAndroid Build Coastguard Worker  which owns it and manages its release.
209*61c4878aSAndroid Build Coastguard Worker
210*61c4878aSAndroid Build Coastguard WorkerAllocator Utilities
211*61c4878aSAndroid Build Coastguard Worker===================
212*61c4878aSAndroid Build Coastguard WorkerIn addition to allocator interfaces, ``pw_allocator`` will provide utilities for
213*61c4878aSAndroid Build Coastguard Workerworking with allocators in a system.
214*61c4878aSAndroid Build Coastguard Worker
215*61c4878aSAndroid Build Coastguard WorkerUniquePtr
216*61c4878aSAndroid Build Coastguard Worker---------
217*61c4878aSAndroid Build Coastguard Worker``pw::allocator::UniquePtr`` is a "smart pointer" analogous to
218*61c4878aSAndroid Build Coastguard Worker``std::unique_ptr``, designed to work with Pigweed allocators. It owns and
219*61c4878aSAndroid Build Coastguard Workermanages an allocated object, automatically deallocating its memory when it goes
220*61c4878aSAndroid Build Coastguard Workerout of scope.
221*61c4878aSAndroid Build Coastguard Worker
222*61c4878aSAndroid Build Coastguard WorkerUnlike ``std::unique_ptr``, Pigweed's ``UniquePtr`` cannot be manually
223*61c4878aSAndroid Build Coastguard Workerconstructed from an existing non-null pointer; it must be done through the
224*61c4878aSAndroid Build Coastguard Worker``Allocator::MakeUnique`` API. This is required as the allocator associated with
225*61c4878aSAndroid Build Coastguard Workerthe object allocation must be known in order to release it.
226*61c4878aSAndroid Build Coastguard Worker
227*61c4878aSAndroid Build Coastguard WorkerUsage reporting
228*61c4878aSAndroid Build Coastguard Worker---------------
229*61c4878aSAndroid Build Coastguard Worker``pw_allocator`` will not require any usage reporting as part of its core
230*61c4878aSAndroid Build Coastguard Workerinterfaces to keep them minimal and reduce implementation burden.
231*61c4878aSAndroid Build Coastguard Worker
232*61c4878aSAndroid Build Coastguard WorkerHowever, ``pw_allocator`` encourages setting up reporting and will provide
233*61c4878aSAndroid Build Coastguard Workerutilities for doing so. Initially, this consists of a layered proxy allocator
234*61c4878aSAndroid Build Coastguard Workerwhich wraps another allocator implementation with basic usage reporting through
235*61c4878aSAndroid Build Coastguard Worker``pw_metric``.
236*61c4878aSAndroid Build Coastguard Worker
237*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
238*61c4878aSAndroid Build Coastguard Worker
239*61c4878aSAndroid Build Coastguard Worker   class AllocatorMetricProxy : public Allocator {
240*61c4878aSAndroid Build Coastguard Worker    public:
241*61c4878aSAndroid Build Coastguard Worker     constexpr explicit AllocatorMetricProxy(metric::Token token)
242*61c4878aSAndroid Build Coastguard Worker         : memusage_(token) {}
243*61c4878aSAndroid Build Coastguard Worker
244*61c4878aSAndroid Build Coastguard Worker     // Sets the wrapped allocator.
245*61c4878aSAndroid Build Coastguard Worker     void Initialize(Allocator& allocator);
246*61c4878aSAndroid Build Coastguard Worker
247*61c4878aSAndroid Build Coastguard Worker     // Exposed usage statistics.
248*61c4878aSAndroid Build Coastguard Worker     metric::Group& memusage() { return memusage_; }
249*61c4878aSAndroid Build Coastguard Worker     size_t used() const { return used_.value(); }
250*61c4878aSAndroid Build Coastguard Worker     size_t peak() const { return peak_.value(); }
251*61c4878aSAndroid Build Coastguard Worker     size_t count() const { return count_.value(); }
252*61c4878aSAndroid Build Coastguard Worker
253*61c4878aSAndroid Build Coastguard Worker     // Implements the Allocator interface by forwarding through to the
254*61c4878aSAndroid Build Coastguard Worker     // sub-allocator provided to Initialize.
255*61c4878aSAndroid Build Coastguard Worker
256*61c4878aSAndroid Build Coastguard Worker   };
257*61c4878aSAndroid Build Coastguard Worker
258*61c4878aSAndroid Build Coastguard WorkerIntegration with C++ polymorphic memory resources
259*61c4878aSAndroid Build Coastguard Worker-------------------------------------------------
260*61c4878aSAndroid Build Coastguard WorkerThe C++ standard library has similar allocator interfaces to those proposed
261*61c4878aSAndroid Build Coastguard Workerdefined as part of its PMR library. The reasons why Pigweed is not using these
262*61c4878aSAndroid Build Coastguard Workerdirectly are :ref:`described below <seed-0110-why-not-pmr>`; however, Pigweed
263*61c4878aSAndroid Build Coastguard Workerwill provide a wrapper which exposes a Pigweed allocator through the PMR
264*61c4878aSAndroid Build Coastguard Worker``memory_resource`` interface. An example of how this wrapper might look is
265*61c4878aSAndroid Build Coastguard Workerpresented here.
266*61c4878aSAndroid Build Coastguard Worker
267*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
268*61c4878aSAndroid Build Coastguard Worker
269*61c4878aSAndroid Build Coastguard Worker   template <typename Allocator>
270*61c4878aSAndroid Build Coastguard Worker   class MemoryResource : public std::pmr::memory_resource {
271*61c4878aSAndroid Build Coastguard Worker    public:
272*61c4878aSAndroid Build Coastguard Worker     template <typename... Args>
273*61c4878aSAndroid Build Coastguard Worker     MemoryResource(Args&&... args) : allocator_(std::forward<Args>(args)...) {}
274*61c4878aSAndroid Build Coastguard Worker
275*61c4878aSAndroid Build Coastguard Worker    private:
276*61c4878aSAndroid Build Coastguard Worker     void* do_allocate(size_t bytes, size_t alignment) override {
277*61c4878aSAndroid Build Coastguard Worker       void* p = allocator_.Allocate(bytes, alignment);
278*61c4878aSAndroid Build Coastguard Worker       PW_ASSERT(p != nullptr);  // Cannot throw in Pigweed code.
279*61c4878aSAndroid Build Coastguard Worker       return p;
280*61c4878aSAndroid Build Coastguard Worker     }
281*61c4878aSAndroid Build Coastguard Worker
282*61c4878aSAndroid Build Coastguard Worker     void do_deallocate(void* p, size_t bytes, size_t alignment) override {
283*61c4878aSAndroid Build Coastguard Worker       allocator_.Deallocate(p, bytes, alignment);
284*61c4878aSAndroid Build Coastguard Worker     }
285*61c4878aSAndroid Build Coastguard Worker
286*61c4878aSAndroid Build Coastguard Worker     bool do_is_equal(const std::pmr::memory_resource&) override {
287*61c4878aSAndroid Build Coastguard Worker       // Pigweed allocators do not yet support the concept of equality; this
288*61c4878aSAndroid Build Coastguard Worker       // remains an open question for the future.
289*61c4878aSAndroid Build Coastguard Worker       return false;
290*61c4878aSAndroid Build Coastguard Worker     }
291*61c4878aSAndroid Build Coastguard Worker
292*61c4878aSAndroid Build Coastguard Worker     Allocator allocator_;
293*61c4878aSAndroid Build Coastguard Worker   };
294*61c4878aSAndroid Build Coastguard Worker
295*61c4878aSAndroid Build Coastguard WorkerFuture Considerations
296*61c4878aSAndroid Build Coastguard Worker=====================
297*61c4878aSAndroid Build Coastguard Worker
298*61c4878aSAndroid Build Coastguard WorkerAllocator traits
299*61c4878aSAndroid Build Coastguard Worker----------------
300*61c4878aSAndroid Build Coastguard WorkerIt can be useful for users to know additional details about a specific
301*61c4878aSAndroid Build Coastguard Workerimplementation of an allocator to determine whether it is suitable for their
302*61c4878aSAndroid Build Coastguard Workeruse case. For example, some allocators may have internal synchronization,
303*61c4878aSAndroid Build Coastguard Workerremoving the need for external locking. Certain allocators may be suitable for
304*61c4878aSAndroid Build Coastguard Workeruses in specialized contexts such as interrupts.
305*61c4878aSAndroid Build Coastguard Worker
306*61c4878aSAndroid Build Coastguard WorkerTo enable users to enforce these types of requirements, it would be useful to
307*61c4878aSAndroid Build Coastguard Workerprovide a way for allocator implementations to define certain traits.
308*61c4878aSAndroid Build Coastguard WorkerOriginally, this proposal accommodated for this by defining derived allocator
309*61c4878aSAndroid Build Coastguard Workerinterfaces which semantically enforced additional implementation contracts.
310*61c4878aSAndroid Build Coastguard WorkerHowever, this approach could have led to an explosion of different allocator
311*61c4878aSAndroid Build Coastguard Workertypes throughout the codebase for each permutation of traits. As such, it was
312*61c4878aSAndroid Build Coastguard Workerremoved from the initial allocator plan for future reinvestigation.
313*61c4878aSAndroid Build Coastguard Worker
314*61c4878aSAndroid Build Coastguard WorkerDynamic collections
315*61c4878aSAndroid Build Coastguard Worker-------------------
316*61c4878aSAndroid Build Coastguard WorkerThe ``pw_containers`` module defines several collections such as ``pw::Vector``.
317*61c4878aSAndroid Build Coastguard WorkerThese collections are modeled after STL equivalents, though being
318*61c4878aSAndroid Build Coastguard Workerembedded-friendly, they reserve a fixed maximum size for their elements.
319*61c4878aSAndroid Build Coastguard Worker
320*61c4878aSAndroid Build Coastguard WorkerWith the addition of dynamic allocation to Pigweed, these containers will be
321*61c4878aSAndroid Build Coastguard Workerexpanded to support the use of allocators. Unless absolutely necessary, upstream
322*61c4878aSAndroid Build Coastguard Workercontainers should be designed to work on the base ``Allocator`` interface ---
323*61c4878aSAndroid Build Coastguard Workernot any of its derived classes --- to offer maximum flexibility to projects
324*61c4878aSAndroid Build Coastguard Workerusing them.
325*61c4878aSAndroid Build Coastguard Worker
326*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
327*61c4878aSAndroid Build Coastguard Worker
328*61c4878aSAndroid Build Coastguard Worker   template <typename T>
329*61c4878aSAndroid Build Coastguard Worker   class DynamicVector {
330*61c4878aSAndroid Build Coastguard Worker     DynamicVector(Allocator& allocator);
331*61c4878aSAndroid Build Coastguard Worker   };
332*61c4878aSAndroid Build Coastguard Worker
333*61c4878aSAndroid Build Coastguard WorkerPer-allocation tagging
334*61c4878aSAndroid Build Coastguard Worker----------------------
335*61c4878aSAndroid Build Coastguard WorkerAnother interface which was originally proposed but shelved for the time being
336*61c4878aSAndroid Build Coastguard Workerallowed for the association of an integer tag with each specific call to
337*61c4878aSAndroid Build Coastguard Worker``Allocate``. This can be incredibly useful for debugging, but requires
338*61c4878aSAndroid Build Coastguard Workerallocator implementations to store additional information with each allocation.
339*61c4878aSAndroid Build Coastguard WorkerThis added complexity to allocators, so it was temporarily removed to focus on
340*61c4878aSAndroid Build Coastguard Workerrefining the core allocator interface.
341*61c4878aSAndroid Build Coastguard Worker
342*61c4878aSAndroid Build Coastguard WorkerThe proposed 32-bit integer tags happen to be the same as the tokens generated
343*61c4878aSAndroid Build Coastguard Workerfrom strings by the ``pw_tokenizer`` module. Combining the two could result in
344*61c4878aSAndroid Build Coastguard Workerthe ability to precisely track the source of allocations in a project.
345*61c4878aSAndroid Build Coastguard Worker
346*61c4878aSAndroid Build Coastguard WorkerFor example, ``pw_allocator`` could provide a macro which tokenizes a user
347*61c4878aSAndroid Build Coastguard Workerstring to an allocator tag, automatically inserting additional metadata such as
348*61c4878aSAndroid Build Coastguard Workerthe file and line number of the allocation.
349*61c4878aSAndroid Build Coastguard Worker
350*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
351*61c4878aSAndroid Build Coastguard Worker
352*61c4878aSAndroid Build Coastguard Worker   void GenerateAndProcessData(TaggedAllocator& allocator) {
353*61c4878aSAndroid Build Coastguard Worker     void* data = allocator->AllocatedTagged(
354*61c4878aSAndroid Build Coastguard Worker         Layout::Sized(kDataSize), PW_ALLOCATOR_TAG("my data buffer"));
355*61c4878aSAndroid Build Coastguard Worker     if (data == nullptr) {
356*61c4878aSAndroid Build Coastguard Worker       return;
357*61c4878aSAndroid Build Coastguard Worker     }
358*61c4878aSAndroid Build Coastguard Worker
359*61c4878aSAndroid Build Coastguard Worker     GenerateData(data);
360*61c4878aSAndroid Build Coastguard Worker     ProcessData(data);
361*61c4878aSAndroid Build Coastguard Worker
362*61c4878aSAndroid Build Coastguard Worker     allocator->Deallocate(data);
363*61c4878aSAndroid Build Coastguard Worker   }
364*61c4878aSAndroid Build Coastguard Worker
365*61c4878aSAndroid Build Coastguard WorkerAllocator implementations
366*61c4878aSAndroid Build Coastguard Worker-------------------------
367*61c4878aSAndroid Build Coastguard WorkerOver time, Pigweed expects to implement a handful of different allocators
368*61c4878aSAndroid Build Coastguard Workercovering the interfaces proposed here. No specific new implementations are
369*61c4878aSAndroid Build Coastguard Workersuggested as part of this proposal. Pigweed's existing ``FreeListHeap``
370*61c4878aSAndroid Build Coastguard Workerallocator will be refactored to implement the ``Allocator`` interface.
371*61c4878aSAndroid Build Coastguard Worker
372*61c4878aSAndroid Build Coastguard Worker---------------------
373*61c4878aSAndroid Build Coastguard WorkerProblem Investigation
374*61c4878aSAndroid Build Coastguard Worker---------------------
375*61c4878aSAndroid Build Coastguard Worker
376*61c4878aSAndroid Build Coastguard WorkerUse cases and requirements
377*61c4878aSAndroid Build Coastguard Worker==========================
378*61c4878aSAndroid Build Coastguard Worker
379*61c4878aSAndroid Build Coastguard Worker* **General-purpose memory allocation.** The target of ``pw_allocator`` is
380*61c4878aSAndroid Build Coastguard Worker  general-purpose dynamic memory usage by typical applications, rather than
381*61c4878aSAndroid Build Coastguard Worker  specialized types of memory allocation that may be required by lower-level
382*61c4878aSAndroid Build Coastguard Worker  code such as drivers.
383*61c4878aSAndroid Build Coastguard Worker
384*61c4878aSAndroid Build Coastguard Worker* **Generic interfaces with minimal policy.** Every project has different
385*61c4878aSAndroid Build Coastguard Worker  resources and requirements, and particularly in constrained systems, memory
386*61c4878aSAndroid Build Coastguard Worker  management is often optimized for their specific use cases. Pigweed's core
387*61c4878aSAndroid Build Coastguard Worker  allocation interfaces should offer as broad of an implementation contract as
388*61c4878aSAndroid Build Coastguard Worker  possible and not bake in assumptions about how they will be run.
389*61c4878aSAndroid Build Coastguard Worker
390*61c4878aSAndroid Build Coastguard Worker* **RTOS or bare metal usage.** While many systems make use of an RTOS which
391*61c4878aSAndroid Build Coastguard Worker  provides utilities such as threads and synchronization primitives, Pigweed
392*61c4878aSAndroid Build Coastguard Worker  also targets systems which run without one. As such, the core allocators
393*61c4878aSAndroid Build Coastguard Worker  should not be tied to any RTOS requirements, and accommodations should be made
394*61c4878aSAndroid Build Coastguard Worker  for different system contexts.
395*61c4878aSAndroid Build Coastguard Worker
396*61c4878aSAndroid Build Coastguard WorkerOut of scope
397*61c4878aSAndroid Build Coastguard Worker------------
398*61c4878aSAndroid Build Coastguard Worker
399*61c4878aSAndroid Build Coastguard Worker* **Asynchronous allocation.** As this proposal is centered around simple
400*61c4878aSAndroid Build Coastguard Worker  general-purpose allocation, it does not consider asynchronous allocations.
401*61c4878aSAndroid Build Coastguard Worker  While these are important use cases, they are typically more specialized and
402*61c4878aSAndroid Build Coastguard Worker  therefore outside the scope of this proposal. Pigweed is considering some
403*61c4878aSAndroid Build Coastguard Worker  forms of asynchronous memory allocation, such as the proposal in the
404*61c4878aSAndroid Build Coastguard Worker  :ref:`Communication Buffers SEED <seed-0109>`.
405*61c4878aSAndroid Build Coastguard Worker
406*61c4878aSAndroid Build Coastguard Worker* **Direct STL integration.** The C++ STL makes heavy use of dynamic memory and
407*61c4878aSAndroid Build Coastguard Worker  offers several ways for projects to plug in their own allocators. This SEED
408*61c4878aSAndroid Build Coastguard Worker  does not propose any direct Pigweed to STL-style allocator adapters, nor does
409*61c4878aSAndroid Build Coastguard Worker  it offer utilities for replacing the global ``new`` and ``delete`` operators.
410*61c4878aSAndroid Build Coastguard Worker  These are additions which may come in future changes.
411*61c4878aSAndroid Build Coastguard Worker
412*61c4878aSAndroid Build Coastguard Worker  It is still possible to use Pigweed allocators with the STL in an indirect way
413*61c4878aSAndroid Build Coastguard Worker  by going through the PMR interface, which is discussed later.
414*61c4878aSAndroid Build Coastguard Worker
415*61c4878aSAndroid Build Coastguard Worker* **Global Pigweed allocators.** Pigweed modules will not assume a global
416*61c4878aSAndroid Build Coastguard Worker  allocator instantiation. Any usage of allocators by modules should rely on
417*61c4878aSAndroid Build Coastguard Worker  dependency injection, leaving consumers with control over how they choose to
418*61c4878aSAndroid Build Coastguard Worker  manage their memory usage.
419*61c4878aSAndroid Build Coastguard Worker
420*61c4878aSAndroid Build Coastguard WorkerAlternative solutions
421*61c4878aSAndroid Build Coastguard Worker=====================
422*61c4878aSAndroid Build Coastguard Worker
423*61c4878aSAndroid Build Coastguard Worker.. _seed-0110-why-not-pmr:
424*61c4878aSAndroid Build Coastguard Worker
425*61c4878aSAndroid Build Coastguard WorkerC++ polymorphic allocators
426*61c4878aSAndroid Build Coastguard Worker--------------------------
427*61c4878aSAndroid Build Coastguard WorkerC++17 introduced the ``<memory_resource>`` header with support for polymorphic
428*61c4878aSAndroid Build Coastguard Workermemory resources (PMR), i.e. allocators. This library defines many allocator
429*61c4878aSAndroid Build Coastguard Workerinterfaces similar to those in this proposal. Naturally, this raises the
430*61c4878aSAndroid Build Coastguard Workerquestion of whether Pigweed can use them directly, benefitting from the larger
431*61c4878aSAndroid Build Coastguard WorkerC++ ecosystem.
432*61c4878aSAndroid Build Coastguard Worker
433*61c4878aSAndroid Build Coastguard WorkerThe primary issue with PMR with regards to Pigweed is that the interfaces
434*61c4878aSAndroid Build Coastguard Workerrequire the use of C++ language features prohibited by Pigweed. The allocator
435*61c4878aSAndroid Build Coastguard Workeris expected to throw an exception in the case of failure, and equality
436*61c4878aSAndroid Build Coastguard Workercomparisons require RTTI. The team is not prepared to change or make exceptions
437*61c4878aSAndroid Build Coastguard Workerto this policy, prohibiting the direct usage of PMR.
438*61c4878aSAndroid Build Coastguard Worker
439*61c4878aSAndroid Build Coastguard WorkerDespite this, Pigweed's allocator interfaces have taken inspiration from the
440*61c4878aSAndroid Build Coastguard Workerdesign of PMR, incorporating many of its ideas. The core proposed ``Allocator``
441*61c4878aSAndroid Build Coastguard Workerinterface is similar to ``std::pmr::memory_resource``, making it possible to
442*61c4878aSAndroid Build Coastguard Workerwrap Pigweed allocators with a PMR adapter for use with the C++ STL, albeit at
443*61c4878aSAndroid Build Coastguard Workerthe cost of an extra layer of virtual indirection.
444*61c4878aSAndroid Build Coastguard Worker
445*61c4878aSAndroid Build Coastguard Worker--------------
446*61c4878aSAndroid Build Coastguard WorkerOpen Questions
447*61c4878aSAndroid Build Coastguard Worker--------------
448*61c4878aSAndroid Build Coastguard WorkerThis SEED proposal is only a starting point for the improvement of the
449*61c4878aSAndroid Build Coastguard Worker``pw_allocator`` module, and Pigweed's memory management story in general.
450*61c4878aSAndroid Build Coastguard Worker
451*61c4878aSAndroid Build Coastguard WorkerThere are several open questions around Pigweed allocators which the team
452*61c4878aSAndroid Build Coastguard Workerexpects to answer in future SEEDs:
453*61c4878aSAndroid Build Coastguard Worker
454*61c4878aSAndroid Build Coastguard Worker* Should generic interfaces for asynchronous allocations be provided, and how
455*61c4878aSAndroid Build Coastguard Worker  would they look?
456*61c4878aSAndroid Build Coastguard Worker
457*61c4878aSAndroid Build Coastguard Worker* Reference counted allocations and "smart pointers": where do they fit in?
458*61c4878aSAndroid Build Coastguard Worker
459*61c4878aSAndroid Build Coastguard Worker* The concept of allocator equality is essential to enable certain use cases,
460*61c4878aSAndroid Build Coastguard Worker  such as efficiently using dynamic containers with their own allocators.
461*61c4878aSAndroid Build Coastguard Worker  This proposal excludes APIs paralleling PMR's ``is_equal`` due to RTTI
462*61c4878aSAndroid Build Coastguard Worker  requirements. Could Pigweed allocators implement a watered-down version of an
463*61c4878aSAndroid Build Coastguard Worker  RTTI / type ID system to support this?
464*61c4878aSAndroid Build Coastguard Worker
465*61c4878aSAndroid Build Coastguard Worker* How do allocators integrate with the monolithic ``pw_system`` as a starting
466*61c4878aSAndroid Build Coastguard Worker  point for projects?
467