Add FreeRTOS heap4 intro card

This commit is contained in:
mpabi
2026-05-02 00:53:25 +02:00
commit e69aaa6d61
29 changed files with 2250 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
#ifndef HEAP4_COMMON_H
#define HEAP4_COMMON_H
#include <stddef.h>
#include <stdint.h>
#ifdef HOST_PRINTF
#include <stdio.h>
#define TRACE_PRINTF(...) printf(__VA_ARGS__)
#else
#define TRACE_PRINTF(...) ((void)0)
#endif
#define HEAP4_ARRAY_LEN(a) ((int)(sizeof(a) / sizeof((a)[0])))
#define HEAP4_ALIGNMENT ((size_t)8)
#define HEAP4_ALIGNMENT_MASK (HEAP4_ALIGNMENT - 1U)
#define HEAP4_ALLOCATED_BIT ((size_t)1U << (sizeof(size_t) * 8U - 1U))
typedef struct HeapBlock {
struct HeapBlock *next;
size_t size;
} HeapBlock;
static inline size_t heap4_align_up(size_t value)
{
if ((value & HEAP4_ALIGNMENT_MASK) != 0U)
value += HEAP4_ALIGNMENT - (value & HEAP4_ALIGNMENT_MASK);
return value;
}
static inline uintptr_t heap4_align_address(uintptr_t address)
{
uintptr_t mask;
mask = (uintptr_t)HEAP4_ALIGNMENT_MASK;
if ((address & mask) != 0U)
address += (uintptr_t)HEAP4_ALIGNMENT - (address & mask);
return address;
}
static inline size_t heap4_clear_allocated(size_t size)
{
return size & ~HEAP4_ALLOCATED_BIT;
}
static inline size_t heap4_mark_allocated(size_t size)
{
return size | HEAP4_ALLOCATED_BIT;
}
static inline int heap4_is_allocated(size_t size)
{
return (size & HEAP4_ALLOCATED_BIT) != 0U;
}
static inline int heap4_blocks_touch(HeapBlock *left, HeapBlock *right)
{
return (uint8_t *)left + heap4_clear_allocated(left->size) == (uint8_t *)right;
}
#endif
+29
View File
@@ -0,0 +1,29 @@
#include "heap4_common.h"
volatile size_t g_header_size;
volatile size_t g_aligned_header_size;
volatile size_t g_allocated_bit_set;
volatile size_t g_user_bytes;
volatile size_t g_total_block_bytes;
int main(void)
{
HeapBlock block;
size_t requested;
requested = 13U;
block.next = 0;
block.size = heap4_mark_allocated(heap4_align_up(requested + sizeof(HeapBlock)));
g_header_size = sizeof(HeapBlock);
g_aligned_header_size = heap4_align_up(sizeof(HeapBlock));
g_allocated_bit_set = heap4_is_allocated(block.size);
g_total_block_bytes = heap4_clear_allocated(block.size);
g_user_bytes = g_total_block_bytes - sizeof(HeapBlock);
TRACE_PRINTF("header=%u aligned=%u allocated=%u total=%u user=%u\n",
(unsigned)g_header_size, (unsigned)g_aligned_header_size,
(unsigned)g_allocated_bit_set, (unsigned)g_total_block_bytes,
(unsigned)g_user_bytes);
return 0;
}
+64
View File
@@ -0,0 +1,64 @@
#include "heap4_common.h"
volatile size_t g_free_total;
volatile size_t g_largest_free;
volatile int g_node_count;
static size_t list_total(HeapBlock *start)
{
HeapBlock *block;
size_t total;
total = 0U;
for (block = start->next; block != 0; block = block->next)
total += block->size;
return total;
}
static size_t list_largest(HeapBlock *start)
{
HeapBlock *block;
size_t largest;
largest = 0U;
for (block = start->next; block != 0; block = block->next)
if (block->size > largest)
largest = block->size;
return largest;
}
static int list_count(HeapBlock *start)
{
HeapBlock *block;
int count;
count = 0;
for (block = start->next; block != 0; block = block->next)
count++;
return count;
}
int main(void)
{
HeapBlock start;
HeapBlock a;
HeapBlock b;
HeapBlock c;
start.next = &a;
start.size = 0U;
a.next = &b;
a.size = 32U;
b.next = &c;
b.size = 80U;
c.next = 0;
c.size = 24U;
g_free_total = list_total(&start);
g_largest_free = list_largest(&start);
g_node_count = list_count(&start);
TRACE_PRINTF("free=%u largest=%u count=%d\n",
(unsigned)g_free_total, (unsigned)g_largest_free, g_node_count);
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
#include "heap4_common.h"
#define HEAP_BYTES 160U
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile size_t g_initial_free_size;
volatile uintptr_t g_aligned_offset;
volatile int g_end_is_last;
static void heap_init(void)
{
uintptr_t raw;
uintptr_t aligned;
size_t available;
HeapBlock *first;
raw = (uintptr_t)&heap_area[0];
aligned = heap4_align_address(raw);
available = HEAP_BYTES - (size_t)(aligned - raw);
available &= ~HEAP4_ALIGNMENT_MASK;
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + available - sizeof(HeapBlock));
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
}
int main(void)
{
heap_init();
g_aligned_offset = (uintptr_t)start.next - (uintptr_t)&heap_area[0];
g_initial_free_size = start.next->size;
g_end_is_last = (start.next->next == end_marker) && (end_marker->next == 0);
TRACE_PRINTF("offset=%u free=%u end_last=%d\n",
(unsigned)g_aligned_offset, (unsigned)g_initial_free_size,
g_end_is_last);
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#include "heap4_common.h"
volatile size_t g_request_1;
volatile size_t g_request_9;
volatile size_t g_request_17;
volatile uintptr_t g_address_delta;
int main(void)
{
uint8_t bytes[32];
uintptr_t raw;
uintptr_t aligned;
g_request_1 = heap4_align_up(1U + sizeof(HeapBlock));
g_request_9 = heap4_align_up(9U + sizeof(HeapBlock));
g_request_17 = heap4_align_up(17U + sizeof(HeapBlock));
raw = (uintptr_t)&bytes[1];
aligned = heap4_align_address(raw);
g_address_delta = aligned - raw;
TRACE_PRINTF("r1=%u r9=%u r17=%u delta=%u\n",
(unsigned)g_request_1, (unsigned)g_request_9,
(unsigned)g_request_17, (unsigned)g_address_delta);
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
#include "heap4_common.h"
#define HEAP_BYTES 128U
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile size_t g_allocated_size;
volatile size_t g_remaining_free;
volatile int g_allocation_ok;
static void heap_init_one_block(void)
{
uintptr_t raw;
uintptr_t aligned;
HeapBlock *first;
raw = (uintptr_t)&heap_area[0];
aligned = heap4_align_address(raw);
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + 120U);
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
}
static void *heap_malloc_whole_block(size_t wanted)
{
HeapBlock *previous;
HeapBlock *block;
size_t total;
total = heap4_align_up(wanted + sizeof(HeapBlock));
previous = &start;
block = start.next;
while (block != end_marker) {
if (block->size >= total) {
previous->next = block->next;
block->next = 0;
block->size = heap4_mark_allocated(block->size);
return (uint8_t *)block + sizeof(HeapBlock);
}
previous = block;
block = block->next;
}
return 0;
}
int main(void)
{
void *p;
HeapBlock *allocated;
heap_init_one_block();
p = heap_malloc_whole_block(24U);
allocated = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
g_allocation_ok = p != 0;
g_allocated_size = heap4_clear_allocated(allocated->size);
g_remaining_free = start.next->size;
TRACE_PRINTF("ok=%d allocated=%u remaining=%u\n",
g_allocation_ok, (unsigned)g_allocated_size,
(unsigned)g_remaining_free);
return 0;
}
+93
View File
@@ -0,0 +1,93 @@
#include "heap4_common.h"
#define HEAP_BYTES 192U
#define MIN_SPLIT_SIZE ((size_t)(sizeof(HeapBlock) * 2U))
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile size_t g_allocated_size;
volatile size_t g_split_free_size;
volatile int g_free_nodes;
static void heap_init_one_block(void)
{
uintptr_t aligned;
HeapBlock *first;
aligned = heap4_align_address((uintptr_t)&heap_area[0]);
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + 176U);
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
}
static void *heap_malloc_split(size_t wanted)
{
HeapBlock *previous;
HeapBlock *block;
HeapBlock *remainder;
size_t total;
size_t original;
total = heap4_align_up(wanted + sizeof(HeapBlock));
previous = &start;
block = start.next;
while (block != end_marker) {
if (block->size >= total) {
original = block->size;
if (original - total > MIN_SPLIT_SIZE) {
remainder = (HeapBlock *)((uint8_t *)block + total);
remainder->size = original - total;
remainder->next = block->next;
previous->next = remainder;
block->size = total;
} else {
previous->next = block->next;
}
block->next = 0;
block->size = heap4_mark_allocated(block->size);
return (uint8_t *)block + sizeof(HeapBlock);
}
previous = block;
block = block->next;
}
return 0;
}
static int count_free_nodes(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
int main(void)
{
void *p;
HeapBlock *allocated;
heap_init_one_block();
p = heap_malloc_split(32U);
allocated = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
g_allocated_size = heap4_clear_allocated(allocated->size);
g_split_free_size = start.next->size;
g_free_nodes = count_free_nodes();
TRACE_PRINTF("allocated=%u split=%u nodes=%d\n",
(unsigned)g_allocated_size, (unsigned)g_split_free_size,
g_free_nodes);
return 0;
}
+88
View File
@@ -0,0 +1,88 @@
#include "heap4_common.h"
static uint8_t heap_area[192];
static HeapBlock start;
static HeapBlock *end_marker;
volatile int g_order_ok;
volatile int g_free_count;
volatile size_t g_total_free;
static void insert_block(HeapBlock *block)
{
HeapBlock *iterator;
for (iterator = &start; iterator->next < block; iterator = iterator->next)
;
block->next = iterator->next;
iterator->next = block;
}
static void heap_free_model(void *p)
{
HeapBlock *block;
if (p == 0)
return;
block = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
block->size = heap4_clear_allocated(block->size);
insert_block(block);
}
static int count_free(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
static size_t total_free(void)
{
HeapBlock *block;
size_t total;
total = 0U;
for (block = start.next; block != end_marker; block = block->next)
total += block->size;
return total;
}
int main(void)
{
HeapBlock *a;
HeapBlock *b;
HeapBlock *c;
void *payload;
a = (HeapBlock *)&heap_area[0];
b = (HeapBlock *)&heap_area[64];
c = (HeapBlock *)&heap_area[128];
end_marker = (HeapBlock *)&heap_area[176];
start.next = a;
a->next = c;
c->next = end_marker;
end_marker->next = 0;
a->size = 40U;
b->size = heap4_mark_allocated(32U);
c->size = 48U;
end_marker->size = 0U;
payload = (uint8_t *)b + sizeof(HeapBlock);
heap_free_model(payload);
g_order_ok = start.next == a && a->next == b && b->next == c && c->next == end_marker;
g_free_count = count_free();
g_total_free = total_free();
TRACE_PRINTF("order=%d count=%d total=%u\n",
g_order_ok, g_free_count, (unsigned)g_total_free);
return 0;
}
+76
View File
@@ -0,0 +1,76 @@
#include "heap4_common.h"
static uint8_t heap_area[192];
static HeapBlock start;
static HeapBlock *end_marker;
volatile int g_free_count;
volatile size_t g_merged_size;
volatile int g_merged_with_right;
static void insert_block_merge(HeapBlock *block)
{
HeapBlock *iterator;
uint8_t *block_end;
for (iterator = &start; iterator->next < block; iterator = iterator->next)
;
block_end = (uint8_t *)block + block->size;
if (block_end == (uint8_t *)iterator->next) {
block->size += iterator->next->size;
block->next = iterator->next->next;
} else {
block->next = iterator->next;
}
if (iterator != &start && heap4_blocks_touch(iterator, block)) {
iterator->size += block->size;
iterator->next = block->next;
} else {
iterator->next = block;
}
}
static int count_free(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
int main(void)
{
HeapBlock *left;
HeapBlock *middle;
HeapBlock *right;
left = (HeapBlock *)&heap_area[0];
middle = (HeapBlock *)&heap_area[48];
right = (HeapBlock *)&heap_area[96];
end_marker = (HeapBlock *)&heap_area[160];
start.next = left;
left->next = right;
right->next = end_marker;
end_marker->next = 0;
left->size = 48U;
middle->size = 48U;
right->size = 64U;
end_marker->size = 0U;
insert_block_merge(middle);
g_free_count = count_free();
g_merged_size = start.next->size;
g_merged_with_right = start.next->next == end_marker;
TRACE_PRINTF("count=%d size=%u merged_right=%d\n",
g_free_count, (unsigned)g_merged_size, g_merged_with_right);
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
#include "heap4_common.h"
#ifndef CONFIG_TOTAL_HEAP_SIZE
#define CONFIG_TOTAL_HEAP_SIZE 256U
#endif
#ifndef CONFIG_SUPPORT_DYNAMIC_ALLOCATION
#define CONFIG_SUPPORT_DYNAMIC_ALLOCATION 1
#endif
#define CONFIG_ADJUSTED_HEAP_SIZE (CONFIG_TOTAL_HEAP_SIZE - HEAP4_ALIGNMENT)
volatile size_t g_total_heap;
volatile size_t g_adjusted_heap;
volatile int g_dynamic_enabled;
volatile int g_trace_is_host_only;
int main(void)
{
g_total_heap = CONFIG_TOTAL_HEAP_SIZE;
g_adjusted_heap = CONFIG_ADJUSTED_HEAP_SIZE;
g_dynamic_enabled = CONFIG_SUPPORT_DYNAMIC_ALLOCATION;
#ifdef HOST_PRINTF
g_trace_is_host_only = 1;
#else
g_trace_is_host_only = 0;
#endif
TRACE_PRINTF("heap=%u adjusted=%u dynamic=%d host_trace=%d\n",
(unsigned)g_total_heap, (unsigned)g_adjusted_heap,
g_dynamic_enabled, g_trace_is_host_only);
return 0;
}
+175
View File
@@ -0,0 +1,175 @@
#include "heap4_common.h"
#define HEAP_BYTES 256U
#define MIN_SPLIT_SIZE ((size_t)(sizeof(HeapBlock) * 2U))
static uint8_t heap_area[HEAP_BYTES + HEAP4_ALIGNMENT];
static HeapBlock start;
static HeapBlock *end_marker;
volatile int g_allocations_ok;
volatile int g_final_free_nodes;
volatile size_t g_final_free_total;
volatile size_t g_minimum_ever_free;
static size_t free_bytes_remaining;
static size_t minimum_ever_free;
static size_t list_total(void)
{
HeapBlock *block;
size_t total;
total = 0U;
for (block = start.next; block != end_marker; block = block->next)
total += block->size;
return total;
}
static int list_count(void)
{
HeapBlock *block;
int count;
count = 0;
for (block = start.next; block != end_marker; block = block->next)
count++;
return count;
}
static void insert_block_merge(HeapBlock *block)
{
HeapBlock *iterator;
uint8_t *block_end;
for (iterator = &start; iterator->next < block; iterator = iterator->next)
;
block_end = (uint8_t *)block + block->size;
if (block_end == (uint8_t *)iterator->next) {
block->size += iterator->next->size;
block->next = iterator->next->next;
} else {
block->next = iterator->next;
}
if (iterator != &start && heap4_blocks_touch(iterator, block)) {
iterator->size += block->size;
iterator->next = block->next;
} else {
iterator->next = block;
}
}
static void heap_init(void)
{
uintptr_t raw;
uintptr_t aligned;
size_t available;
HeapBlock *first;
raw = (uintptr_t)&heap_area[0];
aligned = heap4_align_address(raw);
available = HEAP_BYTES - (size_t)(aligned - raw);
available &= ~HEAP4_ALIGNMENT_MASK;
first = (HeapBlock *)aligned;
end_marker = (HeapBlock *)(aligned + available - sizeof(HeapBlock));
end_marker->next = 0;
end_marker->size = 0U;
first->next = end_marker;
first->size = (uint8_t *)end_marker - (uint8_t *)first;
start.next = first;
start.size = 0U;
free_bytes_remaining = first->size;
minimum_ever_free = free_bytes_remaining;
}
static void *heap_malloc_model(size_t wanted)
{
HeapBlock *previous;
HeapBlock *block;
HeapBlock *remainder;
size_t total;
size_t original;
if (wanted == 0U)
return 0;
total = heap4_align_up(wanted + sizeof(HeapBlock));
previous = &start;
block = start.next;
while (block != end_marker) {
if (block->size >= total) {
original = block->size;
if (original - total > MIN_SPLIT_SIZE) {
remainder = (HeapBlock *)((uint8_t *)block + total);
remainder->size = original - total;
remainder->next = block->next;
previous->next = remainder;
block->size = total;
} else {
previous->next = block->next;
total = original;
}
block->next = 0;
block->size = heap4_mark_allocated(block->size);
free_bytes_remaining -= total;
if (free_bytes_remaining < minimum_ever_free)
minimum_ever_free = free_bytes_remaining;
return (uint8_t *)block + sizeof(HeapBlock);
}
previous = block;
block = block->next;
}
return 0;
}
static void heap_free_model(void *p)
{
HeapBlock *block;
size_t size;
if (p == 0)
return;
block = (HeapBlock *)((uint8_t *)p - sizeof(HeapBlock));
if (!heap4_is_allocated(block->size))
return;
size = heap4_clear_allocated(block->size);
block->size = size;
free_bytes_remaining += size;
insert_block_merge(block);
}
int main(void)
{
void *a;
void *b;
void *c;
heap_init();
a = heap_malloc_model(24U);
b = heap_malloc_model(40U);
heap_free_model(a);
c = heap_malloc_model(16U);
heap_free_model(b);
heap_free_model(c);
g_allocations_ok = a != 0 && b != 0 && c != 0;
g_final_free_nodes = list_count();
g_final_free_total = list_total();
g_minimum_ever_free = minimum_ever_free;
TRACE_PRINTF("ok=%d nodes=%d free=%u min=%u\n",
g_allocations_ok, g_final_free_nodes,
(unsigned)g_final_free_total, (unsigned)g_minimum_ever_free);
return 0;
}