Torq Runtime
The Torq runtime provides the means for loading and running compiled .vmfb models on a Torq device. It is built on top of IREE’s own runtime: the torq-runtime Python package wraps IREE’s Python bindings, and C/C++ applications use IREE’s public runtime API together with a Torq-specific IREE HAL driver. Pick the section below that matches your language.
Python API
The torq-runtime Python package provides bindings for loading and running compiled .vmfb models on a Torq device directly from Python.
Installation
torq-runtime is published on PyPI:
$ pip install torq-runtime
Quick Start
import numpy as np
from torq.runtime import VMFBInferenceRunner
# Load the compiled model
runner = VMFBInferenceRunner("mobilenetv2.vmfb", device_uri="torq")
# Prepare input data
input_data = np.random.randint(0, 255, size=(1, 224, 224, 3), dtype=np.int8)
# Run inference
outputs = runner.infer([input_data])
print(f"Inference took {runner.infer_time_ms:.2f} ms")
Examples
Inspecting Model Inputs and Outputs
from torq.runtime import VMFBInferenceRunner
runner = VMFBInferenceRunner("model.vmfb", device_uri="torq")
if runner.inputs_info:
for i, info in enumerate(runner.inputs_info):
print(f"Input {i}: dtype={info.dtype}, shape={info.shape}")
if runner.outputs_info:
for i, info in enumerate(runner.outputs_info):
print(f"Output {i}: dtype={info.dtype}, shape={info.shape}")
Profiling Inference Latency
from torq.runtime import profile_vmfb_inference_time
avg_ms = profile_vmfb_inference_time(
"model.vmfb",
n_iters=10,
do_warmup=True,
device="torq",
)
print(f"Average inference time: {avg_ms:.2f} ms")
Profiling System Resources
from torq.runtime import profile_vmfb_resources
stats = profile_vmfb_resources(
"model.vmfb",
n_iters=10,
do_warmup=True,
device="torq",
)
print(f"Average inference time: {stats.avg_inference_time_ms:.2f} ms")
print(f"Average DRAM footprint: {stats.avg_dram_footprint_bytes / 1024 / 1024:.1f} MB")
print(f"Peak DRAM footprint: {stats.peak_dram_footprint_bytes / 1024 / 1024:.1f} MB")
print(f"Average memory usage: {stats.avg_anon_mem_bytes / 1024 / 1024:.1f} MB")
print(f"Peak memory usage: {stats.peak_anon_mem_bytes / 1024 / 1024:.1f} MB")
print(f"Average CPU usage: {stats.avg_cpu_percent:.1f}%")
if stats.avg_npu_load_percent is not None:
print(f"Average NPU usage: {stats.avg_npu_load_percent:.1f}%")
Running with Custom Inputs
import numpy as np
from torq.runtime import VMFBInferenceRunner
runner = VMFBInferenceRunner("model.vmfb", device_uri="torq")
# Load preprocessed input from a .npy file
input_data = np.load("preprocessed_input.npy")
outputs = runner.infer([input_data])
Zero-Copy Device Outputs
When model outputs are fed back as inputs (e.g. KV-cache tensors in autoregressive decoding), use device_outputs=True to keep data on the device and avoid unnecessary host transfers:
import numpy as np
from torq.runtime import VMFBInferenceRunner
runner = VMFBInferenceRunner("model.vmfb", device_uri="torq", device_outputs=True)
# Allocate an initial on-device buffer (e.g. for a KV cache)
kv_cache = runner.allocate_device_array(np.zeros((1, 8, 256, 64), dtype=np.float16))
# Run inference — outputs stay on device as DeviceArray objects
results = runner.infer([input_data, kv_cache])
logits, new_kv = results[0], results[1]
# Use the output DeviceArray directly as next step's input
kv_cache = new_kv
# Only bring the logits to host for sampling
logits_np = logits.to_host()
API Reference
VMFBInferenceRunner
The main class for loading and running .vmfb models via the IREE runtime.
VMFBInferenceRunner(
model_path,
*,
function="main",
device_uri="torq",
n_threads=None,
load_method="preload",
load_model_to_mem=True,
runtime_flags=None,
device_outputs=False,
torq_hw_type="astra_machina",
)
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
(required) |
Path to the |
|
|
|
Exported function name inside the module. |
|
|
|
IREE device identifier. |
|
|
|
Worker thread count (only for llvm-cpu device). |
|
|
|
|
|
|
|
Whether to load the model into memory during initialization. |
|
|
|
Extra IREE runtime flags. |
|
|
|
If |
|
|
|
Torq HW backend for the |
Properties:
Property |
Type |
Description |
|---|---|---|
|
|
Path to the loaded model file. |
|
|
Elapsed time in milliseconds for the last call to |
|
|
The underlying IREE HAL device. |
|
|
Exported VMFB function names discovered after the module is loaded. Defaults to an empty list. |
|
|
Input tensor metadata extracted from the model, or |
|
|
Output tensor metadata extracted from the model, or |
Methods:
infer(inputs)
Run inference and return the output arrays.
inputs — Either an iterable of NumPy arrays (or
DeviceArrayobjects) or a mapping of name to array.Returns — A list of NumPy arrays by default. When
device_outputs=True, returns a list of on-deviceDeviceArrayobjects instead.
allocate_device_array(array)
Allocate a device buffer and copy a host NumPy array into it.
array — A NumPy array to upload to the device.
Returns — A
DeviceArraythat can be passed directly toinfer()without further copies.
profile_vmfb_inference_time
Load or reuse a .vmfb model and run inference multiple times for profiling.
profile_vmfb_inference_time(
model_path,
inputs=None,
*,
n_iters=5,
do_warmup=True,
function="main",
device="torq",
n_threads=None,
load_model_to_mem=True,
runtime_flags=None,
device_io=False,
)
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
(required) |
Path to the |
|
|
|
Input arrays. Generated randomly from model metadata when |
|
|
|
Number of timed inference iterations. |
|
|
|
Whether to run one untimed warmup pass first. |
|
|
|
Exported function name inside the module. |
|
|
|
IREE device URI. |
|
|
|
Worker thread count (only for llvm-cpu device). |
|
|
|
|
|
|
|
Whether to load the model into memory during initialization. |
|
|
|
Extra IREE runtime flags. |
|
|
|
Exclude some host copies from profiling by using iree DeviceArray objects for I/O. |
Returns: Average wall-clock inference time in milliseconds.
profile_vmfb_resources
Load or reuse a .vmfb model and run inference multiple times, collecting DRAM, CPU, and Torq NPU statistics alongside timing. Requires a Linux target for process statistics (reads from /proc). NPU load is reported when /sys/class/misc/torq/statistics/torq_inference_time is available.
from torq.runtime import profile_vmfb_resources
profile_vmfb_resources(
model_path,
inputs=None,
*,
n_iters=5,
do_warmup=True,
function="main",
device="torq",
n_threads=None,
load_method="preload",
load_model_to_mem=True,
runtime_flags=None,
device_io=False,
)
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
(required) |
Path to the |
|
|
|
Input arrays. Generated randomly from model metadata when |
|
|
|
Number of timed inference iterations. |
|
|
|
Whether to run one untimed warmup pass first. |
|
|
|
Exported function name inside the module. |
|
|
|
IREE device URI. |
|
|
|
Worker thread count (only for llvm-cpu device). |
|
|
|
|
|
|
|
Whether to load the model into memory during initialization. |
|
|
|
Extra IREE runtime flags. |
|
|
|
Exclude some host copies from profiling by using iree DeviceArray objects for I/O. |
Returns: A ProfileStats dataclass (see below).
ProfileStats
Dataclass returned by profile_vmfb_resources containing profiling results. All resource metrics are process-wide and include overhead from the Python interpreter, the sampling thread, and any other activity in the process.
from torq.runtime.profiling import ProfileStats
Field |
Type |
Description |
|---|---|---|
|
|
Average wall-clock inference time in milliseconds. |
|
|
Average total DRAM footprint in bytes, including file-backed pages (e.g. mmap’d model data). |
|
|
Peak total DRAM footprint in bytes. |
|
|
Average anonymous memory (heap/stack) in bytes, excluding file-backed pages. |
|
|
Peak anonymous memory in bytes. |
|
|
Average CPU utilisation as a percentage (across all cores) during timed iterations. |
|
|
Torq NPU execution time accumulated during timed iterations, or |
|
|
Average Torq NPU utilisation during timed iterations, or |
Methods:
summary()
Return a human-readable summary string with formatted values (times in ms, memory in MB, CPU as a percentage).
stats = profile_vmfb_resources("model.vmfb")
print(stats.summary())
# Avg inference time: 12.345 ms
#
# Process-wide resource usage (includes Python overhead):
# Avg DRAM footprint: 85.2 MB (includes mmap'd model file)
# Peak DRAM footprint: 91.7 MB
# Avg memory usage: 23.4 MB (heap/stack only, excludes model file)
# Peak memory usage: 28.1 MB
# Avg CPU usage: 47.3%
# Avg NPU usage: 82.4%
ResourceSampler
A reusable background sampler for collecting process-wide DRAM and CPU metrics plus optional Torq NPU load around arbitrary workloads. Used internally by profile_vmfb_resources but available for custom profiling scenarios.
from torq.runtime.profiling import ResourceSampler
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
(required) |
Process ID to monitor. |
|
|
|
Sampling interval in seconds. |
|
|
Torq sysfs path |
Path to the Torq cumulative NPU inference-time counter, or |
Properties (available after stop()):
Property |
Type |
Description |
|---|---|---|
|
|
Average total RSS (DRAM footprint) in bytes. |
|
|
Peak total RSS in bytes. |
|
|
Average anonymous RSS in bytes. |
|
|
Peak anonymous RSS in bytes. |
|
|
Average CPU utilisation percentage. |
|
|
Torq NPU execution time accumulated while the sampler was running, or |
|
|
Average Torq NPU utilisation while the sampler was running, or |
run_vmfb
Run a .vmfb model via the iree-run-module CLI and return wall-clock time.
run_vmfb(
model_path,
inputs,
outputs,
device="torq",
n_threads=None,
iree_binary=None,
)
Parameters:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
(required) |
Path to the |
|
|
(required) |
Input descriptors forwarded as |
|
|
(required) |
Output descriptors forwarded as |
|
|
|
IREE device URI. |
|
|
|
Worker thread count (only for llvm-cpu device, defaults to |
|
|
|
Path to the |
Returns: Elapsed wall-clock time in milliseconds.
TensorInfo
Dataclass holding dtype and shape metadata for a tensor.
@dataclass
class TensorInfo:
dtype: DTypeLike
shape: list[int | str]
Field |
Type |
Description |
|---|---|---|
|
|
NumPy-compatible dtype. |
|
|
Tensor dimensions. |
Methods:
is_valid()— ReturnsTrueif every dimension is an integer (i.e., no dynamic dimensions).
Utility Functions
random_inputs_from_info(inputs_info)
Generate random NumPy arrays matching the given tensor metadata. Useful for testing.
inputs_info — Iterable of
TensorInfo.Returns — List of NumPy arrays with appropriate shapes and dtypes.
C/C++ API
There is no separate Torq-specific application API for C/C++. Instead, C/C++ programs use IREE’s own public runtime API (iree_runtime_session_t, iree_hal_device_t, etc.) and simply request the torq HAL driver by name — the same driver that the Python torq.runtime package requests via device_uri="torq". Torq supplies:
An IREE HAL driver/device plugin (
runtime/driver/) that implements thetorqdevice, registered as an IREE “external HAL driver”.A hardware/simulator backend (
runtime/torq_hw/), selected with the--torq_hw_typeflag.The
torq-run-moduleCLI tool (runtime/tools/torq-run-module-main.cpp), a Torq-flavored fork of IREE’s owniree-run-module.
Building with the Torq Driver
Enable the driver when configuring the runtime build:
cmake -DIREE_EXTERNAL_HAL_DRIVERS=torq ...
Any binary that links the driver::registration target (as torq-run-module does) gets the torq driver registered into IREE’s standard driver registry automatically — no explicit call to iree_hal_torq_driver_module_register() is needed in application code as long as the instance is created with iree_runtime_instance_options_use_all_available_drivers().
Quick Start
Running a Model via the CLI
The quickest way to run a .vmfb without writing any code is the torq-run-module tool built alongside the runtime:
torq-run-module \
--module=mobilenetv2.vmfb \
--device=torq \
--input=1x224x224x3xsi8=@input.bin
Embedding the Runtime
Applications that embed the runtime directly use IREE’s high-level iree_runtime_session_t API and request the "torq" device by name:
#include "iree/runtime/api.h"
iree_status_t run_inference(const char* vmfb_path) {
// Shared across all sessions. Enumerates every driver linked into the
// binary, including "torq" once the runtime is built with
// -DIREE_EXTERNAL_HAL_DRIVERS=torq.
iree_runtime_instance_options_t instance_options;
iree_runtime_instance_options_initialize(&instance_options);
iree_runtime_instance_options_use_all_available_drivers(&instance_options);
iree_runtime_instance_t* instance = NULL;
IREE_RETURN_IF_ERROR(iree_runtime_instance_create(
&instance_options, iree_allocator_system(), &instance));
// Equivalent of VMFBInferenceRunner(..., device_uri="torq").
iree_hal_device_t* device = NULL;
IREE_RETURN_IF_ERROR(iree_runtime_instance_try_create_default_device(
instance, iree_make_cstring_view("torq"), &device));
iree_runtime_session_options_t session_options;
iree_runtime_session_options_initialize(&session_options);
iree_runtime_session_t* session = NULL;
IREE_RETURN_IF_ERROR(iree_runtime_session_create_with_device(
instance, &session_options, device,
iree_runtime_instance_host_allocator(instance), &session));
iree_hal_device_release(device);
// Equivalent of VMFBInferenceRunner(vmfb_path, ...).
IREE_RETURN_IF_ERROR(iree_runtime_session_append_bytecode_module_from_file(
session, vmfb_path));
// Equivalent of runner.infer([input_array]). The function name uses the
// "<module_name>.<function_name>" form, matching the exported name in the
// compiled module (compare to `function="main"` in VMFBInferenceRunner).
iree_runtime_call_t call;
IREE_RETURN_IF_ERROR(iree_runtime_call_initialize_by_name(
session, iree_make_cstring_view("module.main"), &call));
iree_hal_buffer_view_t* input = NULL;
// ... allocate/populate `input`, e.g. with
// iree_hal_buffer_view_allocate_buffer_copy() ...
IREE_RETURN_IF_ERROR(
iree_runtime_call_inputs_push_back_buffer_view(&call, input));
iree_hal_buffer_view_release(input);
IREE_RETURN_IF_ERROR(iree_runtime_call_invoke(&call, /*flags=*/0));
iree_hal_buffer_view_t* output = NULL;
IREE_RETURN_IF_ERROR(
iree_runtime_call_outputs_pop_front_buffer_view(&call, &output));
// ... read `output` back to host, e.g. with iree_hal_device_transfer_d2h() ...
iree_hal_buffer_view_release(output);
iree_runtime_call_deinitialize(&call);
iree_runtime_session_release(session);
iree_runtime_instance_release(instance);
return iree_ok_status();
}
See IREE’s own hello_world_terse.c demo for a complete, runnable version of this pattern, and runtime/tools/torq-run-module-main.cpp in this repository for how torq-run-module drives the same device through IREE’s iree_tooling_run_module_from_flags() helper instead of hand-written session code.
Device Selection
Hardware backend and allocator selection are exposed as process-wide IREE flags rather than constructor parameters:
Flag |
Default |
Description |
|---|---|---|
|
|
Torq hardware/simulator backend: |
|
|
Buffer allocator backing the |
Set them on the command line (as with torq-run-module --torq_hw_type=sim ...), via a flags file, or by calling IREE’s iree_flags_parse_checked() yourself before creating the device.
Profiling
There is no C/C++ equivalent of infer_time_ms, profile_vmfb_inference_time, or profile_vmfb_resources. To reproduce the same measurements in C/C++:
Inference latency — time the call yourself around
iree_runtime_call_invoke()(e.g. withiree_time_now()orstd::chrono), the same wayinfer_time_msis computed aroundinfer()in Python.NPU/CPU/DRAM usage — the raw sources the Python
ResourceSamplerreads are available directly on Linux: process-wide CPU/DRAM from/proc/<pid>/statand/proc/<pid>/smaps_rollup, and cumulative Torq NPU execution time from/sys/class/misc/torq/statistics/torq_inference_time. The runtime does not provide a reusable C/C++ helper for this; an application needs to read these itself around the inference call.
Public Headers
Header |
Contents |
|---|---|
|
|
|
|
|
|
For everything else — sessions, calls, buffer views, modules — use IREE’s own public headers: iree/runtime/api.h, iree/hal/api.h, and iree/vm/api.h.