viewalyzer-sdk
Python SDK for the ViewAlyzer headless CLI: automate embedded trace capture, analytics queries, and regression assertions from Python, pytest, and CI.
ViewAlyzer records RTOS/baremetal trace streams from real targets (ST-Link
SWO, J-Link RTT, RAM-buffer draining, UDP, serial) into self-describing
.vadb recordings, which are standard SQLite files, and answers analytics
queries about them as JSON. This package wraps that CLI so a
hardware-in-the-loop test can be three lines of Python.
from viewalyzer_sdk import ViewAlyzer
va = ViewAlyzer() # finds the installed ViewAlyzer app
rec = va.record("board.vacf", output="run1.vadb", duration_s=10)
assert rec.total_events > 0 # capture actually captured
assert rec.is_clean() # no corruption, no loss
assert rec.inversions()["inversions"] == [] # no priority inversions
assert rec.task_stats()[0]["cpu_percent"] < 80 # CPU headroom held
Zero dependencies, stdlib only. Requires a ViewAlyzer installation (the app is the engine; this package is the steering wheel). Get the app at viewalyzer.net.
Install
pip install viewalyzer-sdk
Then check the wiring:
viewalyzer-doctor
which prints the executable the SDK found (or how to point it at one), the CLI's version handshake, and the app's own health check of external tools and attached probes.
Finding the ViewAlyzer executable
First hit wins:
- the
VIEWALYZERenvironment variable (path to the executable); set but wrong raises immediately rather than silently falling back; PATH(ViewAlyzer/viewalyzer,.exeimplied on Windows);- the standard install locations:
%ProgramFiles%\ViewAlyzerand%LOCALAPPDATA%\Programs\ViewAlyzeron Windows,/Applicationsand~/Applicationson macOS,/usr/local/bin,~/.local/bin, and/opt/ViewAlyzeron Linux.
Or pass a path explicitly: ViewAlyzer("/path/to/ViewAlyzer"). Nothing is
ever hardcoded: every tool path the CLI uses (J-Link install dir,
arm-none-eabi-gdb, ...) can be set through the connection config or the
method arguments.
Capturing
# From a committed connection config (.vacf)...
rec = va.record("board.vacf", output="ci-run.vadb", duration_s=10)
# ...or an inline dict with the same keys (CLI flag names, no leading --):
rec = va.record(
{"transport": "udp", "udp-ip": "127.0.0.1", "udp-port": 5005,
"cpu-clock-hz": 170_000_000, "cobs": True},
output="ci-run.vadb",
duration_s=10,
)
# Watch variables during the same capture (memory-polled over the probe):
rec = va.record("board.vacf", output="run.vadb", duration_s=10,
elf="firmware.elf", symbols=["adc_value:u16"], poll_hz=200)
rec.path is the authoritative on-disk file (the CLI forces the .vadb
extension), rec.recording_id the id for later queries.
Memory polling needs no firmware instrumentation at all:
symbols = va.list_symbols("firmware.elf", filter="motor")
rec = va.record_polls("firmware.elf", ["tick_counter", "adc_value"],
duration_s=10, poll_hz=100, config="board.vacf")
And for firmware using the RAM-buffer transport, a post-mortem snapshot reads the trace ring out of target RAM without resetting anything:
rec = va.snapshot("board.vacf", output="crash.vadb", elf="firmware.elf")
print(rec.info["summary"]) # ring kind, events, window bytes, ...
Querying
Tiered, size-bounded JSON via the CLI. Start at summary, drill down:
rec.timeline() # per-task CPU%, slice stats, jitter
rec.timeline(tier="bucketed", t_start_us=0, t_end_us=1_000_000,
bucket_us=10_000) # CPU% over time
rec.events() # counts by kind, top tasks
rec.user_traces() # data channels: min/max/mean/last
rec.cpu() # the CPU panel's scheduler statistics
rec.timers() # per-timer lateness stats, violations
rec.comms() # producer -> consumer paths, latency
rec.etm() # ETM call-tree profile (if captured)
rec.series("cpu-load") # timeline series as [[t_us, value], ...]
rec.inversions() # every priority inversion, full story
rec.sql("SELECT name, cpu_percent FROM va_task_stats "
"ORDER BY cpu_percent DESC LIMIT 5")
Golden-run regression testing distills a recording into a small, git-committable baseline and gates CI on deviations:
rec.fingerprint(out="golden.vafp.json") # commit this file
result = new_rec.compare("golden.vafp.json") # later runs
assert result["verdict"] in ("pass", "warn")
And because a .vadb is a SQLite database, overview reads skip the
subprocess entirely:
rec = va.open("ci-run.vadb")
rec.summary() # va_summary: total_events, cpu_load_percent, ...
rec.task_stats() # per-task stats, synthetic lanes filtered out
rec.meta() # provenance: va_cpu_hz, va_os, ...
con = rec.connect() # read-only sqlite3.Connection for anything else
pytest recipe
# conftest.py
import pytest
from viewalyzer_sdk import ViewAlyzer
@pytest.fixture(scope="session")
def va():
client = ViewAlyzer()
assert client.version()["schema_version"] == 1
return client
@pytest.fixture(scope="session")
def rec(va, tmp_path_factory):
out = tmp_path_factory.mktemp("trace") / "run.vadb"
r = va.record("board.vacf", output=out, duration_s=10)
assert r.total_events > 0, "empty capture - check probe/firmware setup"
return r
# test_regression.py
def test_no_priority_inversions(rec):
assert rec.inversions()["inversions"] == []
def test_control_task_period_jitter(rec):
stats = {t["name"]: t for t in rec.task_stats()}
assert abs(stats["control_tid"]["max_jitter_us"]) < 200
Error handling
Everything raises ViewAlyzerError with a machine-readable .code: the
CLI's own envelope codes (no_such_recording, bad_sql, bad_arguments,
window_too_wide with .suggestion telling you how to narrow the window)
plus the SDK's own (binary_missing, timeout, bad_output,
record_failed, file_not_found). Capture failures surface the CLI's
ERROR: diagnostics (e.g. Failed to connect to target), not a bare exit
code.
Portable configs
.vacf files committed with a project are portable except for
machine-absolute tool paths (jlink, arm-gdb, ...). Don't edit the
shared file for your machine: load it, override in memory, and pass the
dict:
cfg = json.loads(Path("board.vacf").read_text())
if not Path(cfg.get("jlink", "")).exists(): # path from another machine
cfg["jlink"] = shutil.which("JLinkGDBServerCL") or cfg["jlink"]
rec = va.record(cfg, output="run.vadb", duration_s=10)
Notes
- Query-layer times are microseconds since recording start; raw
va_events.t_cyclesvalues are CPU cycles (meta.va_cpu_hz). delete_recording()/delete_all_recordings()delete the files on disk, not just index entries.- One process per call, no daemon: parallel pytest workers are fine as long as they don't fight over the same debug probe.
Full method-by-method reference, error-code table, and troubleshooting
(including what to do about a capture with total_events == 0):
docs/API.md.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file viewalyzer_sdk-1.0.0.tar.gz.
File metadata
- Download URL: viewalyzer_sdk-1.0.0.tar.gz
- Upload date:
- Size: 28.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
555706bd2213196ef22267eb8ac3c5476117773cfe1ec3b92f21176bb1ba423e
|
|
| MD5 |
5d3c7690c289d550721340caae99290a
|
|
| BLAKE2b-256 |
b804da3061c81bffb7646584c80170f1ae4e47670fd51b1f3905c46b6920e91e
|
Provenance
The following attestation bundles were made for viewalyzer_sdk-1.0.0.tar.gz:
Publisher:
workflow.yml on BKPT-Labs/ViewAlyzer-SDK
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
viewalyzer_sdk-1.0.0.tar.gz -
Subject digest:
555706bd2213196ef22267eb8ac3c5476117773cfe1ec3b92f21176bb1ba423e - Sigstore transparency entry: 2457028279
- Sigstore integration time:
-
Permalink:
BKPT-Labs/ViewAlyzer-SDK@ec8eb7ed8c6e463d2e1c4322403357446e23b35d -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/BKPT-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@ec8eb7ed8c6e463d2e1c4322403357446e23b35d -
Trigger Event:
push
-
Statement type:
File details
Details for the file viewalyzer_sdk-1.0.0-py3-none-any.whl.
File metadata
- Download URL: viewalyzer_sdk-1.0.0-py3-none-any.whl
- Upload date:
- Size: 25.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c29953a911acb94ca12c880ea0cefdf1f642e6dd83587daf7f4cf67b321c732
|
|
| MD5 |
9b77cbd7e2cc254485dfdc52123d05fc
|
|
| BLAKE2b-256 |
acb363860ea329a1610301ea1c9c7e9c6167a25b1387c76148a30c9a2f9874f8
|
Provenance
The following attestation bundles were made for viewalyzer_sdk-1.0.0-py3-none-any.whl:
Publisher:
workflow.yml on BKPT-Labs/ViewAlyzer-SDK
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
viewalyzer_sdk-1.0.0-py3-none-any.whl -
Subject digest:
7c29953a911acb94ca12c880ea0cefdf1f642e6dd83587daf7f4cf67b321c732 - Sigstore transparency entry: 2457028700
- Sigstore integration time:
-
Permalink:
BKPT-Labs/ViewAlyzer-SDK@ec8eb7ed8c6e463d2e1c4322403357446e23b35d -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/BKPT-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@ec8eb7ed8c6e463d2e1c4322403357446e23b35d -
Trigger Event:
push
-
Statement type: