The .vadb file
One SQLite file per recording, the same schema the app, the CLI queries and the Python SDK read. When a query does not shape the data the way you need, open the file: query sql runs one read-only statement, the SDK's Recording.connect() hands you a read-only connection, and any SQLite client works.
Tables
| TABLE | COLUMNS | HOLDS |
|---|---|---|
meta | key, value | format, version, capture_source, capture_utc, va_cpu_hz, va_os, recorder_version, and the hardware-trace keys below |
va_objects | id, ns, va_id, name, extra | Everything that has a name: tasks and ISRs, sync objects, user channels and events, DWT comparators, ITM ports. ns is the namespace (task, isr, user_trace, dwt, itm, ...), va_id the firmware's id inside it |
va_events | id, t_cycles, t_atoms, frame_pos, kind, start_end, obj, obj2, value_i, value_f, text, pre_sync | Every event. t_cycles is CPU cycles; seconds = t_cycles / va_cpu_hz. kind is the event kind (task_switch, isr, user_trace, user_event, string, mutex, queue, dwt_pc, ...), start_end 1 for a start, 0 for an end, obj the object id |
health | stage, counters | stage = 'recorder': corrupt_bytes, corrupt_runs, lost_events, seq_gaps, main_trace_bytes |
raw_log | section, data | The byte-log (section = 'va_file'), so a recording can be re-parsed by a newer engine |
va_summary, va_task_stats, va_trace_stats, va_timer_stats, va_work_stats, va_comm_paths, va_comm_resources | Derived statistics the app shows on open, recomputed by load | |
va_signal_blocks | Full-rate waveforms from an external instrument, present only when a file has any |
Queries by hand
-- what is in the file
select kind, count(*) as n from va_events group by kind order by n desc;
-- a user channel's samples in seconds (integer channels fill value_i, float channels value_f)
select e.t_cycles * 1.0 / (select value from meta where key = 'va_cpu_hz') as t_s, coalesce(e.value_f, e.value_i) as value
from va_events e join va_objects o on o.id = e.obj
where o.ns = 'user_trace' and o.name = 'Sine Wave' order by e.t_cycles;
-- ISR run times in microseconds (start/end pairs on the same object)
with s as (
select obj, t_cycles as t0, lead(t_cycles) over (partition by obj order by t_cycles) as t1, start_end
from va_events where kind = 'isr')
select o.name, count(*) as runs, avg(t1 - t0) * 1e6 / 170e6 as mean_us, max(t1 - t0) * 1e6 / 170e6 as max_us
from s join va_objects o on o.id = s.obj where s.start_end = 1 group by o.name;
$ 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}
from viewalyzer_sdk import ViewAlyzer
rec = ViewAlyzer().open("run.vadb")
with rec.connect() as db: # read-only sqlite3 connection
rows = db.execute("select name from va_objects where ns = 'task'").fetchall()
Hardware trace in the file
Hardware trace rides va_events with no schema change (meta.version stays 1):
| KIND | NS / VA_ID | FIELDS |
|---|---|---|
dwt_pc | dwt / 0x2000 | value_i = the sampled PC, or NULL when the core was asleep |
dwt_exc | dwt / 0x1000 + exception number | value_i = 1 enter, 2 exit, 3 return |
dwt_data | dwt / comparator 0 to 3, named after the watch | value_i = the value, obj2 = size, text = w or r plus pc=0x... when traced |
dwt_data_pc | dwt / comparator | PC-only comparators: value_i = PC |
dwt_counters | dwt / 0x2010 + index (cpi, exc, sleep, lsu, fold, cyc) | value_i = cycles per wrap |
itm_text | itm / port | text |
Meta keys: hardware_trace (the applied register image, the registers found, and the capture's swo_load), pc_sample_source (dwt-swo or pcsr-poll), pc_sample_interval_cycles, va_itmhw_bytes, va_itmhw_overflows.
Byte-logs and raw dumps
load accepts a .vadb, a .va byte-log (the recorder's bytes with a small container header, written while a capture runs) and a raw wire dump with no header at all; all decode to the same recording, and load x.va --output x.vadb converts. A .vadb also keeps its byte-log in raw_log, so a recording can always be re-parsed by a newer engine.