Docs / API reference / syn_mem.h
syn_mem.hv0.1.0
<synaptic/syn_mem.h> is the tensor memory manager: a bump-pointer arena with a persistent/ephemeral region split, a separate scratch pool at the top of the arena, and 16-byte alignment on every allocation for NPU DMA compatibility. Tensors are allocated with an explicit lifetime class, ephemeral memory is reclaimed in O(1) with a single reset call between inferences, and live statistics (usage, high-water mark, allocation counts) are available at any time. The concepts behind the design are covered in The tensor memory model.
Types & constants
| Name | Kind | Description |
|---|---|---|
syn_mem_lifetime_t | enum | Memory lifetime classification. SYN_MEM_PERSISTENT — lives across inference calls (weights, biases); SYN_MEM_EPHEMERAL — freed after each inference (activations); SYN_MEM_SHARED — in the shared IPC region (input/output tensors). |
syn_tensor_t | struct | Tensor descriptor. Fields: void *data — pointer to tensor data; size_t size — total size in bytes; syn_npu_dtype_t dtype — data type; uint8_t ndim — number of dimensions (max 4); uint32_t shape[4] — shape as [batch, height, width, ch]; syn_mem_lifetime_t lifetime — memory lifetime class. |
syn_mem_stats_t | struct | Memory statistics. Fields: size_t arena_total — total arena size; size_t arena_used — currently allocated; size_t arena_peak — high-water mark; size_t scratch_total — total scratch pool size; size_t scratch_used — currently used scratch; uint32_t alloc_count — total allocations since init; uint32_t reset_count — total ephemeral resets since init. |
The element type syn_npu_dtype_t (INT8, UINT8, INT16, FLOAT16, FLOAT32) is defined in syn_hal_npu.h, which this header includes.
Functions
| Signature | Description |
|---|---|
int syn_mem_init(void *arena_base, size_t arena_size) | Initializes the arena over a caller-provided buffer. The top CONFIG_SYNAPTIC_SCRATCH_POOL_SIZE bytes are reserved as the scratch pool. Returns 0 on success, -EINVAL if arena_base is NULL, arena_size is 0, or the arena is not larger than the scratch pool. Normally called for you by syn_init(). |
void syn_mem_reset_ephemeral(void) | Resets the ephemeral region and the scratch pool to empty in O(1) and increments reset_count. Persistent allocations are untouched. Call between inferences. |
syn_tensor_t *syn_mem_tensor_alloc(const uint32_t *shape, uint8_t ndim, syn_npu_dtype_t dtype, syn_mem_lifetime_t lifetime) | Allocates a tensor descriptor plus its data block from the arena in one 16-byte-aligned allocation. Returns the descriptor, or NULL if the arena is uninitialized, shape is NULL, ndim is 0 or greater than 4, or the arena is out of space. |
void syn_mem_tensor_free(syn_tensor_t *tensor) | No-op in the bump allocator — individual frees are not supported. Reclaim ephemeral tensors with syn_mem_reset_ephemeral(). |
int syn_mem_tensor_init(syn_tensor_t *tensor, const uint32_t *shape, uint8_t ndim, syn_npu_dtype_t dtype) | Fills in a caller-owned tensor descriptor (size, dtype, ndim, shape) without allocating any data. data and lifetime are left for the caller to set. Returns 0 on success, -EINVAL on NULL arguments or invalid ndim. |
void *syn_mem_scratch_acquire(size_t size) | Bump-allocates size bytes (16-byte aligned) from the scratch pool at the top of the arena. Returns the pointer, or NULL if the arena is uninitialized, size is 0, or the pool is exhausted. |
void syn_mem_scratch_release(void *ptr) | No-op — scratch memory is reclaimed as a whole by syn_mem_reset_ephemeral(). |
int syn_mem_get_stats(syn_mem_stats_t *stats) | Copies current statistics into *stats. Returns 0 on success, -EINVAL if stats is NULL or the arena is uninitialized. |
void syn_mem_print_stats(void) | Logs a one-line arena summary (usable/used/persistent/ephemeral/peak/scratch) via the Zephyr logging subsystem. |
Usage
From the hello_inference sample — allocate an ephemeral input tensor, fill it, and print the arena state afterwards:
/* Allocate a 1x16x16x3 INT8 input tensor from the ephemeral region */
uint32_t input_shape[] = {1, 16, 16, 3};
syn_tensor_t *input = syn_mem_tensor_alloc(input_shape, 4,
SYN_NPU_DTYPE_INT8,
SYN_MEM_EPHEMERAL);
if (input == NULL) {
return -ENOMEM;
}
/* Fill with a test pattern */
uint8_t *data = (uint8_t *)input->data;
for (size_t i = 0; i < input->size; i++) {
data[i] = (uint8_t)(i & 0xFF);
}
/* ... run inference ... */
syn_mem_print_stats();
/* Reclaim all ephemeral tensors and scratch in O(1) */
syn_mem_reset_ephemeral();Notes
- Implementation status: fully implemented in v0.1.0 (
src/core/syn_mem.c). - Allocator semantics: this is a bump allocator.
syn_mem_tensor_free()andsyn_mem_scratch_release()are deliberate no-ops; the only way to reclaim memory issyn_mem_reset_ephemeral()(ephemeral + scratch) or re-initializing the arena. Persistent allocations live until re-init. - Layout:
[base … persistent … ephemeral … | scratch pool … base+total]. The scratch pool size comes fromCONFIG_SYNAPTIC_SCRATCH_POOL_SIZE(range 1024–65536); the arena size fromCONFIG_SYNAPTIC_TENSOR_ARENA_SIZE(range 4096–524288). See the Kconfig reference. - Ownership: in a normal application
syn_init()owns the arena buffer and callssyn_mem_init()— see syn_api.h. Call it directly only in bare-bones tests that skip the full runtime. - SYN_MEM_SHARED: the lifetime class for tensors in the inter-core IPC region is defined now; the dual-core transport that uses it is part of the IPC work — see syn_ipc.h and Dual-core design & IPC.
- Threading: the allocator keeps its state in a single static structure without internal locking; serialize concurrent allocations at the application level.