ssm
0.0.2
Runtime Library for the Sparse Synchronous Model
|
Values are always word-sized, and may point to heap-allocated, reference-counted objects; heap memory is allocated from a set of size-indexed memory pools. More...
Values are always word-sized, and may point to heap-allocated, reference-counted objects; heap memory is allocated from a set of size-indexed memory pools.
For simplicity and flexibility, all values in SSM runtime are word-sized, represented using ssm_value_t. When the size of a value exceeds what can be represented by a word, the value is a pointer to a heap-allocated object. In particular, they point to a memory management metadata header, ssm_mm.
The SSM runtime uses reference counting to manage the lifetime of heap objects. The reference count is also maintained in the ssm_mm header. When a reference is duplicated, use ssm_dup() to increment its reference count. When a reference is dropped, use ssm_drop() decrement its reference and free if necessary. These macros first check whether the given ssm_value_t is heap-allocated before attempting to dereference the heap pointer; to skip this check (for example, if a value is known to be a heap object at compile time), use ssm_dup_unsafe() and ssm_drop_unsafe(). When the reference count of an object reaches zero, it is cleaned up and freed using ssm_drop_final(), which drop any references held by the soon-to-be-freed object.
The ssm_mm header's kind field indicates what ssm_kind the object is. This determines its memory layout in the heap, in particular where the object might hold references (pointers) to other heap objects. The interpretation and layout of the 16-bit info field depends on the kind, coming in three different "flavors": vector, variant, and size. All this information is used by ssm_drop_final() to figure out the number and location of values to ssm_drop(), as well as the size of the object to deallocate.
Heap objects are allocated for each ssm_kind using functions with prefix ssm_new_, such as ssm_new_adt() or ssm_new_time().
The SSM runtime comes with its own platform-agnostic allocator, parameterized by handlers set using ssm_mem_init(). It allocates small pieces of memory in blocks, within designated memory pools. Each memory pool consists of zero or more fixed-size memory pages, and are requested from the platform/OS on-demand via the alloc_page() handler. Meanwhile, allocations for larger ranges of memory are deferred to the alloc_mem() and free_mem() handlers.
The allocator's memory pools may be configured using the SSM_MEM_POOL_MIN, SSM_MEM_POOL_FACTOR_BASE2, SSM_MEM_POOL_COUNT, and SSM_MEM_PAGE_SIZE preprocessor constants. The default values produce 4 memory pools, of sizes 16B, 64B, 256B, and 1024B, and a memory page size of 4096B.
The runtime recognizes several compile time configuration macros that help with profiling and debugging. They are:
Data Structures | |
struct | ssm_mem_statistics_pool |
Statistics for a heap page pool; used in ssm_mem_statistics_t. More... | |
struct | ssm_mem_statistics |
Statistics for the heap; filled with ssm_mem_statistics_collect(). More... | |
union | ssm_value_t |
SSM values are either "packed" values or heap-allocated. More... | |
struct | ssm_mm |
The memory management metadata "header" for heap-allocated objects. More... | |
Macros | |
#define | SSM_MEM_POOL_MIN 16 |
Block size of the smallest memory pool. More... | |
#define | SSM_MEM_POOL_FACTOR_BASE2 2 |
Factor between each successive memory pool size, in base 2. More... | |
#define | SSM_MEM_POOL_COUNT 4 |
Number of memory pools. More... | |
#define | SSM_MEM_POOL_SIZE(pool) (SSM_MEM_POOL_MIN << (SSM_MEM_POOL_FACTOR_BASE2 * pool)) |
Compute the size of a memory pool. More... | |
#define | SSM_MEM_POOL_MAX SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT - 1) |
The size of the largest memory pool. More... | |
#define | SSM_MEM_PAGE_SIZE SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT) |
The size of a memory page; must be greater than SSM_MEM_POOL_MAX. More... | |
#define | ssm_marshal(v) (ssm_value_t) { .packed_val = ((v) << 1 | 1) } |
Construct an ssm_value_t from a 31-bit integral value. More... | |
#define | ssm_unmarshal(v) ((v).packed_val >> 1) |
Extract an integral value from a packed ssm_value_t. More... | |
#define | ssm_on_heap(v) (((v).packed_val & 0x1) == 0) |
Whether a value is on the heap (i.e., is an object). More... | |
#define | ssm_is_shared(v) !(ssm_on_heap(v) && ((v).heap_ptr->ref_count == 1)) |
Whether a value is shared, i.e., unsafe to modify. More... | |
#define | ssm_dup(v) (ssm_on_heap(v) ? ssm_dup_unsafe(v) : (v)) |
Duplicate a possible heap reference, incrementing its ref count. More... | |
#define | ssm_drop(v) |
Drop a reference to a possible heap item, and free it if necessary. More... | |
#define | ssm_dup_unsafe(v) ((++(v).heap_ptr->ref_count, (v))) |
Duplicate a heap reference, incrementing its ref count. More... | |
#define | ssm_drop_unsafe(v) |
Drop a reference to a heap item, and free it if necessary. More... | |
Typedefs | |
typedef struct ssm_mem_statistics_pool | ssm_mem_statistics_pool_t |
Statistics for a heap page pool; used in ssm_mem_statistics_t. More... | |
typedef struct ssm_mem_statistics | ssm_mem_statistics_t |
Statistics for the heap; filled with ssm_mem_statistics_collect(). More... | |
typedef uint32_t | ssm_word_t |
Values are 32-bits, the largest supported machine word size. More... | |
Enumerations | |
enum | ssm_kind { SSM_TIME_K = 0 , SSM_ADT_K , SSM_SV_K , SSM_CLOSURE_K , SSM_ARRAY_K , SSM_BLOB_K } |
The different kinds of heap objects, enumerated. More... | |
Functions | |
void | ssm_mem_init (void *(*alloc_page_handler)(void), void *(*alloc_mem_handler)(size_t), void(*free_mem_handler)(void *, size_t)) |
Initializes the underlying allocator system. More... | |
void | ssm_mem_destroy (void(*free_page_handler)(void *)) |
Tears down the underlying allocator system. More... | |
void | ssm_mem_statistics_collect (ssm_mem_statistics_t *stats) |
Collect and return statistics about the heap. More... | |
void | ssm_drop_final (ssm_value_t v) |
Finalize and free a heap object. More... | |
void | ssm_dups (size_t cnt, ssm_value_t *arr) |
Call ssm_dup() on an array of values. More... | |
void | ssm_drops (size_t cnt, ssm_value_t *arr) |
Call ssm_drop() on an array of values. More... | |
void * | ssm_mem_alloc (size_t size) |
Allocate a contiguous range of memory. More... | |
void | ssm_mem_prealloc (size_t size, size_t num_pages) |
Preallocate memory pages to ensure capacity in memory pools. More... | |
void | ssm_mem_free (void *m, size_t size) |
Deallocate memory allocated by ssm_mem_alloc(). More... | |
#define SSM_MEM_POOL_MIN 16 |
Block size of the smallest memory pool.
Must be strictly greater than the word size, i.e., the size of ssm_word_t.
Definition at line 185 of file ssm-internal.h.
#define SSM_MEM_POOL_FACTOR_BASE2 2 |
Factor between each successive memory pool size, in base 2.
Must be strictly greater than 0.
Definition at line 199 of file ssm-internal.h.
#define SSM_MEM_POOL_COUNT 4 |
Number of memory pools.
Must be strictly greater than 0.
Definition at line 213 of file ssm-internal.h.
#define SSM_MEM_POOL_SIZE | ( | pool | ) | (SSM_MEM_POOL_MIN << (SSM_MEM_POOL_FACTOR_BASE2 * pool)) |
Compute the size of a memory pool.
pool | the 0-index of the memory pool. |
Definition at line 227 of file ssm-internal.h.
#define SSM_MEM_POOL_MAX SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT - 1) |
The size of the largest memory pool.
Definition at line 234 of file ssm-internal.h.
#define SSM_MEM_PAGE_SIZE SSM_MEM_POOL_SIZE(SSM_MEM_POOL_COUNT) |
The size of a memory page; must be greater than SSM_MEM_POOL_MAX.
Definition at line 241 of file ssm-internal.h.
#define ssm_marshal | ( | v | ) | (ssm_value_t) { .packed_val = ((v) << 1 | 1) } |
Construct an ssm_value_t from a 31-bit integral value.
v | the 31-bit integral value. |
#define ssm_unmarshal | ( | v | ) | ((v).packed_val >> 1) |
Extract an integral value from a packed ssm_value_t.
v | the packed ssm_value_t. |
#define ssm_on_heap | ( | v | ) | (((v).packed_val & 0x1) == 0) |
Whether a value is on the heap (i.e., is an object).
v | pointer to the ssm_value_t. |
#define ssm_is_shared | ( | v | ) | !(ssm_on_heap(v) && ((v).heap_ptr->ref_count == 1)) |
Whether a value is shared, i.e., unsafe to modify.
The opposite of "shared" is "unique," as in C++'s "unique_ptr."
v | pointer to the ssm_value_t. |
#define ssm_dup | ( | v | ) | (ssm_on_heap(v) ? ssm_dup_unsafe(v) : (v)) |
Duplicate a possible heap reference, incrementing its ref count.
If the caller knows v is definitely on the heap, call ssm_drop_unsafe() to eliminate the heap check (and omit call if it is definitely not on the heap).
v | pointer to the ssm_mm header of the heap item. |
#define ssm_drop | ( | v | ) |
Drop a reference to a possible heap item, and free it if necessary.
If v is freed, all references held by the heap item itself will also be be dropped.
If the caller knows that v is definitely a heap item, call ssm_drop_unsafe() to eliminate the heap check (and omit call if it is definitely not on the heap).
v | ssm_value_t to be dropped. |
#define ssm_dup_unsafe | ( | v | ) | ((++(v).heap_ptr->ref_count, (v))) |
Duplicate a heap reference, incrementing its ref count.
Called by ssm_dup().
ssm_on_heap(v)
.v | pointer to the ssm_mm header of the heap item. |
#define ssm_drop_unsafe | ( | v | ) |
Drop a reference to a heap item, and free it if necessary.
If v is freed, ssm_drop_final() will be called to drop all heap objects v refers to.
Called by ssm_drop().
ssm_on_heap(v)
.v | ssm_value_t to be dropped. |
typedef struct ssm_mem_statistics_pool ssm_mem_statistics_pool_t |
Statistics for a heap page pool; used in ssm_mem_statistics_t.
typedef struct ssm_mem_statistics ssm_mem_statistics_t |
Statistics for the heap; filled with ssm_mem_statistics_collect().
A collection of satistics collected by ssm_mem_statistics_collect() and designed to be printed by a function you supply.
typedef uint32_t ssm_word_t |
enum ssm_kind |
The different kinds of heap objects, enumerated.
Types enumerated here that are not ADTs are chosen because they cannot be easily or efficiently expressed as a product of words. For instance, 64-bit timestamps cannot be directly stored in the payload of a regular heap object, where even-numbered timestamps may be misinterpreted as pointers.
Enumerator | |
---|---|
SSM_TIME_K | 64-bit timestamps, ssm_time_t |
SSM_ADT_K | ADT object, e.g., ssm_adt1. |
SSM_SV_K | Scheduled variables, ssm_sv_t. |
SSM_CLOSURE_K | Closure object, e.g., ssm_closure1. |
SSM_ARRAY_K | Array of values, e.g., ssm_array1. |
SSM_BLOB_K | Blob of arbitrary data, e.g., ssm_blob1. |
void ssm_mem_init | ( | void *(*)(void) | alloc_page_handler, |
void *(*)(size_t) | alloc_mem_handler, | ||
void(*)(void *, size_t) | free_mem_handler | ||
) |
Initializes the underlying allocator system.
Memory pages are requested from the platform/OS on-demand via the provided alloc_page_handler. This handler must return a pointer to the beginning of a range of memory of size SSM_MEM_PAGE_SIZE, and the page must be zeroed out. These pages are assumed to never be freed.
To support arbitrarily large allocations, SSM's allocator uses alloc_mem_handler to allocate memory, and free_mem_handler to release it. There are no requirements on the contents of memory allocated with alloc_mem_handler. These handlers may also assume they will not be invoked to request memory ranges of less than SSM_MEM_POOL_MAX bytes.
If the allocator is compiled with valgrind support (i.e., USE_VALGRIND is defined), it will perform a leak-check summary, to checkpoint how much memory has already been allocated.
alloc_page_handler | allocates pages. |
alloc_mem_handler | allocates arbitrarily large. |
free_mem_handler | frees memory allocated with alloc_mem_handler. |
void ssm_mem_destroy | ( | void(*)(void *) | free_page_handler | ) |
Tears down the underlying allocator system.
If the allocator is compiled with valgrind support (i.e., USE_VALGRIND is defined), it will perform a full leak-check summary, to report how much memory has been leaked since ssm_mem_init().
free_page_handler | frees pages allocated with alloc_page_handler. |
void ssm_mem_statistics_collect | ( | ssm_mem_statistics_t * | stats | ) |
Collect and return statistics about the heap.
stats | non-NULL pointer to a ssm_mem_statistics_t to be filled in |
void ssm_drop_final | ( | ssm_value_t | v | ) |
Finalize and free a heap object.
Drops all heap objects v refers to, and perform any additional finalization as required by the ssm_kind of v.
Called by ssm_drop_unsafe().
ssm_on_heap(v)
.v | ssm_value_t to be finalized and freed. |
void ssm_dups | ( | size_t | cnt, |
ssm_value_t * | arr | ||
) |
void ssm_drops | ( | size_t | cnt, |
ssm_value_t * | arr | ||
) |
Call ssm_drop() on an array of values.
void* ssm_mem_alloc | ( | size_t | size | ) |
Allocate a contiguous range of memory.
Memory will be allocated from an appropriately sized memory pool, if one is available. Guaranteed to be aligned against the smallest power of 2 greater than size.
size | the requested memory range size, in bytes. |
void ssm_mem_prealloc | ( | size_t | size, |
size_t | num_pages | ||
) |
Preallocate memory pages to ensure capacity in memory pools.
Does nothing if no memory pool will fit a block of size.
size | size whose memory pool should be preallocaed pages. |
num_pages | number of pages to allocate. |
void ssm_mem_free | ( | void * | m, |
size_t | size | ||
) |
Deallocate memory allocated by ssm_mem_alloc().
The behavior of freeing memory not allocated by ssm_mem_alloc() is undefined.
m | pointer to the memory range allocated by ssm_mem_alloc(). |
size | the size of the memory range allocated by ssm_mem_alloc(). |