Your first graph
This page walks through examples/matrix-compute, the canonical starter
example: an FFT + matrix-multiply pipeline with a Rust plugin. The topology
is a linear chain with one fan-out and one fan-in:
gen_vec(buf_size) ─────────────────────────────────► vec_to_mat
└─► fft_planner ─► compute_fft ──► vec_to_mat
└─► mat_mul ─► write_res
The builder code
This is the graph definition from
examples/matrix-compute/run_bench.py, trimmed to the essentials:
import tomii as tm
app = tm.Graph()
# Initializations — computed once, before any frame runs
buf_size = app.var("buf_size", 100)
num_nodes = app.var("num_nodes", 200)
fft_planner = app.var("fft_planner", func="fft_planner", args=[buf_size])
result_file = app.var("result_file", func="get_out_file",
args=[tm.String("SCRIPT_DIR"), tm.String("result.txt")])
# Pipeline — factor=num_nodes creates 200 parallel instances of each node
gen_vec = app.node("gen_vec", func="generate_vector",
factor=num_nodes, args=[buf_size])
compute_fft = app.node("compute_fft", func="compute_fft",
factor=num_nodes, args=[fft_planner, gen_vec.out()])
vec_mat = app.node("vec_mat", func="vec_to_mat",
factor=num_nodes, args=[gen_vec.out(), compute_fft.wait()])
mat_mul = app.node("mat_mul", func="mat_mul",
factor=num_nodes, args=[vec_mat.out(), vec_mat.out()])
app.node("write_res", func="write_to_file",
args=[result_file, mat_mul.out(end=num_nodes)])
app.build(func_path="examples/matrix-compute/src/lib.rs",
plugin_manifest="examples/matrix-compute/Cargo.toml")
app.run(workers=4, slots=2, timing="timing.csv")
Line by line:
app.var("buf_size", 100)defines a constant.app.var("fft_planner", func=..., args=...)defines a computed initialization: the plugin functionfft_plannerruns once at startup and its result is shared by everycompute_fftinstance.func="generate_vector"names a plugin function. The graph never contains kernel code — only function names. The kernels live inexamples/matrix-compute/src/lib.rs, annotated with#[tomii_export](see Rust plugins).factor=num_nodescreates 200 instances of each node per frame. Instanceiofcompute_fftdepends on instanceiofgen_vec.gen_vec.out()is a data dependency: instanceireceives the result ofgen_vec[i].compute_fft.wait()is a barrier:vec_mat[i]waits forcompute_fft[i]to finish but does not consume its result. The barrier is needed becausecompute_fftmutates the vector in place.mat_mul.out(end=num_nodes)is a fan-in:write_resreceives all 200mat_mulresults as one variadic argument.
The JSON it emits
app.to_json() produces the same file as
examples/matrix-compute/graph.json. One node, as emitted:
{
"name": "vec_mat",
"factor": "num_nodes",
"function": "vec_to_mat",
"args": [
{ "type": "$res", "predecessor": { "name": "gen_vec", "indexes": "0" } },
{ "type": "$barrier", "predecessor": { "name": "compute_fft", "indexes": "0" } }
]
}
.out() became $res, .wait() became $barrier, and the Var reference
became a $ref. The full mapping is in the
JSON graph format reference.
Build and run
From the repository root:
python examples/matrix-compute/run_bench.py --workers 4 --slots 8 --max-frames 100
The first run compiles libmatcomp.so and regenerates the function registry;
subsequent runs with --no-clean skip the rebuild
(examples/matrix-compute/README.md). build() compiles the plugin from the
annotated Rust source; run() writes the graph JSON to a temp file and
launches the runtime binary.
Verify the output
bash examples/matrix-compute/verify.sh
This builds the perfval binary, cross-checks the matrix output against a
NumPy reference, and prints PASS on success. Per-element error statistics
go to validation.txt (examples/matrix-compute/README.md).
Next
- Running graphs — what
workers,slots, and the otherrun()options mean. - Nodes and variables — the builder API in full.
- Rust plugins — how the kernel side works.