Portable C99 runtime for TiGrIS. Executes .tgrs inference plans on embedded devices with no dynamic allocation and no dependencies beyond libc.
A .tgrs plan is an ordered list of operator calls with pre-computed tile parameters, arena offsets, and weight pointers. The runtime is small because it does not need to make any decisions: the compiler already made them.
- Loads a
.tgrsplan from flash (memory-mapped, no copy) - Walks the plan stage by stage, using a bump allocator over an arena you provide
- Handles tiled execution (spatial strips, chain streaming, temporal partitioning) transparently
- Pluggable kernel backends: pick one at link time
- About 5 KB of code on a typical Cortex-M build, zero heap allocation at runtime
The plan format is stable and versioned; the runtime refuses to load plans it does not understand.
Backends are swapped at link time. The compiler does not care which one you pick: plans are the same across all of them.
| Backend | Target | Source |
|---|---|---|
reference |
Any C99 | tigris_kernels.c |
s8_ref |
Any C99, int8 | tigris_kernels_s8.c |
esp-nn |
ESP32 family (SIMD on S3/P4, C fallbacks elsewhere) | tigris_kernels_esp_nn.c |
cmsis-nn |
Cortex-M family (DSP on M4/M7, Helium on M55, plain C elsewhere) | tigris_kernels_cmsis_nn.c |
You can also register your own kernel function and pass it to tigris_run; the runtime does not assume any particular kernel library.
The runtime works against a memory region you own. You pass in an SRAM buffer (always required) and optionally a PSRAM buffer; the plan decides which stages live where. Weights are either copied into the arena or read in place from flash (XIP), depending on how the plan was compiled.
+--------- SRAM arena ---------+ +------- PSRAM (optional) -------+
| activations (bump-allocated) | | spill buffers, large weights |
+------------------------------+ +--------------------------------+
|
+--- weights: copied here, or read in place from flash
No malloc, no free, no hidden allocations. The arena sizes are fixed at compile time and validated when the plan is loaded.
cmake -B build && cmake --build build
./build/test_kernels
./build/test_e2e test/fixtures/model 262144Generate test fixtures from an ONNX model using the compiler:
pip install tigris-ml
tigris gen-fixtures model.onnx -o test/fixtures/ -m 256KThe runtime ships as a standard ESP-IDF component. An example project lives under examples/esp32:
cd examples/esp32
idf.py set-target esp32s3
idf.py build && idf.py flashThe runtime is a single static library. Link it, pick a kernel backend, and call:
#include "tigris.h"
tigris_plan_t plan;
tigris_load(&plan, plan_data, plan_size);
tigris_mem_t mem;
tigris_mem_init(&mem, sram_buf, sram_size, psram_buf, psram_size);
tigris_run(&plan, &mem, input_data, output_ptrs, kernel_func, NULL);For most users this is wrapped by the C harness that tigris codegen produces. You only touch these APIs directly when you embed the runtime in a larger system with its own memory layout.
- Getting started: installation, first compile, deploying to ESP32
- Introducing TiGrIS: design, benchmarks, how tiling works
- Runtime API: header reference and memory model