mm: move preceding to previous free node to reduce the overhead

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
This commit is contained in:
wangbowen6 2022-12-22 16:02:42 +08:00 committed by Xiang Xiao
parent 723c6e52e2
commit b1948a1631
11 changed files with 105 additions and 70 deletions

View File

@ -119,7 +119,8 @@
*/
#define MM_ALLOC_BIT 0x1
#define MM_MASK_BIT MM_ALLOC_BIT
#define MM_PREVFREE_BIT 0x2
#define MM_MASK_BIT (MM_ALLOC_BIT | MM_PREVFREE_BIT)
#ifdef CONFIG_MM_SMALL
# define MMSIZE_MAX UINT16_MAX
#else
@ -130,6 +131,13 @@
#define SIZEOF_MM_ALLOCNODE sizeof(struct mm_allocnode_s)
/* What is the overhead of the allocnode
* Remove the space of preceding field since it locates at the end of the
* previous freenode
*/
#define OVERHEAD_MM_ALLOCNODE (SIZEOF_MM_ALLOCNODE - sizeof(mmsize_t))
/* What is the size of the freenode? */
#define SIZEOF_MM_FREENODE sizeof(struct mm_freenode_s)

View File

@ -100,10 +100,9 @@ void mm_extend(FAR struct mm_heap_s *heap, FAR void *mem, size_t size,
/* Get and initialize the new terminal node in the heap */
newnode = (FAR struct mm_allocnode_s *)
(blockend - SIZEOF_MM_ALLOCNODE);
newnode->size = SIZEOF_MM_ALLOCNODE | MM_ALLOC_BIT;
newnode->preceding = size;
newnode = (FAR struct mm_allocnode_s *)
(blockend - SIZEOF_MM_ALLOCNODE);
newnode->size = SIZEOF_MM_ALLOCNODE | MM_ALLOC_BIT;
heap->mm_heapend[region] = newnode;

View File

@ -79,13 +79,14 @@ void mm_foreach(FAR struct mm_heap_s *heap, mm_node_handler_t handler,
node = (FAR struct mm_allocnode_s *)((FAR char *)node + nodesize))
{
nodesize = SIZEOF_MM_NODE(node);
minfo("region=%d node=%p size=%zu preceding=%u (%c)\n",
minfo("region=%d node=%p size=%zu preceding=%u (%c %c)\n",
region, node, nodesize, (unsigned int)node->preceding,
(node->size & MM_PREVFREE_BIT) ? 'F' : 'A',
(node->size & MM_ALLOC_BIT) ? 'A' : 'F');
handler(node, arg);
DEBUGASSERT(prev == NULL ||
DEBUGASSERT((node->size & MM_PREVFREE_BIT) == 0 ||
SIZEOF_MM_NODE(prev) == node->preceding);
prev = node;
}

View File

@ -120,7 +120,7 @@ void mm_free(FAR struct mm_heap_s *heap, FAR void *mem)
/* Check if the following node is free and, if so, merge it */
next = (FAR struct mm_freenode_s *)((FAR char *)node + nodesize);
DEBUGASSERT(next->preceding == nodesize);
DEBUGASSERT((next->size & MM_PREVFREE_BIT) == 0);
if ((next->size & MM_ALLOC_BIT) == 0)
{
FAR struct mm_allocnode_s *andbeyond;
@ -132,6 +132,8 @@ void mm_free(FAR struct mm_heap_s *heap, FAR void *mem)
*/
andbeyond = (FAR struct mm_allocnode_s *)((FAR char *)next + nextsize);
DEBUGASSERT((andbeyond->size & MM_PREVFREE_BIT) != 0 &&
andbeyond->preceding == nextsize);
/* Remove the next node. There must be a predecessor,
* but there may not be a successor node.
@ -151,16 +153,24 @@ void mm_free(FAR struct mm_heap_s *heap, FAR void *mem)
andbeyond->preceding = nodesize;
next = (FAR struct mm_freenode_s *)andbeyond;
}
else
{
next->size |= MM_PREVFREE_BIT;
next->preceding = nodesize;
}
/* Check if the preceding node is also free and, if so, merge
* it with this node
*/
prev = (FAR struct mm_freenode_s *)((FAR char *)node - node->preceding);
prevsize = SIZEOF_MM_NODE(prev);
DEBUGASSERT(node->preceding == prevsize);
if ((prev->size & MM_ALLOC_BIT) == 0)
if ((node->size & MM_PREVFREE_BIT) != 0)
{
prev = (FAR struct mm_freenode_s *)
((FAR char *)node - node->preceding);
prevsize = SIZEOF_MM_NODE(prev);
DEBUGASSERT((prev->size & MM_ALLOC_BIT) == 0 &&
node->preceding == prevsize);
/* Remove the node. There must be a predecessor, but there may
* not be a successor node.
*/

View File

@ -134,19 +134,18 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart,
* all available memory.
*/
heap->mm_heapstart[IDX] = (FAR struct mm_allocnode_s *)
heapbase;
heap->mm_heapstart[IDX] = (FAR struct mm_allocnode_s *)heapbase;
MM_ADD_BACKTRACE(heap, heap->mm_heapstart[IDX]);
heap->mm_heapstart[IDX]->size = SIZEOF_MM_ALLOCNODE | MM_ALLOC_BIT;
node = (FAR struct mm_freenode_s *)
(heapbase + SIZEOF_MM_ALLOCNODE);
heap->mm_heapstart[IDX]->size = SIZEOF_MM_ALLOCNODE | MM_ALLOC_BIT;
node = (FAR struct mm_freenode_s *)
(heapbase + SIZEOF_MM_ALLOCNODE);
DEBUGASSERT((((uintptr_t)node + SIZEOF_MM_ALLOCNODE) % MM_MIN_CHUNK) == 0);
node->size = heapsize - 2*SIZEOF_MM_ALLOCNODE;
node->preceding = SIZEOF_MM_ALLOCNODE;
heap->mm_heapend[IDX] = (FAR struct mm_allocnode_s *)
(heapend - SIZEOF_MM_ALLOCNODE);
heap->mm_heapend[IDX]->size = SIZEOF_MM_ALLOCNODE | MM_ALLOC_BIT;
heap->mm_heapend[IDX]->preceding = node->size;
node->size = heapsize - 2 * SIZEOF_MM_ALLOCNODE;
heap->mm_heapend[IDX] = (FAR struct mm_allocnode_s *)
(heapend - SIZEOF_MM_ALLOCNODE);
heap->mm_heapend[IDX]->size = SIZEOF_MM_ALLOCNODE | MM_ALLOC_BIT |
MM_PREVFREE_BIT;
heap->mm_heapend[IDX]->preceding = node->size;
MM_ADD_BACKTRACE(heap, heap->mm_heapend[IDX]);
#undef IDX

View File

@ -129,7 +129,15 @@ int mm_mallinfo(FAR struct mm_heap_s *heap, FAR struct mallinfo *info)
mm_foreach(heap, mallinfo_handler, info);
info->arena = heap->mm_heapsize;
info->uordblks += region * SIZEOF_MM_ALLOCNODE; /* account for the tail node */
/* Account for the heap->mm_heapend[region] node overhead and the
* heap->mm_heapstart[region]->preceding:
* heap->mm_heapend[region] overhead size = OVERHEAD_MM_ALLOCNODE
* heap->mm_heapstart[region]->preceding size = sizeof(mmsize_t)
* and SIZEOF_MM_ALLOCNODE = OVERHEAD_MM_ALLOCNODE + sizeof(mmsize_t).
*/
info->uordblks += region * SIZEOF_MM_ALLOCNODE;
DEBUGASSERT((size_t)info->uordblks + info->fordblks == heap->mm_heapsize);

View File

@ -133,7 +133,7 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
* (2) to make sure that it is an even multiple of our granule size.
*/
alignsize = MM_ALIGN_UP(size + SIZEOF_MM_ALLOCNODE);
alignsize = MM_ALIGN_UP(size + OVERHEAD_MM_ALLOCNODE);
if (alignsize < size)
{
/* There must have been an integer overflow */
@ -189,6 +189,13 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
node->flink->blink = node->blink;
}
/* Get a pointer to the next node in physical memory */
next = (FAR struct mm_freenode_s *)(((FAR char *)node) + nodesize);
DEBUGASSERT((next->size & MM_ALLOC_BIT) != 0 &&
(next->size & MM_PREVFREE_BIT) != 0 &&
next->preceding == nodesize);
/* Check if we have to split the free node into one of the allocated
* size and another smaller freenode. In some cases, the remaining
* bytes can be smaller (they may be SIZEOF_MM_ALLOCNODE). In that
@ -199,21 +206,16 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
remaining = nodesize - alignsize;
if (remaining >= SIZEOF_MM_FREENODE)
{
/* Get a pointer to the next node in physical memory */
next = (FAR struct mm_freenode_s *)(((FAR char *)node) + nodesize);
/* Create the remainder node */
remainder = (FAR struct mm_freenode_s *)
(((FAR char *)node) + alignsize);
remainder->size = remaining;
remainder->preceding = alignsize;
remainder->size = remaining;
/* Adjust the size of the node under consideration */
node->size = alignsize;
node->size = alignsize | (node->size & MM_MASK_BIT);
/* Adjust the 'preceding' size of the (old) next node. */
@ -223,6 +225,14 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
mm_addfreechunk(heap, remainder);
}
else
{
/* Previous physical memory node is alloced, so clear the previous
* free bit in next->size.
*/
next->size &= ~MM_PREVFREE_BIT;
}
/* Handle the case of an exact size match */
@ -238,7 +248,7 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
MM_ADD_BACKTRACE(heap, node);
kasan_unpoison(ret, mm_malloc_size(heap, ret));
#ifdef CONFIG_MM_FILL_ALLOCATIONS
memset(ret, 0xaa, alignsize - SIZEOF_MM_ALLOCNODE);
memset(ret, 0xaa, alignsize - OVERHEAD_MM_ALLOCNODE);
#endif
#ifdef CONFIG_DEBUG_MM
minfo("Allocated %p, size %zu\n", ret, alignsize);

View File

@ -62,5 +62,5 @@ size_t mm_malloc_size(FAR struct mm_heap_s *heap, FAR void *mem)
DEBUGASSERT(node->size & MM_ALLOC_BIT);
return SIZEOF_MM_NODE(node) - SIZEOF_MM_ALLOCNODE;
return SIZEOF_MM_NODE(node) - OVERHEAD_MM_ALLOCNODE;
}

View File

@ -146,7 +146,6 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
{
FAR struct mm_allocnode_s *newnode;
FAR struct mm_allocnode_s *next;
FAR struct mm_freenode_s *prev;
size_t precedingsize;
size_t newnodesize;
@ -154,8 +153,6 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
next = (FAR struct mm_allocnode_s *)
((FAR char *)node + SIZEOF_MM_NODE(node));
prev = (FAR struct mm_freenode_s *)
((FAR char *)node - node->preceding);
/* Make sure that there is space to convert the preceding
* mm_allocnode_s into an mm_freenode_s. I think that this should
@ -193,8 +190,11 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
* set up the node size.
*/
if ((prev->size & MM_ALLOC_BIT) == 0)
if ((node->size & MM_PREVFREE_BIT) != 0)
{
FAR struct mm_freenode_s *prev =
(FAR struct mm_freenode_s *)((FAR char *)node - node->preceding);
/* Remove the node. There must be a predecessor, but there may
* not be a successor node.
*/
@ -206,7 +206,7 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
prev->flink->blink = prev->blink;
}
precedingsize += prev->size;
precedingsize += SIZEOF_MM_NODE(prev);
node = (FAR struct mm_allocnode_s *)prev;
}
@ -215,18 +215,18 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
/* Set up the size of the new node */
newnodesize = (uintptr_t)next - (uintptr_t)newnode;
newnode->size = newnodesize | MM_ALLOC_BIT;
newnode->size = newnodesize | MM_ALLOC_BIT | MM_PREVFREE_BIT;
newnode->preceding = precedingsize;
/* Fix the preceding size of the next node */
/* Clear the previous free bit of the next node */
next->preceding = newnodesize;
next->size &= ~MM_PREVFREE_BIT;
/* Convert the newnode chunk size back into malloc-compatible size by
* subtracting the header size SIZEOF_MM_ALLOCNODE.
* subtracting the header size OVERHEAD_MM_ALLOCNODE.
*/
allocsize = newnodesize - SIZEOF_MM_ALLOCNODE;
allocsize = newnodesize - OVERHEAD_MM_ALLOCNODE;
/* Add the original, newly freed node to the free nodelist */
@ -240,16 +240,16 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
}
/* Check if there is free space at the end of the aligned chunk. Convert
* malloc-compatible chunk size to include SIZEOF_MM_ALLOCNODE as needed
* malloc-compatible chunk size to include OVERHEAD_MM_ALLOCNODE as needed
* for mm_shrinkchunk.
*/
size = MM_ALIGN_UP(size + SIZEOF_MM_ALLOCNODE);
size = MM_ALIGN_UP(size + OVERHEAD_MM_ALLOCNODE);
if (allocsize > size)
{
/* Shrink the chunk by that much -- remember, mm_shrinkchunk wants
* internal chunk sizes that include SIZEOF_MM_ALLOCNODE.
* internal chunk sizes that include OVERHEAD_MM_ALLOCNODE.
*/
mm_shrinkchunk(heap, node, size);

View File

@ -71,7 +71,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
size_t size)
{
FAR struct mm_allocnode_s *oldnode;
FAR struct mm_freenode_s *prev;
FAR struct mm_freenode_s *prev = NULL;
FAR struct mm_freenode_s *next;
size_t newsize;
size_t oldsize;
@ -117,7 +117,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
* (2) to make sure that it is an even multiple of our granule size.
*/
newsize = MM_ALIGN_UP(size + SIZEOF_MM_ALLOCNODE);
newsize = MM_ALIGN_UP(size + OVERHEAD_MM_ALLOCNODE);
if (newsize < size)
{
/* There must have been an integer overflow */
@ -149,8 +149,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
if (newsize < oldsize)
{
mm_shrinkchunk(heap, oldnode, newsize);
kasan_poison((FAR char *)oldnode + SIZEOF_MM_NODE(oldnode),
oldsize - SIZEOF_MM_NODE(oldnode));
kasan_poison((FAR char *)oldnode + SIZEOF_MM_NODE(oldnode) +
sizeof(mmsize_t), oldsize - SIZEOF_MM_NODE(oldnode));
}
/* Then return the original address */
@ -169,13 +169,15 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
next = (FAR struct mm_freenode_s *)((FAR char *)oldnode + oldsize);
if ((next->size & MM_ALLOC_BIT) == 0)
{
DEBUGASSERT((next->size & MM_PREVFREE_BIT) == 0);
nextsize = SIZEOF_MM_NODE(next);
}
prev = (FAR struct mm_freenode_s *)
((FAR char *)oldnode - oldnode->preceding);
if ((prev->size & MM_ALLOC_BIT) == 0)
if ((oldnode->size & MM_PREVFREE_BIT) != 0)
{
prev = (FAR struct mm_freenode_s *)
((FAR char *)oldnode - oldnode->preceding);
DEBUGASSERT((prev->size & MM_ALLOC_BIT) == 0);
prevsize = SIZEOF_MM_NODE(prev);
}
@ -251,7 +253,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
* there may not be a successor node.
*/
DEBUGASSERT(prev->blink);
DEBUGASSERT(prev && prev->blink);
prev->blink->flink = prev->flink;
if (prev->flink)
{
@ -273,11 +275,10 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
prevsize -= takeprev;
DEBUGASSERT(prevsize >= SIZEOF_MM_FREENODE);
prev->size = prevsize;
prev->size = prevsize | (prev->size & MM_MASK_BIT);
nodesize += takeprev;
newnode->size = nodesize | MM_MASK_BIT;
newnode->size = nodesize | MM_ALLOC_BIT | MM_PREVFREE_BIT;
newnode->preceding = prevsize;
next->preceding = nodesize;
/* Return the previous free node to the nodelist
* (with the new size)
@ -289,9 +290,9 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
{
/* Yes.. update its size (newnode->preceding is already set) */
nodesize += prevsize;
newnode->size = nodesize | MM_ALLOC_BIT;
next->preceding = nodesize;
nodesize += prevsize;
newnode->size = nodesize | MM_ALLOC_BIT |
(newnode->size & MM_MASK_BIT);
}
newmem = (FAR void *)((FAR char *)newnode + SIZEOF_MM_ALLOCNODE);
@ -343,7 +344,6 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
((FAR char *)oldnode + nodesize);
newnode->size = nextsize - takenext;
DEBUGASSERT(newnode->size >= SIZEOF_MM_FREENODE);
newnode->preceding = nodesize;
andbeyond->preceding = newnode->size;
/* Add the new free node to the nodelist (with the new size) */
@ -354,7 +354,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
{
/* Yes, just update some pointers. */
andbeyond->preceding = nodesize;
andbeyond->size &= ~MM_PREVFREE_BIT;
}
}
@ -368,7 +368,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
* should be safe for this.
*/
memcpy(newmem, oldmem, oldsize - SIZEOF_MM_ALLOCNODE);
memcpy(newmem, oldmem, oldsize - OVERHEAD_MM_ALLOCNODE);
}
return newmem;
@ -388,7 +388,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
newmem = mm_malloc(heap, size);
if (newmem)
{
memcpy(newmem, oldmem, oldsize - SIZEOF_MM_ALLOCNODE);
memcpy(newmem, oldmem, oldsize - OVERHEAD_MM_ALLOCNODE);
mm_free(heap, oldmem);
}

View File

@ -72,6 +72,7 @@ void mm_shrinkchunk(FAR struct mm_heap_s *heap,
/* Get the chunk next the next node (which could be the tail chunk) */
andbeyond = (FAR struct mm_allocnode_s *)((FAR char *)next + nextsize);
DEBUGASSERT((andbeyond->size & MM_PREVFREE_BIT) != 0);
/* Remove the next node. There must be a predecessor, but there may
* not be a successor node.
@ -93,7 +94,6 @@ void mm_shrinkchunk(FAR struct mm_heap_s *heap,
/* Set up the size of the new node */
newnode->size = nextsize + nodesize - size;
newnode->preceding = size;
node->size = size | (node->size & MM_MASK_BIT);
andbeyond->preceding = newnode->size;
@ -118,10 +118,10 @@ void mm_shrinkchunk(FAR struct mm_heap_s *heap,
/* Set up the size of the new node */
newnode->size = nodesize - size;
newnode->preceding = size;
node->size = size | (node->size & MM_MASK_BIT);
next->preceding = newnode->size;
newnode->size = nodesize - size;
node->size = size | (node->size & MM_MASK_BIT);
next->size |= MM_PREVFREE_BIT;
next->preceding = newnode->size;
/* Add the new node to the freenodelist */