xref: /aosp_15_r20/external/pigweed/pw_allocator/design.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_allocator-design:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker================
4*61c4878aSAndroid Build Coastguard WorkerDesign & roadmap
5*61c4878aSAndroid Build Coastguard Worker================
6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage::
7*61c4878aSAndroid Build Coastguard Worker   :name: pw_allocator
8*61c4878aSAndroid Build Coastguard Worker
9*61c4878aSAndroid Build Coastguard Worker-----------------------
10*61c4878aSAndroid Build Coastguard WorkerDesign of pw::Allocator
11*61c4878aSAndroid Build Coastguard Worker-----------------------
12*61c4878aSAndroid Build Coastguard WorkerTraditionally, most embedded firmware have laid out their systems’ memory usage
13*61c4878aSAndroid Build Coastguard Workerstatically, with every component’s buffers and resources set at compile time. As
14*61c4878aSAndroid Build Coastguard Workersystems grow larger and more complex, dynamic allocation provides increasing
15*61c4878aSAndroid Build Coastguard Workeropportunities to simplify code and improve memory usage by enabling sharing and
16*61c4878aSAndroid Build Coastguard Workereliminating large reservations.
17*61c4878aSAndroid Build Coastguard Worker
18*61c4878aSAndroid Build Coastguard WorkerAs a result, ``pw_allocator`` seeks to make dynamic allocation possible without
19*61c4878aSAndroid Build Coastguard Workersacrificing too much of the control over memory usage that embedded developers
20*61c4878aSAndroid Build Coastguard Workerare accustomed to and need. The fundamental design goals of ``pw_allocator`` are
21*61c4878aSAndroid Build Coastguard Workerfor allocators to be:
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker- Familiar: The interface and its usage should resemble that of C++17's
24*61c4878aSAndroid Build Coastguard Worker  `std::pmr::polymorphic_allocator`_ type.
25*61c4878aSAndroid Build Coastguard Worker- Flexible: A diverse set of allocation strategies should be implementable
26*61c4878aSAndroid Build Coastguard Worker  using allocators.
27*61c4878aSAndroid Build Coastguard Worker- Composable: Allocators should be able to combine and use other allocators.
28*61c4878aSAndroid Build Coastguard Worker- Extensible: Downstream projects should be able to provide their own allocator
29*61c4878aSAndroid Build Coastguard Worker  implementations, and easily integrate them with Pigweed's.
30*61c4878aSAndroid Build Coastguard Worker- Cost-effective: Projects should be able to include only the allocator
31*61c4878aSAndroid Build Coastguard Worker  behaviors they desire.
32*61c4878aSAndroid Build Coastguard Worker- Observable: Allocators should provide tools and data to reveal how memory is
33*61c4878aSAndroid Build Coastguard Worker  being used.
34*61c4878aSAndroid Build Coastguard Worker- Correcting: Allocators should include features to help uncover
35*61c4878aSAndroid Build Coastguard Worker  `memory defects`_ including heap corruption, leaks, use-after-frees, etc.
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker.. _module-pw_allocator-design-differences-with-polymorphic-allocators:
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard WorkerDifferences with C++ polymorphic allocators
40*61c4878aSAndroid Build Coastguard Worker===========================================
41*61c4878aSAndroid Build Coastguard WorkerC++17 introduced the ``<memory_resource>`` header with support for polymorphic
42*61c4878aSAndroid Build Coastguard Workermemory resources (PMR), i.e. allocators. This library defines many allocator
43*61c4878aSAndroid Build Coastguard Workerinterfaces similar to those in ``pw_allocator``.
44*61c4878aSAndroid Build Coastguard Worker
45*61c4878aSAndroid Build Coastguard WorkerPigweed has decided to keep ``pw_allocator`` distinct from PMR primarily because
46*61c4878aSAndroid Build Coastguard Workerthe latter's interface requires the use of C++ language features prohibited by
47*61c4878aSAndroid Build Coastguard WorkerPigweed. In PMR, allocators are expected to throw an exception in the case of
48*61c4878aSAndroid Build Coastguard Workerfailure, and equality comparisons require runtime type identification (RTTI).
49*61c4878aSAndroid Build Coastguard Worker
50*61c4878aSAndroid Build Coastguard WorkerEven so, ``pw_allocator`` has taken inspiration from the design of PMR,
51*61c4878aSAndroid Build Coastguard Workerincorporating many of its ideas. :ref:`module-pw_allocator-api-allocator` in
52*61c4878aSAndroid Build Coastguard Workerparticular is similar to `std::pmr::memory_resource`_.
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard WorkerThis similarity is most evident in the PMR adapter class,
55*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_allocator-api-pmr_allocator`. This adapter allows any
56*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_allocator-api-allocator` to be used as a
57*61c4878aSAndroid Build Coastguard Worker`std::pmr::polymorphic_allocator`_ with any standard library that
58*61c4878aSAndroid Build Coastguard Worker`can use an allocator`_. Refer to the guides on how to
59*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_allocator-use-standard-library-containers`.
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker.. _module-pw_allocator-design-forwarding:
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard WorkerForwarding allocator concept
64*61c4878aSAndroid Build Coastguard Worker============================
65*61c4878aSAndroid Build Coastguard WorkerIn addition to concrete allocator implementations, the design of
66*61c4878aSAndroid Build Coastguard Worker``pw_allocator`` also encourages the use of "forwarding" allocators. These are
67*61c4878aSAndroid Build Coastguard Workerimplementations of the :ref:`module-pw_allocator-api-allocator` interface that
68*61c4878aSAndroid Build Coastguard Workerdon't allocate memory directly and instead rely on other allocators while
69*61c4878aSAndroid Build Coastguard Workerproviding some additional behavior.
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard WorkerFor example, the :ref:`module-pw_allocator-api-allocator` records various
72*61c4878aSAndroid Build Coastguard Workermetrics such as the peak number of bytes allocated and the number of failed
73*61c4878aSAndroid Build Coastguard Workerallocation requests. It wraps another allocator which is used to actually
74*61c4878aSAndroid Build Coastguard Workerperform dynamic allocation. It implements the allocator API, and so it can be
75*61c4878aSAndroid Build Coastguard Workerpassed into any routines that use dependency injection by taking a generic
76*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_allocator-api-allocator` parameter.
77*61c4878aSAndroid Build Coastguard Worker
78*61c4878aSAndroid Build Coastguard WorkerThese "forwarding" allocators are not completely free. At a miniumum, they
79*61c4878aSAndroid Build Coastguard Workerrepresent an extra virtual indirection, and an extra function call, albeit one
80*61c4878aSAndroid Build Coastguard Workerthat can often be inlined. Additional behavior-specific code or state adds to
81*61c4878aSAndroid Build Coastguard Workertheir cost in terms of code size and performance. Even so, these "forwarding"
82*61c4878aSAndroid Build Coastguard Workerallocators can provide savings relative to a "`golden hammer`_"-style allocator
83*61c4878aSAndroid Build Coastguard Workerthat combined all of their features and more. By decomposing allocators into
84*61c4878aSAndroid Build Coastguard Workerorthogonal behaviors, implementers can choose to pay for only those that they
85*61c4878aSAndroid Build Coastguard Workerwant.
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker-----------------------------
88*61c4878aSAndroid Build Coastguard WorkerDesign of allocator utilities
89*61c4878aSAndroid Build Coastguard Worker-----------------------------
90*61c4878aSAndroid Build Coastguard WorkerIn addtion to providing allocator implementations themselves, ``pw_allocator``
91*61c4878aSAndroid Build Coastguard Workerincludes some foundational classes that can be used to implement allocators.
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker.. _module-pw_allocator-design-block:
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard Workerpw::allocator::Block
96*61c4878aSAndroid Build Coastguard Worker====================
97*61c4878aSAndroid Build Coastguard WorkerSeveral allocators make use of allocation metadata stored inline with the
98*61c4878aSAndroid Build Coastguard Workerallocations themselves. Often referred to as a "header", this metadata
99*61c4878aSAndroid Build Coastguard Workerimmediately precedes the pointer to usable space returned by the allocator. This
100*61c4878aSAndroid Build Coastguard Workerheader allows allocations to be variably sized, and converts allocation into a
101*61c4878aSAndroid Build Coastguard Worker`bin packing problem`_. An allocator that uses headers has a miniumum alignment
102*61c4878aSAndroid Build Coastguard Workermatching that of the header type itself.
103*61c4878aSAndroid Build Coastguard Worker
104*61c4878aSAndroid Build Coastguard WorkerFor ``pw_allocator``, the most common way to store this header is as a
105*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_allocator-api-block`. This class is used to construct a
106*61c4878aSAndroid Build Coastguard Workerdoubly-linked list of subsequences of the allocator's memory region. It was
107*61c4878aSAndroid Build Coastguard Workerdesigned with the following features:
108*61c4878aSAndroid Build Coastguard Worker
109*61c4878aSAndroid Build Coastguard Worker- **Templated offset types**: Rather than use pointers to the next and previous
110*61c4878aSAndroid Build Coastguard Worker  blocks, ``Block`` uses offsets of a templated unsigned integral type. This
111*61c4878aSAndroid Build Coastguard Worker  saves a few bits that can be used for other purposes, since the blocks are
112*61c4878aSAndroid Build Coastguard Worker  always aligned to the block header. It also gives callers the ability to
113*61c4878aSAndroid Build Coastguard Worker  reduce the size of the headers if the allocator's memory region is
114*61c4878aSAndroid Build Coastguard Worker  sufficently small, e.g. a type of ``uint16_t`` could be used if the region
115*61c4878aSAndroid Build Coastguard Worker  could hold no more than 65536 block headers.
116*61c4878aSAndroid Build Coastguard Worker- **Splitting and merging**: This class centralizes the logic for splitting
117*61c4878aSAndroid Build Coastguard Worker  memory regions into smaller pieces. Usable sub-blocks can either be split from
118*61c4878aSAndroid Build Coastguard Worker  the beginning or end of a block. Additionally, blocks from  either end can be
119*61c4878aSAndroid Build Coastguard Worker  split at specified alignment boundaries. This class also provides the logic
120*61c4878aSAndroid Build Coastguard Worker  for merging blocks back together. Together, these methods provide the
121*61c4878aSAndroid Build Coastguard Worker  invariant that a free block is only ever adjacent to blocks in use.
122*61c4878aSAndroid Build Coastguard Worker- **Validation and poisoning**: On every deallocation, blocks validate their
123*61c4878aSAndroid Build Coastguard Worker  metadata against their neighbors. A block can fail to be validated if it or
124*61c4878aSAndroid Build Coastguard Worker  its neighbors have had their headers overwritten. In this case, it's unsafe to
125*61c4878aSAndroid Build Coastguard Worker  continue to use this memory and the block code will assert in order make you
126*61c4878aSAndroid Build Coastguard Worker  aware of the problem. Additionally, blocks can "paint" their memory with a
127*61c4878aSAndroid Build Coastguard Worker  known poison pattern that's checked whenever the memory is next allocated. If
128*61c4878aSAndroid Build Coastguard Worker  the check fails, then some code has written to unallocated memory. Again, the
129*61c4878aSAndroid Build Coastguard Worker  block code will assert to alert you of a "use-after-free" condition.
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard Worker.. tip::
132*61c4878aSAndroid Build Coastguard Worker   In the case of memory corruption, the validation routines themsleves may
133*61c4878aSAndroid Build Coastguard Worker   crash while attempting to inspect block headers. These crashes are not
134*61c4878aSAndroid Build Coastguard Worker   exploitable from a security perspective, but lack the diagnostic information
135*61c4878aSAndroid Build Coastguard Worker   from the usual ``PW_CHECK`` macro. Examining a stack trace may be helpful in
136*61c4878aSAndroid Build Coastguard Worker   determining why validation failed.
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker.. _module-pw_allocator-design-metrics:
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard WorkerAllocator metrics
141*61c4878aSAndroid Build Coastguard Worker=================
142*61c4878aSAndroid Build Coastguard WorkerA common desire for a project using dynamic memory is to clearly understand how
143*61c4878aSAndroid Build Coastguard Workermuch memory is being allocated. However, each tracked metric adds code size,
144*61c4878aSAndroid Build Coastguard Workermemory overhead, and a per-call performance cost. As a result, ``pw_allocator``
145*61c4878aSAndroid Build Coastguard Workeris design to allow allocator implementers to select just the metrics they're
146*61c4878aSAndroid Build Coastguard Workerinterested in.
147*61c4878aSAndroid Build Coastguard Worker
148*61c4878aSAndroid Build Coastguard WorkerIn particular, the :ref:`module-pw_allocator-api-metrics_adapter` uses
149*61c4878aSAndroid Build Coastguard Workerper-metric type traits generated by ``PW_ALLOCATOR_METRICS_DECLARE`` to
150*61c4878aSAndroid Build Coastguard Workerconditionally include the code to update the metrics that are included in its
151*61c4878aSAndroid Build Coastguard Worker``MetricsType`` template parameter type. A suitable ``MetricType`` struct can be
152*61c4878aSAndroid Build Coastguard Workercreated using the ``PW_ALLOCATOR_METRICS_ENABLE`` macro, which will only create
153*61c4878aSAndroid Build Coastguard Workerfields for the enabled metrics.
154*61c4878aSAndroid Build Coastguard Worker
155*61c4878aSAndroid Build Coastguard WorkerUsing these macros prevents unwanted metrics from increasing either the code
156*61c4878aSAndroid Build Coastguard Workersize or object size of the metrics adapter, and by extension,
157*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_allocator-api-tracking_allocator`.
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker-------
160*61c4878aSAndroid Build Coastguard WorkerRoadmap
161*61c4878aSAndroid Build Coastguard Worker-------
162*61c4878aSAndroid Build Coastguard WorkerWhile the :ref:`module-pw_allocator-api-allocator` interface is almost stable,
163*61c4878aSAndroid Build Coastguard Workerthere are some outstanding features the Pigweed team would like to add to
164*61c4878aSAndroid Build Coastguard Worker``pw_allocator``:
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker- **Asynchronous allocators**: Determine whether these should be provided, and
167*61c4878aSAndroid Build Coastguard Worker  if so, add them.
168*61c4878aSAndroid Build Coastguard Worker- **Additional smart pointers**: Determine if pointers like ``std::shared_ptr``,
169*61c4878aSAndroid Build Coastguard Worker  etc., are needed, and if so, add them.
170*61c4878aSAndroid Build Coastguard Worker- **Dynamic containers**: Provide the concept of allocator equality without
171*61c4878aSAndroid Build Coastguard Worker  using RTTI or ``typeid``. This would allow dynamic containers with their own
172*61c4878aSAndroid Build Coastguard Worker  allocators.
173*61c4878aSAndroid Build Coastguard Worker- **Default allocators**: Integrate ``pw_allocator`` into the monolithic
174*61c4878aSAndroid Build Coastguard Worker  ``pw_system`` as a starting point for projects.
175*61c4878aSAndroid Build Coastguard Worker
176*61c4878aSAndroid Build Coastguard WorkerFound a bug? Got a feature request? Please create a new issue in our `tracker`_!
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard WorkerWant to discuss allocators in real-time with the Pigweed team? Head over to our
179*61c4878aSAndroid Build Coastguard Worker`Discord`_!
180*61c4878aSAndroid Build Coastguard Worker
181*61c4878aSAndroid Build Coastguard Worker.. _memory defects: https://en.wikipedia.org/wiki/Memory_corruption
182*61c4878aSAndroid Build Coastguard Worker.. _golden hammer: https://en.wikipedia.org/wiki/Law_of_the_instrument#Computer_programming
183*61c4878aSAndroid Build Coastguard Worker.. _bin packing problem: https://en.wikipedia.org/wiki/Bin_packing_problem
184*61c4878aSAndroid Build Coastguard Worker.. _std::pmr::memory_resource: https://en.cppreference.com/w/cpp/memory/memory_resource
185*61c4878aSAndroid Build Coastguard Worker.. _std::pmr::polymorphic_allocator: https://en.cppreference.com/w/cpp/memory/polymorphic_allocator
186*61c4878aSAndroid Build Coastguard Worker.. _can use an allocator: https://en.cppreference.com/w/cpp/memory/uses_allocator
187*61c4878aSAndroid Build Coastguard Worker.. _tracker: https://pwbug.dev
188*61c4878aSAndroid Build Coastguard Worker.. _Discord: https://discord.gg/M9NSeTA
189