BKPT LabsDOCS/VIEWALYZER CLI/QUERIES VIEWALYZER · HEADLESS CLI
VIEWALYZER · CLI & AUTOMATION

Queries

query <verb> --recording <id|path> prints one JSON object shaped for a consumer, from a recording on disk. Every response carries schema_version, recording_id and query (most also carry path and budget); times are microseconds since the recording start; tasks are referenced by a compact code (T1, T2) defined in the response's task_legend, channels by C1, C2 in trace_legend.

The machine-readable schema catalog is JSON Schema draft 2020-12 and has one named schema per verb at #/$defs/<verb>. The shapes below are not inferred from examples: they are the documented schema_version: 2 contract.

$ viewalyzer-cli query summary --recording run.vadb
{"schema_version":2,"recording_id":"328d49aa4eb6","query":"summary","budget":"med","duration_us":5111531,"span_seconds":5.11,"cpu_freq_hz":170000000.0,"os":"BareMetal","total_events":21930,"context_switches":14679,"cpu_load_percent":0.27,"total_tasks":1,"lost_events":0,"corrupt_bytes":0,"pre_sync":{"lost_events":0,"corrupt_bytes":21,"corrupt_runs":1,"seq_gaps":0},"execution_ended_abnormally":false,"ended_abnormally":null,"execution_end":{"t_us":5111531,"task":"main","last_event":{"kind":"task_switch","object":"main"}},"capture_utc":"2026-08-29T08:29:39Z"}

Tiers and budgets

Three verbs (timeline, events, user-traces) come in three tiers, so a consumer never pulls a payload it cannot handle:

--TIER NEEDS RETURNS
summary (default)nothingwhole-recording statistics
bucketed--t-start-us, --t-end-us, --bucket-usone value per bucket over the window
raw--t-start-us, --t-end-usthe individual rows in the window

--budget low|med|high scales the caps (rows 200 / 1000 / 5000, buckets 64 / 256 / 1024, serialized size 12 / 48 / 200 KB). A window that exceeds a cap does not truncate silently: it answers window_too_wide with a suggestion (a narrower t_end_us, a wider bucket, a --kinds or --channels filter, or a higher budget). The -all verbs (slices, slice-details, events-all, user-traces-all) are unbounded, for consumers that manage payload size themselves (--max-slices n).

$ viewalyzer-cli query user-traces --recording run.vadb --tier raw --t-start-us 1000000 --t-end-us 1010000 --channels "Sine Wave"
{"schema_version":2,"query":"user-traces","tier":"raw","t_start_us":1000000,"t_end_us":1010000,
 "trace_legend":{"C1":{"name":"Sine Wave","va_id":42,"display":"graph","ns":"user_trace"}},
 "sample_fields":["channel_code","t_us","value"],
 "samples":[["C1",1000239,88.0],["C1",1002370,83.0],["C1",1004502,77.0],["C1",1006632,71.0],["C1",1008768,63.0]]}

The verbs

VERB PAYLOAD
summaryWhole-recording scalars plus execution_ended_abnormally (boolean), ended_abnormally (fault/stack-trap time, task, and last event; otherwise null), execution_end (last event and task), recording integrity, and separate pre_sync acquisition counters
timelinePer-lane cards: cpu_percent, slice_count, mean/p50/p95/p99/max slice, preemptions, observed period p50/p95, max_jitter_us, anomalies[]; bucketed: per-lane CPU% per bucket; raw: slices: [[task_code, t_start_us, dur_us], ...]
eventsCounts by_kind and top_objects (--kinds filters); bucketed: kind counts per bucket; raw: {t_us, kind, start_end, code|obj, value_i, value_f, text}
user-tracesPer channel {count, min, max, mean, last, rms, std_dev, rate_hz, min_at_us, max_at_us} (--channels by name or code); bucketed: [{min,max,mean,count} | null] per bucket; raw: samples: [[channel_code, t_us, value], ...]
cpuTop-level CPU model fields (there is intentionally no cpu wrapper): busy_pct, idle_pct, min and max load with their times over a sliding window, context_switches, preemptions, tasks[] (execution percentiles net of preemption, period and outliers, blocked time, inversions, sync and failed ops, stack), findings[]; --t-start-us/--t-end-us scope everything
inversionsscope is mutexes_only; every mutex contention has type (inversion when the waiter outranks the holder, OS-aware), waiter/holder priorities and times. Semaphore events do not identify an owner, so semaphore inversion is not inferred
verdictsUnified verdicts[] from native CPU/fatal-end detectors and optional Trace Domain rules. detectors.native and detectors.trace_domains report status and finding counts; domain status distinguishes no_descriptors, all_disabled, no_rules, and ready
timersPer kernel timer: measured fires, predicted fires, arms and stops, phase-corrected lateness (mean/p99/max_lat_us), violations against --threshold-us (500), a 12-bin histogram, callback duration and callback_mean_evidence (measured, estimated, mixed, unknown); work[] k_work lanes. Raw: fire_records[] with callback evidence, event IDs and a cause on violations; measured stop_callbacks[]
commspaths[] (producer>via>consumer: kind, count, rate, median/p99/max latency, blocked) and resources[] (sends, receives, matched, still pending, empty receives, contentions, peak pending); with --bucket-us a per-resource backlog series. ipc[] adds queue/notification/flag values at the window end and recording_totals (including full/empty time)
task-statesObserved task states and priority history; completed ready/blocked/sleeping/suspended times and wake-to-run latency. --task-id N filters by recording actor ID. Raw adds states[] and priority_history[]
resourcesQueue occupancy, indexed notification values, event flags, stream/message buffers, memory slabs, condition variables and poll resources. Raw adds observed value history[]; --resource-id N selects one actor
queue-failuresIndividual send/receive/peek failures with resource ID, event ID, task/ISR and observed occupancy; --resource-id N filters without combining same-named queues
semaphoresStructured give/take/failure counts, completed/incomplete waits, median/P99/max blocking duration and relative outliers. Raw adds waits[]; --resource-id N selects one semaphore
series--kind cpu-load (total plus per-lane bands), event-rate, stack, heap (with failed_allocs_us and capacity), task-timing --task n --metric exec|period, interval --from task:a|trace:a|resource:a --to .... Compact curves use fields + values; stack additionally has canonical object rows stack: [{t_us,total_stack_used_bytes}]
sql--sql "SELECT ...": read-only, one statement, rows capped by budget, BLOBs as "<blob N bytes>"
fingerprint, compareGolden-run regression testing; compare result values are named current (candidate recording) and baseline (fingerprint/envelope). Exit 0 pass/warn, 2 regression, 1 command/input error; see Regression tests in CI
$ viewalyzer-cli query cpu --recording run.vadb
{"schema_version":2,"query":"cpu","window":{"t_start_us":0,"t_end_us":5111531,"scoped":false},"busy_pct":0.27,"idle_pct":99.73,"min_load_pct":0.27,"max_load_pct":0.27,"sweep_window_us":500000,"context_switches":0,"preemptions":0,
 "tasks":[{"name":"ISR:SysTick","kind":"isr","cpu_pct":0.27,"runs":5111,"mean_us":2.74,"p50_us":2.75,"p99_us":2.77,"max_us":2.87,"period_p50_us":1000.0,"period_p95_us":1000.1,"outliers":0,"preempt_count":0,"blocked":0,"inversions":0}],"findings":[]}

$ viewalyzer-cli query series --recording run.vadb --kind cpu-load --bucket-us 500000
{"schema_version":2,"query":"series","kind":"cpu-load","window_us":500000,"points":256,"fields":["t_us","load_pct"],"total":[[0,0.0],[19967,0.28],[39934,0.27], ...]}

RTOS states and IPC evidence

viewalyzer-cli query task-states --recording run.vadb --tier raw --task-id 1
viewalyzer-cli query resources --recording run.vadb --tier raw --resource-id 3 --t-start-us 100000 --t-end-us 200000
viewalyzer-cli query queue-failures --recording run.vadb --resource-id 3
viewalyzer-cli query semaphores --recording run.vadb --tier raw
viewalyzer-cli query timers --recording run.vadb --tier raw

The IDs above are examples: take task_id or resource_id from the query's unfiltered response. These are recording actor IDs, not recorder wire IDs or names. Two resources can have the same name. A filter that matches no actor returns an empty list. The --headless --query <verb> form works too.

task-states, resources and semaphores support summary (default) and raw. Raw may cover the whole recording; a time window is optional. bucketed is rejected for these verbs. queue-failures always returns individual events. All four accept --t-start-us, --t-end-us and --budget. New timestamps and durations are in microseconds relative to recording start, including recordings whose device clock starts at a nonzero value.

  • Task states: state_events_recorded: false means no recorded state history; empty state arrays and zero completed totals do not establish how the task spent unknown time. Raw intervals are clipped to the window, with complete: false if they cross the selection, event loss or capture end. Only whole, completed intervals contribute to completed_time_us and wake-to-run metrics. priority_at_start carries the last observed priority before the window; priority_history contains changes inside it. Missing priorities stay null. recording_ipc_totals explicitly covers the whole recording.
  • Resources: initial_value is the observed value at the window start; value at at_us is the observed value at its end. Raw history contains observations and loss markers inside the window. A null value means unknown, including after loss until another observation. Queue values are used slots, slab values are used blocks, and notification/flag values are bitfields. Stream-buffer transfer bytes do not establish occupancy. recording_totals always covers the whole recording. The existing comms.ipc fields retain their original at_ns/duration-in-nanoseconds names for compatibility.
  • Queue failures: total counts matching detail events in the selected window, before row limits. With no window it matches the resource failure count. Legacy duplicate events and deferred requests are excluded. An ISR row has exception set and null task_id/task; it is not attributed to the interrupted task. used and capacity can be null. A failed operation alone cannot distinguish an expected nonblocking poll from a timeout. Older captures without queue-detail events have no exact failure list.
  • Semaphores: operation counts and waits cover the selected window. Incomplete waits remain visible with null duration_us, and do not affect median/P99/max. Blocking ends at ready/running, before any later scheduling delay. With at least ten complete waits, outliers exceed four times the median with a 1 ms floor; otherwise outlier_threshold_us is null. These observations do not establish ownership or actual token count. The same findings appear in cpu/verdicts, and verdicts.detectors.native.kinds includes semaphore.
  • Timers: measured_callbacks means explicit callback tracing was observed; it does not guarantee every exit arrived. Per-fire callback_traced identifies an explicit entry, and callback_evidence is measured, estimated, or unknown. A missing traced exit stays unknown with no cb_end_us. callback_mean_evidence describes the durations contributing to the existing cb_mean_us, including mixed if both measured and estimated samples occur. Raw stop_callbacks contains completed, measured start/end/duration records.

The existing slice-details query adds an rtos object with priority at the slice, its previous recorded wait (including completeness), and explicitly named recording_state_totals and recording_ipc_totals. Existing slice fields and compact slices/timeline arrays remain unchanged.

Responses retain schema version 2. Item lists obey the budget's item cap; raw histories share one row allowance across the new query response. Check every *_truncated/truncated flag. If a history is truncated, narrow the window or filter to one actor before interpreting its end. The byte cap can still return window_too_wide; a cap never silently establishes a complete history. No replay metric names or HIL pass/fail thresholds change.

SQL

When no verb shapes the data the way you need, sql runs one read-only statement against the recording's tables (The .vadb file):

va_events.text contains event payload text only; it does not duplicate object names. Resolve names with va_events.obj -> va_objects.id, for example select e.*, o.name as obj_name from va_events e left join va_objects o on o.id = e.obj.

$ viewalyzer-cli query sql --recording run.vadb --sql "select kind, count(*) as n from va_events group by kind order by n desc limit 5"
{"schema_version":2,"query":"sql","columns":["kind","n"],"rows":[["user_event",19136],["isr",10222],["user_trace",7176],["user_toggle",75],["string",5]],"row_count":5,"truncated":false}

Hardware-trace queries

Present when the recording was captured with hardware trace (--dwt ... or the hardware-trace block on an SWO transport, or DWT_PCSR polling on the others); no_hw_trace otherwise.

VERB DATA
profile [--elf f]PC-sample hotspots: total_samples, sleep_samples, span_s, sample_rate_hz, hotspots[] of {symbol, addr, samples, pct, file, line, isr} (symbolicated with --elf), source (dwt-swo or pcsr-poll), interval_cycles, sleep_pct, outside_elf_pct
itm-console [--port N]ports[] of {port, lines: [{t_us, text}], bytes}; lines split on newline, an unterminated tail is marked partial; --port keeps one port
dwt-datawatches[] of {cmp, name, address, function, count, first: [{t_us, value, rw, pc?, symbol?, file?, line?}]} (up to 256 samples each; --elf symbolicates the PCs)
dwt-exctotal, max_depth, exceptions[] of {num, name, enter, exit, return, max_depth}, events[] of {t_us, num, func, depth} (up to 4096)
dwt-counterscounters.{cpi,exc,sleep,lsu,fold,cyc} = {wraps, cycles, rate_per_s}, span_s, cpu_load_pct (from the sleep counter, null without it), overflows, reliable
swo-load{bytes, seconds, bytes_per_s, swo_hz, share_pct, overflows} for the whole capture

irq, etm and target-caps are reserved and error naming the reason (no_hw_trace, etm_not_present, bad_arguments).

load and export

load prints a recording's summary (recording.{duration_us, os, total_events, lanes_detail[], channels_detail[], lost_events, ...}) and converts or exports:

$ viewalyzer-cli load run.va --output run.vadb                              # a byte-log or raw wire dump into a .vadb
$ viewalyzer-cli load run.vadb --export traces --format csv --out -         # events | traces | spans | tasks | channels
t_us,channel,va_id,value
6,Sine Wave,42,0
9,Tick Counter,43,0
11,Workload,46,0

replay run.vadb [--perf] re-parses a recording and prints [metric] category,name,value,unit lines (info, data, per-lane task.slices and task.cpu, per-channel trace, flow, result,status), the surface the HIL bench parses; --perf adds pipeline timings. Exit 0 when the recording carries task slices or user traces, 1 otherwise.