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