Skip to main content

JSON graph format

Tomii executes graphs defined in JSON. The Python API generates this format for you (Graph.to_json), but you can also write it by hand. The source of truth for the format is the serde structs in tomii-core/src/json_structs.rs; this page documents every field they define. python -m tomii --schema prints a machine-readable schema for graph construction.

Top-level structure

{
"initializations": [ ... ],
"nodes": [ ... ],
"post_nodes": [ ... ],
"network_config": { ... }
}
FieldRequiredDescription
initializationsno (defaults to empty)Objects computed once before execution
nodesyesComputation nodes
post_nodesnoNodes run in the post-computation phase
network_confignoNetwork receiver configuration

Initializations

Each entry in initializations defines a named object that exists before any node runs. Nodes reference these objects by name with $ref arguments, and factor fields can reference them as counts.

FieldRequiredTypeDescription
nameyesstringUnique name
factornofactorNumber of instances
argsyesarrayTyped values: {"type": ..., "value": ...} (both fields required)
functionnostringPlugin function that computes the object from args

Without function, the single arg is parsed as a literal typed value. With function, the plugin function is called at init time with args:

{
"name": "buf_size",
"args": [ { "type": "usize", "value": "100" } ]
},
{
"name": "fft_planner",
"function": "fft_planner",
"args": [ { "type": "$ref", "value": "buf_size" } ]
}

(from examples/matrix-compute/graph.json)

Two names are reserved and resolved at runtime rather than defined by you: $index (the instance index of the consuming node) and $workers (the worker count). Use them as $ref values, e.g. {"type": "$ref", "value": "$index"}.

Nodes

Each entry in nodes (and post_nodes) defines a task.

FieldRequiredTypeDescription
nameyesstringUnique name
functionyesstringPlugin function to execute
argsyesarrayArguments passed to the function
factornofactorNumber of parallel instances
loopnoobject{"name": string, "factor": factor?} — loop configuration
loop_argsnoarrayArguments for the loop
group_sizenofactorInstances grouped into one task
conditionnoobjectNode-level condition
prioritynostring"high", "normal" (default), or "low"
use_workersnostringWorker index range "start-end", inclusive on both ends ("0-7" = workers 0 through 7)

A node with factor creates that many parallel instances of the task, each with its own instance index. See nodes and vars.

Arguments

Each element of args is an object with a type and, depending on the type, a value or a predecessor:

FieldRequiredDescription
typeyesType string (see below)
valuenoLiteral value or referenced name
predecessornoPredecessor object for dependency types
conditionnoArg-level guard: {"operation", "value", "value_type"}

Argument types

typeUsesMeaning
$refvalueReference to an initialization object
$respredecessorData dependency: consume a predecessor's result
$deppredecessorOrdering-only dependency: wait, but do not fetch the result
$barrierpredecessorWait for the selected predecessor instances to complete
literal typevalueConstant parsed from the string, e.g. {"type": "usize", "value": "100"}

Literal types accepted: bool, char, i8i128, u8u128, usize, isize, f32, f64, String, Complex32, Complex64, and Vec<T> where T is any of the scalar types (the value is a comma-separated list). Complex values accept "3.5+2.5i", "3.5,2.5", or "{\"re\":3.5,\"im\":2.5}". The full runtime type system is described in types.

Network input is consumed by naming the virtual node $network as a predecessor, not by a distinct argument type:

{
"type": "$res",
"predecessor": { "name": "$network", "indexes": "0" }
}

(from the MIMO benchmark graph generated by bench/mimo-bench/tomii/build_graph.py; the $network node exists when network_config is present)

Predecessor objects

FieldRequiredTypeDescription
nameyesstringPredecessor node name (or $network)
indexesyesstringInstance selection (see below)
group_bynofactorGroup this many predecessor completions before firing one successor

indexes selects which predecessor instances the consuming instance depends on, as relative instance offsets: 0 means the same index, -1 the previous. Three syntaxes are accepted:

SyntaxExampleMeaning
single"0"One offset; also accepts an init name that resolves to a number
comma list"0,1,2"Exact list of offsets
range"0-5", "0-num_nodes"Contiguous range of offsets

In a range, each endpoint may be a number or an init name. A numeric end is inclusive: "0-5" selects offsets 0 through 5. A named end resolves to the variable's value and is exclusive: "0-num_nodes" with num_nodes = 200 selects offsets 0 through 199. This matters for barriers that fan in over all instances of a factor node:

{
"name": "write_res",
"function": "write_to_file",
"args": [
{ "type": "$ref", "value": "result_file" },
{
"type": "$res",
"predecessor": { "name": "mat_mul", "indexes": "0-num_nodes" }
}
]
}

(from examples/matrix-compute/graph.json)

With group_by, a barrier over N predecessor instances fires the successor once per group of group_by completions instead of once for all N. See control flow.

Factor

A factor is either a literal integer or a string naming an initialization object that holds a number:

"factor": 200
"factor": "num_nodes"

The reserved name "$workers" resolves to the worker count. Factors appear on nodes, initializations, loops, group_size, group_by, and several network_config fields.

Conditions

A node-level condition gates execution: the node's function runs only if the condition holds, evaluated by calling a plugin function.

FieldRequiredDescription
operationyesComparison, e.g. "Eq", "Neq"
valueyesComparison value as a string
value_typeyesRust type of value, e.g. "bool"
functionyesPlugin function returning the value to compare
argsyesArguments passed to function
"condition": {
"operation": "Eq",
"value": "false",
"value_type": "bool",
"function": "is_pilot",
"args": [
{ "type": "$res", "predecessor": { "name": "$network", "indexes": "0" } },
{ "type": "$ref", "value": "framestats" },
{ "type": "$ref", "value": "$index" }
]
}

(from the MIMO benchmark graph generated by bench/mimo-bench/tomii/build_graph.py)

The arg-level condition (inside an argument object) is a guard with only operation, value, and value_type — the argument is used only if the guard holds.

network_config

Present only for graphs that ingest packets from the network. Dedicated receiver threads (--receiver-threads) own the sockets and inject data as the virtual $network node's results. See network sources.

FieldRequiredTypeDescription
socket_typeyesstringOnly "udp" is currently supported
num_socketsyesfactorNumber of receive sockets
packet_lengthyesfactorPacket size in bytes
frame_packetsyesfactorPackets per frame (legacy spelling stream_packets still accepted)
buffer_depthno (default 128)integerReceive buffer depth
addressyesstringBind address, literal or the name of a String init object
start_portyesfactorFirst port; socket i binds start_port + i
extract_packet_funcyesstringPlugin function that extracts payload from a packet
id_functionyesstringPlugin function that maps a packet to its frame id
index_functionyesobject{"function": string, "args": [...]} — maps a packet to a $network instance index
"network_config": {
"socket_type": "udp",
"num_sockets": "antennas",
"packet_length": "packet_length",
"frame_packets": "packets_per_frame",
"buffer_depth": 2000,
"address": "server_address",
"start_port": "base_port",
"extract_packet_func": "process_packet",
"id_function": "get_frame_id"
}

(from the MIMO benchmark graph generated by bench/mimo-bench/tomii/build_graph.py; index_function is required by the current json_structs.rs and must be added to graphs written against older versions)

Complete example

examples/matrix-compute/graph.json, trimmed to two nodes:

{
"initializations": [
{ "name": "buf_size", "args": [ { "type": "usize", "value": "100" } ] },
{ "name": "num_nodes", "args": [ { "type": "usize", "value": "200" } ] },
{
"name": "fft_planner",
"function": "fft_planner",
"args": [ { "type": "$ref", "value": "buf_size" } ]
}
],
"nodes": [
{
"name": "gen_vec",
"factor": "num_nodes",
"function": "generate_vector",
"args": [ { "type": "$ref", "value": "buf_size" } ]
},
{
"name": "compute_fft",
"factor": "num_nodes",
"function": "compute_fft",
"args": [
{ "type": "$ref", "value": "fft_planner" },
{
"type": "$res",
"predecessor": { "name": "gen_vec", "indexes": "0" }
}
]
}
]
}

Each of the 200 compute_fft instances depends on the gen_vec instance at offset 0 from its own index — a 1:1 edge. More examples are collected in examples.