GitHub

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

NameKindDescription
syn_mem_lifetime_tenumMemory 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_tstructTensor 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_tstructMemory 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

SignatureDescription
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:

c
/* 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() and syn_mem_scratch_release() are deliberate no-ops; the only way to reclaim memory is syn_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 from CONFIG_SYNAPTIC_SCRATCH_POOL_SIZE (range 1024–65536); the arena size from CONFIG_SYNAPTIC_TENSOR_ARENA_SIZE (range 4096–524288). See the Kconfig reference.
  • Ownership: in a normal application syn_init() owns the arena buffer and calls syn_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.