137 lines
3.4 KiB
C
137 lines
3.4 KiB
C
#include "heap4_model.h"
|
|
|
|
enum { BLOCK_BYTES = 48 };
|
|
|
|
typedef struct {
|
|
ModelBlock first;
|
|
uint8_t first_payload[BLOCK_BYTES - sizeof(ModelBlock)];
|
|
ModelBlock middle;
|
|
uint8_t middle_payload[BLOCK_BYTES - sizeof(ModelBlock)];
|
|
ModelBlock last;
|
|
uint8_t last_payload[BLOCK_BYTES - sizeof(ModelBlock)];
|
|
} CoalesceArena;
|
|
|
|
typedef union {
|
|
uint64_t force_alignment;
|
|
CoalesceArena blocks;
|
|
} AlignedCoalesceArena;
|
|
|
|
AlignedCoalesceArena g_coalesce_arena;
|
|
ModelBlock *g_free_head;
|
|
volatile size_t g_before_nodes;
|
|
volatile size_t g_before_total;
|
|
volatile size_t g_before_largest;
|
|
volatile size_t g_after_nodes;
|
|
volatile size_t g_after_total;
|
|
volatile size_t g_after_largest;
|
|
volatile int g_task02_pass;
|
|
|
|
static void insert_and_coalesce(ModelBlock *block)
|
|
{
|
|
ModelBlock *previous = NULL;
|
|
ModelBlock *current = g_free_head;
|
|
|
|
while (current != NULL && (uintptr_t)current < (uintptr_t)block)
|
|
{
|
|
previous = current;
|
|
current = current->next;
|
|
}
|
|
|
|
block->next = current;
|
|
if (current != NULL &&
|
|
(uint8_t *)block + block->size == (uint8_t *)current)
|
|
{
|
|
block->size += current->size;
|
|
block->next = current->next;
|
|
}
|
|
|
|
if (previous != NULL &&
|
|
(uint8_t *)previous + previous->size == (uint8_t *)block)
|
|
{
|
|
previous->size += block->size;
|
|
previous->next = block->next;
|
|
}
|
|
else if (previous != NULL)
|
|
{
|
|
previous->next = block;
|
|
}
|
|
else
|
|
{
|
|
g_free_head = block;
|
|
}
|
|
}
|
|
|
|
static void measure(size_t *nodes, size_t *total, size_t *largest)
|
|
{
|
|
ModelBlock *block;
|
|
|
|
*nodes = 0U;
|
|
*total = 0U;
|
|
*largest = 0U;
|
|
for (block = g_free_head; block != NULL; block = block->next)
|
|
{
|
|
(*nodes)++;
|
|
*total += block->size;
|
|
if (block->size > *largest)
|
|
{
|
|
*largest = block->size;
|
|
}
|
|
}
|
|
}
|
|
|
|
__attribute__((noinline)) void task02_fragmented_checkpoint(void)
|
|
{
|
|
#if defined(__GNUC__)
|
|
__asm__ volatile("" ::: "memory");
|
|
#endif
|
|
}
|
|
|
|
__attribute__((noinline)) void task02_debug_checkpoint(void)
|
|
{
|
|
#if defined(__GNUC__)
|
|
__asm__ volatile("" ::: "memory");
|
|
#endif
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
CoalesceArena *arena = &g_coalesce_arena.blocks;
|
|
size_t nodes;
|
|
size_t total;
|
|
size_t largest;
|
|
|
|
arena->first.size = BLOCK_BYTES;
|
|
arena->middle.size = BLOCK_BYTES;
|
|
arena->last.size = BLOCK_BYTES;
|
|
g_free_head = NULL;
|
|
|
|
insert_and_coalesce(&arena->first);
|
|
insert_and_coalesce(&arena->last);
|
|
measure(&nodes, &total, &largest);
|
|
g_before_nodes = nodes;
|
|
g_before_total = total;
|
|
g_before_largest = largest;
|
|
task02_fragmented_checkpoint();
|
|
|
|
insert_and_coalesce(&arena->middle);
|
|
measure(&nodes, &total, &largest);
|
|
g_after_nodes = nodes;
|
|
g_after_total = total;
|
|
g_after_largest = largest;
|
|
g_task02_pass =
|
|
g_before_nodes == 2U && g_before_total == 96U &&
|
|
g_before_largest == 48U && g_after_nodes == 1U &&
|
|
g_after_total == 144U && g_after_largest == 144U &&
|
|
g_free_head == &arena->first && g_free_head->next == NULL;
|
|
|
|
task02_debug_checkpoint();
|
|
|
|
#if defined(HOST_PRINTF)
|
|
printf("before_nodes=%zu before_total=%zu before_largest=%zu "
|
|
"after_nodes=%zu after_total=%zu after_largest=%zu pass=%d\n",
|
|
g_before_nodes, g_before_total, g_before_largest,
|
|
g_after_nodes, g_after_total, g_after_largest, g_task02_pass);
|
|
#endif
|
|
return g_task02_pass ? 0 : 1;
|
|
}
|