Commit Graph

27 Commits

Author SHA1 Message Date
Damian Krolik 5f5410a0cc sys: heap: support maximum allocated bytes statistic
Besides the current allocated/free bytes, keep track of
the maximum allocated bytes to help determine the heap
size requirements. Also, provide a function to reset
the statistic.

Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no>
2022-04-13 13:27:28 -07:00
Chen Peng1 a71cd8790f heap: add functions to get heap runtime statistics
add functions to get the sys_heap runtime statistics,
include total free bytes, total allocated bytes.

Signed-off-by: Chen Peng1 <peng1.chen@intel.com>
2021-11-11 16:21:43 -05:00
Nicolas Pitre 46db2b491d lib/os/heap: option for optimizing for one heap size on 32-bit systems
The "small" heap is is way sufficient for most 32-bit systems.

Let's provide the option to have only one type of heap allowing for
smaller and faster heap code due to not having a bunch of runtime
conditionals based on the heap size.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-10-17 07:34:51 -04:00
Maksim Masalski f18b728a4c heap: create unique variable name
In code is a variable "chunksz_t chunksz" that has the same name as
function "chunksz_t chunksz()" in the one heap.h file.
Create unique variable name to avoid misreading in the future.

Found as a coding guideline violation (MISRA R5.9) by static
coding scanning tool.

Signed-off-by: Maksim Masalski <maksim.masalski@intel.com>
2021-05-25 19:06:06 -04:00
Nicolas Pitre b1eefc0c26 lib/os/heap: straighten up our type usage
The size_t usage, especially in struct z_heap_bucket made the heap
header almost 2x bigger than it needs to be on 64-bit systems.
This prompted me to clean up our type usage to make the code more
efficient and easier to understand. From now on:

- chunkid_t is for absolute chunk position measured in chunk units
- chunksz_t is for chunk sizes measured in chunk units
- size_t is for buffer sizes measured in bytes

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-03-18 19:33:39 -04:00
Nicolas Pitre e919bb2d16 lib/os/heap: abstract conversion from chunk size to usable bytes
This is the reverse of bytes_to_chunksz().

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-03-18 19:33:39 -04:00
Nicolas Pitre a54e101a1e lib/os/heap: rename struct z_heap.len to struct z_heap.end_chunk
The end marker chunk was represented by the len field of struct z_heap.
It is now renamed to end_chunk to make it more obvious what it is.

And while at it...

Given that it is used in size_too_big() to cap the allocation size
already, we no longer need to test the bucket index against the
biggest index possible derived from end_chunk in alloc_chunk(). The
corresponding bucket_idx() call is relatively expensive on some
architectures so avoiding it (turning it into a CHECK() instead) is
a good thing.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-03-18 19:33:39 -04:00
Nicolas Pitre e8910f629d lib/os/heap: document the reason behind the header field ordering
This is not obvious why the order is important when only looking at
the header file.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-03-18 19:33:39 -04:00
Nicolas Pitre f2fd0e8bb6 lib/os/heap: make printed heap info more useful
Turn sys_heap_dump() into sys_heap_print_info() to better reflect
what it actually does, and improve the information being printed.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-03-16 16:06:53 +01:00
Nicolas Pitre 7a91cf0176 Revert "lib/os/heap: introduce option to force big heap mode"
This reverts commit b6b6d39bb6.

With both commit 4690b8d5ec ("libc/minimal: fix malloc() allocated
memory alignment") and commit c822e0abbd ("libc/minimal: fix
realloc() allocated memory alignment") in place, there is no longer
a need for enforcing the big heap mode on every allocations.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-02-19 07:32:22 -05:00
Martin Åberg b6b6d39bb6 lib/os/heap: introduce option to force big heap mode
This option allows forcing big heap mode. Useful on for getting 8-byte
aligned blocks on 32-bit machines.

Signed-off-by: Martin Åberg <martin.aberg@gaisler.com>
2021-01-24 10:11:11 -05:00
Nicolas Pitre f436315e02 lib/os/heap: guard against arithmetic overflows
Let's do it upfront only once for each entry point and dispense
with overflow checks later to keep the code simple.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2021-01-20 14:15:44 -05:00
Aastha Grover 83b9f69755 code-guideline: Fixing code violation 10.4 Rule
Both operands of an operator in the arithmetic conversions
performed shall have the same essential type category.

Changes are related to converting the integer constants to the
unsigned integer constants

Signed-off-by: Aastha Grover <aastha.grover@intel.com>
2020-10-01 17:13:29 -04:00
Nicolas Pitre 6014e5f441 lib/os/heap: remove big_heap restriction for aligned allocations
After commit 8a6b02b5bf ("lib/os/heap: some code simplification in
sys_heap_aligned_alloc()") it is no longer required to have a "big"
heap for aligned allocations to work on 32-bit targets. While the
natural alignment for returned memory has an offset of 4 within a chunk
unit due to the smaller header size, returning to a chunkid from a
memory pointer with an offset of 8 will fall back onto the proper chunk
number once the 4 is substracted and then divided by 8.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-07-14 19:35:52 -04:00
Nicolas Pitre 9b538e4079 lib/os/heap: make "solo free headers" into first-class citizens
Instead of limiting the excess split-off to sufficiently large chunks
in split_alloc(), let's allow normal allocations to create "solo free
headers" just like with aligned allocations. There is no point leaving
them in the allocated chunk if the user didn't ask for it. Doing so
makes them eligible for merging at the next opportunity and potentially
reusable sooner.

Also make the validation code aware of them.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-07-14 19:35:52 -04:00
Nicolas Pitre 64af35049c lib/os/heap: debugging facility to dump the heap structure to the cconsole
It is linked in only when used, so handy to always have it around for
analysis purposes.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-26 11:41:43 -07:00
Andy Ross ed258e9c6f lib/os/heap: Add sys_heap_aligned_alloc()
Add support for a C11-style aligned_alloc() in the heap
implementation.  This is properly optimized, in the sense that unused
prefix/suffix data around the chosen allocation is returned to the
heap and made available for general allocation.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2020-06-22 14:54:04 -04:00
Nicolas Pitre ad59e923e9 sys_heap: reduce the size of struct z_heap_bucket by half
This struct is taking up most of the heap's constant footprint overhead.
We can easily get rid of the list_size member as it is mostly used to
determine if the list is empty, and that can be determined through
other means.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre 74fbca412a sys_heap: perform cheap overflow detection on freed memory
Make the LEFT_SIZE field first and SIZE_AND_USED field last (for an
allocated chunk) so they sit right next to the allocated memory. The
current chunk's SIZE_AND_USED field points to the next (right) chunk,
and from there the LEFT_SIZE field should point back to the current
chunk. Many trivial memory overflows should trip that test.

One way to make this test more robust could involve xor'ing the values
within respective accessor pairs. But at least the fact that the size
value is shifted by one bit already prevent fooling the test with a
same-byte corruption.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre d1125d21d4 sys_heap: remove need for last_chunk()
We already have chunk #0 containing our struct z_heap and marked as
used. We can add a partial chunk at the very end that is also marked
as used. By doing so there is no longer a need for checking heap
boundaries at run time when merging/splitting chunks meaning fewer
conditionals in the code's hot path.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre 6d827fa080 sys_heap: introduce min_chunk_size()
With this we can remove magic constants, especially those used with
big_heap().

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre e553161b8e sys_heap: optimize struct z_heap
It is possible to remove a few fields from struct z_heap, removing
some runtime indirections by doing so:

- The buf pointer is actually the same as the struct z_heap pointer
  itself. So let's simply create chunk_buf() that perform a type
  conversion. That type is also chunk_unit_t now rather than u64_t so
  it can be defined based on CHUNK_UNIT.

- Replace the struct z_heap_bucket pointer by a zero-sized array at the
  end of struct z_heap.

- Make chunk #0 into an actual chunk with its own header. This allows
  for removing the chunk0 field and streamlining the code. This way
  h->chunk0 becomes right_chunk(h, 0). This sets the table for further
  simplifications to come.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre e2b64777e5 sys_heap: optimize usage of size and used flags
By storing the used flag in the LSB, it is no longer necessary to have
a size_mask variable to locate that flag. This produces smaller and
faster code.

Replace the validation check in chunk_set() to base it on the storage
type.

Also clarify the semantics of set_chunk_size() which allows for clearing
the used flag bit unconditionally which simplifies the code further.

The idea of moving the used flag bit into the LEFT_SIZE field was
raised. It turns out that this isn't as beneficial as it may seem
because the used bit is set only once i.e. when the memory is handed off
to a user and the size field becomes frozen at that point. Modifications
on the leftward chunk may still occur and extra instructions to preserve
that bit would be necessary if it were moved there.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre 54950aca01 sys_heap: provide more chunk_fields accessors
Let's provide accessors for getting and setting every field to make the
chunk header layout abstracted away from the main code. Those are:

SIZE_AND_USED: chunk_used(), chunk_size(), set_chunk_used() and
chunk_size().

LEFT_SIZE: left_chunk() and set_left_chunk_size().

FREE_PREV: prev_free_chunk() and set_prev_free_chunk().

FREE_NEXT: next_free_chunk() and set_next_free_chunk().

To be consistent, the former chunk_set_used() is now set_chunk_used().

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Nicolas Pitre f97eca26e6 sys_heap: some cleanups to make the code clearer
First, some renames to make accessors more explicit:

  size() --> chunk_size()
  used() --> chunk_used()
  free_prev() --> prev_free_chunk()
  free_next() --> next_free_chunk()

Then, the return type of chunk_size() is changed from chunkid_t to
size_t, and chunk_used() from chunkid_t to bool.

The left_size() accessor is used only once and can be easily substituted
by left_chunk(), so it is removed.

And in free_list_add() the variable b is renamed to bi so to be
consistent with usage in sys_heap_alloc().

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2020-06-21 19:25:35 +02:00
Kumar Gala a1b77fd589 zephyr: replace zephyr integer types with C99 types
git grep -l 'u\(8\|16\|32\|64\)_t' | \
		xargs sed -i "s/u\(8\|16\|32\|64\)_t/uint\1_t/g"
	git grep -l 's\(8\|16\|32\|64\)_t' | \
		xargs sed -i "s/s\(8\|16\|32\|64\)_t/int\1_t/g"

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2020-06-08 08:23:57 -05:00
Andy Ross aa4227754c lib/os: Add sys_heap, a new/simpler/faster memory allocator
The existing mem_pool implementation has been an endless source of
frustration.  It's had alignment bugs, it's had racy behavior.  It's
never been particularly fast.  It's outrageously complicated to
configure statically.  And while its fragmentation resistance and
overhead on small blocks is good, it's space efficiencey has always
been very poor due to the four-way buddy scheme.

This patch introduces sys_heap.  It's a more or less conventional
segregated fit allocator with power-of-two buckets.  It doesn't expose
its level structure to the user at all, simply taking an arbitrarily
aligned pointer to memory.  It stores all metadata inside the heap
region.  It allocates and frees by simple pointer and not block ID.
Static initialization is trivial, and runtime initialization is only a
few cycles to format and add one block to a list header.

It has excellent space efficiency.  Chunks can be split arbitrarily in
8 byte units.  Overhead is only four bytes per allocated chunk (eight
bytes for heaps >256kb or on 64 bit systems), plus a log2-sized array
of 2-word bucket headers.  No coarse alignment restrictions on blocks,
they can be split and merged (in units of 8 bytes) arbitrarily.

It has good fragmentation resistance.  Freed blocks are always
immediately merged with adjacent free blocks.  Allocations are
attempted from a sample of the smallest bucket that might fit, falling
back rapidly to the smallest block guaranteed to fit.  Split memory
remaining in the chunk is always returned immediately to the heap for
other allocation.

It has excellent performance with firmly bounded runtime.  All
operations are constant time (though there is a search of the smallest
bucket that has a compile-time-configurable upper bound, setting this
to extreme values results in an effectively linear search of the
list), objectively fast (about a hundred instructions) and amenable to
locked operation.  No more need for fragile lock relaxation trickery.

It also contains an extensive validation and stress test framework,
something that was sorely lacking in the previous implementation.

Note that sys_heap is not a compatible API with sys_mem_pool and
k_mem_pool.  Partial wrappers for those (now-) legacy APIs will appear
later and a deprecation strategy needs to be chosen.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2020-04-14 10:05:55 -07:00