Memory.xcc
Benoit Dupont de Dinechin (Benoit.Dupont-de-Dinechin@st.com)
Copyright 2007 STMicroelectronics. Copyright 1995 - 1998 Commissariat a l'Energie Atomique.
This program is free software; you can redistribute it and/or modify it under the terms of either (at your option): the GNU General Public License (GPL) version 2; the GNU Lesser General Public License (LGPL) version 2.1; any later version of these licences as published by the Free Software Foundation.
This module implements the memory allocator used by all the CDT containers and data structures. It basically provides the "reap" interface proposed by "Reconsidering Custom Memory Allocation" by E. D. Berger, B. G. Zorn, K. S. McKinley. This is done on top of the system malloc().
The "reap" interface provides a 'freeAll' method to free all the memory of a Memory allocator at once, and also supports parent-child relationships between Memory allocators so that deleting one recursively deletes its children.
In addition to the "reap" interface, we enable memory pooling of small-sized allocation requests. Pooling is controlled by a threshold supplied to Memory_new. Currently pooled memory is only release when freeAll or Memory_delete is called.
MemoryUsage— State to track memory usage.
struct MemoryUsage_ { //@args uint32_t INUSE; // Current memory space in use. uint32_t MAXUSE; // Maximum memory space used. uint32_t OPENED; // Current number of allocations in all size ranges. uint32_t ALLOCS; // Total number of allocations in all size ranges. MemoryUsageRecord_ SMALLRECORDS[MemoryUsage_SMALLCOUNT]; MemoryUsageRecord_ LARGERECORDS[MemoryUsage_LARGECOUNT]; };
MemoryUsage_pretty— Pretty-print this MemoryUsage.
bool MemoryUsage_pretty(const_MemoryUsage this, FILE *file);
MemoryUsage_alloc— Trace usage of malloc
.
void MemoryUsage_alloc(MemoryUsage this, uint32_t size, bool isPool);
MemoryUsage_free— Trace usage of free
.
void MemoryUsage_free(MemoryUsage this, uint32_t size, bool isPool);
MemoryListItem— Fields needed by the items of a MemoryList.
struct MemoryListItem_ { //@args struct MemoryListItem_ *NEXT; struct MemoryListItem_ *PREV; };
MemoryList— Manage a list of items derived from MemoryListItem.
struct MemoryList_ { //@args struct MemoryListItem_ *FIRST; struct MemoryListItem_ *LAST; };
MemoryList_first -- For use by MemoryList_FOREACH_MemoryListItem.
static inline MemoryListItem MemoryList_first(MemoryList this) { return MemoryList_FIRST(this); }
MemoryList_FOREACH_MemoryListItem— Iterator.
#define MemoryList_FOREACH_MemoryListItem(this, item) { \ MemoryListItem MemoryList_NEXT = NULL; \ MemoryListItem item = MemoryList_first(this); \ for (; item != NULL; item = MemoryList_NEXT) { \ MemoryList_NEXT = MemoryListItem_NEXT(item); #define MemoryList_ENDEACH_MemoryListItem \ } \ }
MemoryList_append— Append item to this MemoryList.
void MemoryList_append(MemoryList this, MemoryListItem item);
MemoryList_remove— Remove item from this MemoryList.
void MemoryList_remove(MemoryList this, MemoryListItem item);
MemoryTableEntry— Entry in a MemoryTable.
struct MemoryTableEntry_ { //@args void *start, size_t useSize, int level, //@args struct MemoryTableEntry_ *leaf size_t USESIZE; // Size of memory available for use. uint16_t LEVEL; // Level to keep the binary search tree balanced. uint16_t REFC; // Reference counter of this MemoryTableEntry_. struct MemoryTableEntry_ *LEFT; // The left kid in the binary search tree. struct MemoryTableEntry_ *RIGHT; // The right kid in the binary search tree. char *START; // The start memory address. //@access PAST (MemoryTableEntry_START(this) + MemoryTableEntry_USESIZE(this)) struct MemoryBlock_ *NEXTBLOCK; // Next MemoryBlock in the Memory_RECYCLE list. //@access BLOCK (MemoryBlock)((MemoryListItem)(this) - 1) };
MemoryTable— Maps addresses to MemoryBlock(s).
Currently the MemoryTable only allows search and insert operations.
Uses a balanced search tree as described in "Balanced Search Trees Made Simple" by Arne Andersson (http://user.it.uu.se/~arnea/research.html).
struct MemoryTable_ { //@args void *memory MemoryTableEntry_ LEAF_; //@access LEAF MemoryTable__LEAF_(this) MemoryTableEntry ROOT; };
MemoryTable_search— Search this MemoryTable for the MemoryBlock containing address
.
struct MemoryBlock_ * MemoryTable_search(const_MemoryTable this, const void *address);
MemoryBlock— Block of memory.
struct MemoryBlock_ { //@args size_t useSize, MemoryTableEntry leaf MemoryListItem_ ITEM_; //@access ITEM MemoryBlock__ITEM_(this) //@access NEXT (MemoryBlock)MemoryListItem_NEXT(MemoryBlock_ITEM(this)) //@access PREV (MemoryBlock)MemoryListItem_PREV(MemoryBlock_ITEM(this)) MemoryTableEntry_ ENTRY_; //@access ENTRY MemoryBlock__ENTRY_(this) //@access NEXTBLOCK MemoryTableEntry_NEXTBLOCK(MemoryBlock_ENTRY(this)) //@mutate NEXTBLOCK MemoryTableEntry__NEXTBLOCK(MemoryBlock_ENTRY(this)) //@access REALSIZE (sizeof(MemoryBlock_) + MemoryBlock_USESIZE(this)) //@access USESIZE MemoryTableEntry_USESIZE(MemoryBlock_ENTRY(this)) //@mutate USESIZE MemoryTableEntry__USESIZE(MemoryBlock_ENTRY(this)) //@access START MemoryTableEntry_START(MemoryBlock_ENTRY(this)) //@mutate START MemoryTableEntry__START(MemoryBlock_ENTRY(this)) //@access PAST MemoryTableEntry_PAST(MemoryBlock_ENTRY(this)) //@access REFC MemoryTableEntry_REFC(MemoryBlock_ENTRY(this)) //@mutate REFC MemoryTableEntry__REFC(MemoryBlock_ENTRY(this)) };
Memory -- Memory allocator.
struct Memory_ { //@args Memory parent, size_t pooled MemoryListItem_ ITEM_; // Used to embed this Memory in a MemoryList. //@access ITEM Memory__ITEM_(this) //@access NEXT (Memory)MemoryListItem_NEXT(Memory_ITEM(this)) //@access PREV (Memory)MemoryListItem_PREV(Memory_ITEM(this)) struct Memory_ *PARENT; // Parent in the Memory parent-child relationships. //@access isRoot (Memory_PARENT(this) == NULL) size_t POOLED; // Maximum alloc size for request to be pooled. size_t TOTALSIZE; // Total allocated size (for statistics). size_t TOTALCOUNT; // Total allocated count (for statistics). MemoryBlock POOLBLOCK; // Currently active pooling block. char *POOLFIRST; // First available address in pooling block. char *POOLPAST; // Past available address in pooling block. MemoryBlock RECYCLE; // Start of list of MemoryBlock(s) to recycle. MemoryList_ CHILDREN_; // Children of this Memory allocator. //@access CHILDREN Memory__CHILDREN_(this) MemoryList_ BLOCKS_; // MemoryBlock(s) managed by this Memory allocator. //@access BLOCKS Memory__BLOCKS_(this) //@access TABLE (MemoryTable)(this + 1) };
Memory_new— Make a new Memory allocator.
parent
- The parent memory allocator.
pooled
- The maximum allocation size pooled by this Memory allocator.
Memory allocators are organized in tree thanks to the parent
parameter. When a
Memory allocator is deleted or does freeAll, it recursively deletes all its children.
The pooled
parameter is the threshold on allocation size beyond which the
Memory_alloc
and Memory_free
directly forward to malloc
and free
. For
allocations sizes no greater than pooled
, the requests are pooled by the
Memory allocator.
Memory Memory_new(Memory parent, size_t pooled);
Memory_delete— Delete this Memory allocator.
Memory Memory_delete(Memory this);
Memory_children— For use by Memory_CHILDREN_FOREACH_Memory.
static inline MemoryList Memory_children(Memory this) { return Memory_CHILDREN(this); }
Memory_CHILDREN_FOREACH_Memory— Iterator for Memory_CHILDREN.
#define Memory_CHILDREN_FOREACH_Memory(this, child) { \ MemoryList Memory_CHILDREN = Memory_children(this); \ MemoryList_FOREACH_MemoryListItem(Memory_CHILDREN, item) { \ Memory child = (Memory)item; #define Memory_CHILDREN_ENDEACH_Memory \ } MemoryList_ENDEACH_MemoryListItem; \ }
Memory_blocks— For use by Memory_FOREACH_MemoryBlock.
static inline MemoryList Memory_blocks(Memory this) { return Memory_BLOCKS(this); }
Memory_FOREACH_MemoryBlock— Iterator for Memory_BLOCKS.
#define Memory_FOREACH_MemoryBlock(this, block) { \ MemoryList Memory_BLOCKS = Memory_blocks(this); \ MemoryList_FOREACH_MemoryListItem(Memory_BLOCKS, item) { \ MemoryBlock block = (MemoryBlock)item; #define Memory_ENDEACH_MemoryBlock \ } MemoryList_ENDEACH_MemoryListItem; \ }
Memory_POOLFACTOR -- Multiplied by Memory_POOLED to compute pooling block use size.
#ifndef Memory_POOLFACTOR #define Memory_POOLFACTOR 8 #endif//Memory_POOLFACTOR
Memory_alloc_— Specialized Memory_alloc
for non-zero aligned alignedSize
.
void * Memory_alloc_(Memory this, size_t alignedSize);
Memory_alloc— Allocate memory in its own MemoryBlock or in a pool.
size
- The requested allocation size in bytes.
- Return
- Allocated address that holds
size
bytes. - Ensure
- Returned address is non-NULL.
static inline void * Memory_alloc(Memory this, size_t size) { Except_CHECK(this != NULL); if (size > 0) { size_t alignedSize = CDT_ALIGN_NEXT(size); void *alloc = Memory_alloc_(this, alignedSize); return alloc; } return NULL; }
Memory_free_— Specialized Memory_free
for non-NULL address
.
void Memory_free_(Memory this, void *address);
Memory_free— Free the memory at given address
unless it is pooled.
Pooled memory is not returned to the system until this
Memory is deleted.
However, reference counting of pooling memory blocks is maintained so when all
the allocations of such a block are freed it is recycled.
static inline void * Memory_free(Memory this, void *address) { Except_CHECK(this != NULL); if (address != NULL) { Except_CHECK(CDT_ALIGNED(address)); Memory_free_(this, address); } return NULL; }
Memory_freeAll— Free all the MemoryBlock(s) and children of this Memory allocator.
void Memory_freeAll(Memory this);
Memory_realloc— Reallocate data allocated by this Memory allocator.
void * Memory_realloc(Memory this, void* address, size_t size);