blob: 24ae1727dfb16e3703a9430bb0e80c675b2c1182 [file] [log] [blame]
.. _module-pw_allocator:
------------
pw_allocator
------------
This module provides various building blocks
for a dynamic allocator. This is composed of the following parts:
- ``block``: An implementation of a doubly-linked list of memory blocks,
supporting splitting and merging of blocks.
- ``freelist``: A freelist, suitable for fast lookups of available memory chunks
(i.e. ``block`` s).
- ``allocator``: An interface for memory allocators. Several concrete
implementations are also provided.
Block
=====
.. doxygenclass:: pw::allocator::Block
:members:
FreeList
========
.. doxygenclass:: pw::allocator::FreeList
:members:
Allocator
=========
.. doxygenclass:: pw::allocator::Allocator
:members:
Example
-------
As an example, the following implements a simple allocator that tracks memory
using ``Block``.
.. literalinclude:: public/pw_allocator/simple_allocator.h
:language: cpp
:linenos:
:start-after: [pw_allocator_examples_simple_allocator]
:end-before: [pw_allocator_examples_simple_allocator]
Other Implemetations
--------------------
Provided implementations of the ``Allocator`` interface include:
- ``AllocatorMetricProxy``: Wraps another allocator and records its usage.
- ``FallbackAllocator``: Dispatches first to a primary allocator, and, if that
fails, to a secondary alloator.
- ``LibCAllocator``: Uses ``malloc``, ``realloc``, and ``free``. This should
only be used if the ``libc`` in use provides those functions.
- ``NullAllocator``: Always fails. This may be useful if allocations should be
disallowed under specific circumstances.
- ``SplitFreeListAllocator``: Tracks memory using ``Block``, and splits large
and small allocations between the front and back, respectively, of it memory
region in order to reduce fragmentation.
UniquePtr
=========
.. doxygenclass:: pw::allocator::UniquePtr
:members:
.. _module-pw_allocator-test-support:
Test Support
============
This module also provides several utilities designed to make it easier to write
tests for custom ``Allocator`` implementations:
AllocatorForTest
----------------
.. doxygenclass:: pw::allocator::test::AllocatorForTest
:members:
WithBuffer
----------
.. doxygenclass:: pw::allocator::test::WithBuffer
:members:
AllocatorTestHarness
--------------------
.. doxygenclass:: pw::allocator::test::AllocatorTestHarness
:members:
Heap Poisoning
==============
By default, this module disables heap poisoning since it requires extra space.
User can enable heap poisoning by enabling the ``pw_allocator_POISON_HEAP``
build arg.
.. tab-set::
.. tab-item:: GN
:sync: gn
.. code-block:: sh
$ gn args out
# Modify and save the args file to use heap poison.
pw_allocator_POISON_HEAP = true
.. tab-item:: CMake
:sync: cmake
.. code-block:: sh
# Modify the top-level CMakeLists.txt and add:
set(pw_allocator_POISON_HEAP, ON)
When heap poisoning is enabled, ``pw_allocator`` will add ``sizeof(void*)``
bytes before and after the usable space of each ``Block``, and paint the space
with a hard-coded randomized pattern. During each check, ``pw_allocator``
will check if the painted space still remains the pattern, and return ``false``
if the pattern is damaged.
Heap Visualizer
===============
Functionality
-------------
``pw_allocator`` supplies a pw command ``pw heap-viewer`` to help visualize
the state of the heap at the end of a dump file. The heap is represented by
ASCII characters, where each character represents 4 bytes in the heap.
.. image:: doc_resources/pw_allocator_heap_visualizer_demo.png
Usage
-----
The heap visualizer can be launched from a shell using the Pigweed environment.
.. code-block:: sh
$ pw heap-viewer --dump-file <directory of dump file> --heap-low-address
<hex address of heap lower address> --heap-high-address <hex address of heap
lower address> [options]
The required arguments are:
- ``--dump-file`` is the path of a file that contains ``malloc/free``
information. Each line in the dump file represents a ``malloc/free`` call.
``malloc`` is represented as ``m <size> <memory address>`` and ``free`` is
represented as ``f <memory address>``. For example, a dump file should look
like:
.. code-block:: sh
m 20 0x20004450 # malloc 20 bytes, the pointer is 0x20004450
m 8 0x2000447c # malloc 8 bytes, the pointer is 0x2000447c
f 0x2000447c # free the pointer at 0x2000447c
...
Any line not formatted as the above will be ignored.
- ``--heap-low-address`` is the start of the heap. For example:
.. code-block:: sh
--heap-low-address 0x20004440
- ``--heap-high-address`` is the end of the heap. For example:
.. code-block:: sh
--heap-high-address 0x20006040
Options include the following:
- ``--poison-enable``: If heap poisoning is enabled during the
allocation or not. The value is ``False`` if the option is not specified and
``True`` otherwise.
- ``--pointer-size <integer of pointer size>``: The size of a pointer on the
machine where ``malloc/free`` is called. The default value is ``4``.
.. _module-pw_allocator-size:
Size report
===========
``pw_allocator`` provides some of its own implementations of the ``Allocator``
interface, whos costs are shown below.
.. include:: allocator_size_report
.. _module-pw_allocator-metric-collection:
Metric collection
=================
Consumers can use an ``AllocatorMetricProxy`` to wrap an allocator and collect
usage statistics. These statistics are implemented using
:ref:`module-pw_metric`.
.. code-block:: cpp
MyAllocator allocator;
AllocatorMetricProxy proxy(PW_TOKENIZE_STRING_EXPR("my allocator"));
proxy.Init(allocator);
// ...Perform various allocations and deallocations...
proxy.Dump();
Metric collection is controlled using the ``pw_allocator_COLLECT_METRICS`` build
argument. If this is unset or ``false``, metric collection is skipped.
To force metric collection regardless of the build argument, tests may include
the ``"pw_allocator/allocator_metric_proxy_for_tests.h"`` header file and depend
on the ``//pw_allocator:allocator_metric_proxy_for_tests`` target.