Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

env:
OS: ${{ matrix.os }}
Expand Down
23 changes: 23 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,29 @@ Outputs from ``print`` calls from on-device user-code are forwarded to host ``st

`For more examples, see the examples folder.`_

Performance
===========

Round-trip Communication Latency
---------------------------------

Belay provides reasonable communication latency between the host computer and the MicroPython device.
You can measure the latency of your setup using the ``belay latency`` command:

.. code-block:: bash

belay latency /dev/ttyUSB0

Benchmark results on an M3 MacBook Pro with an RP2040 (pi pico) device over USB:

.. code-block:: text

Statistics (10000 samples):
Min: 3.67 ms
Max: 11.52 ms
Average: 4.19 ms
Median: 4.17 ms
Std Dev: 0.21 ms

.. |GHA tests| image:: https://github.com/BrianPugh/belay/actions/workflows/tests.yaml/badge.svg?branch=main
:target: https://github.com/BrianPugh/belay/actions?query=workflow%3Atests
Expand Down
76 changes: 76 additions & 0 deletions belay/cli/latency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import csv
import statistics
import time
from pathlib import Path
from typing import Annotated, Optional

from cyclopts import Parameter

from belay import Device
from belay.cli.common import PasswordStr, PortStr


def latency(
port: PortStr,
*,
password: PasswordStr = "",
count: Annotated[int, Parameter(alias="-c")] = 10,
verbose: Annotated[bool, Parameter(alias="-v")] = False,
output: Annotated[Optional[Path], Parameter(alias="-o")] = None,
with_timing: Annotated[bool, Parameter(alias="-t", negative=("--no-with-timing", "--without-timing"))] = True,
):
"""Measure round-trip latency between host and device.

Performs multiple round-trip measurements and reports statistics.

Parameters
----------
count : int
Number of round-trip measurements to perform.
verbose : bool
Show individual measurements in addition to statistics.
output : Path, optional
Export individual latency measurements to a CSV file.
with_timing: bool
With the additional per-call time synchronization logic.
"""
device = Device(port, password=password, auto_sync_time=with_timing)

latencies = []
if verbose:
print(f"Measuring latency with {count} iterations...")

for i in range(count):
start = time.perf_counter()
device("0") # Short, no-op statement
end = time.perf_counter()
latency_ms = (end - start) * 1000
latencies.append(latency_ms)
if verbose:
print(f" {i + 1:2d}: {latency_ms:6.2f} ms")

# Calculate statistics
min_latency = min(latencies)
max_latency = max(latencies)
avg_latency = statistics.mean(latencies)
median_latency = statistics.median(latencies)
stdev_latency = statistics.stdev(latencies) if len(latencies) > 1 else 0.0

if verbose:
print()
print(f"Statistics ({count} samples):")
print(f" Min: {min_latency:6.2f} ms")
print(f" Max: {max_latency:6.2f} ms")
print(f" Average: {avg_latency:6.2f} ms")
print(f" Median: {median_latency:6.2f} ms")
print(f" Std Dev: {stdev_latency:6.2f} ms")

# Export to CSV if requested
if output is not None:
with output.open("w", newline="") as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["latency_ms"])
for latency_ms in latencies:
writer.writerow([f"{latency_ms:.2f}"])

device.close()
2 changes: 2 additions & 0 deletions belay/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from belay.cli.exec import exec
from belay.cli.info import info
from belay.cli.install import install
from belay.cli.latency import latency
from belay.cli.new import new
from belay.cli.run import run
from belay.cli.select import select
Expand All @@ -27,6 +28,7 @@
app.command(exec)
app.command(info)
app.command(install)
app.command(latency)
app.command(new)
app.command(run)
app.command(select)
Expand Down
Loading