Skip to content

Timing accuracy: NTP/PTP-over-Wi-Fi comparison + USB-vs-PCIe transport-latency bench#228

Merged
josephnef merged 3 commits into
masterfrom
transport-latency-bench
Jul 10, 2026
Merged

Timing accuracy: NTP/PTP-over-Wi-Fi comparison + USB-vs-PCIe transport-latency bench#228
josephnef merged 3 commits into
masterfrom
transport-latency-bench

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

Summary

Answers the recurring question "how accurate is the TSF time distribution vs NTP/PTP
over Wi-Fi?"
with measured numbers from a two-node bench, and lands a reusable
transport-latency microbench. Follow-up to #227 (over-the-air time distribution).

Two small, self-contained additions — a benchmark tool and a docs writeup; no
library change.

tests/reglat.cpp — register round-trip latency (USB vs PCIe)

One binary that times RtlAdapter::rtw_read32 over whichever transport it opens —
USB vendor-control by default, PCIe BAR2 MMIO when DEVOURER_PCIE_BDF is set (the
PCIe path compiles only with DEVOURER_PCIE, via the devourer PUBLIC
DEVOURER_HAVE_PCIE define). Added as a plain add_executable (USB path builds in
all configs). Measured on the same binary:

Transport mean/op jitter (p99−p50)
USB (8822EU) ~68 µs ~64 µs
PCIe 8821CE (MMIO) ~2.2 µs ~0.08 µs

~30× faster, ~600–900× lower jitter. The AdjustBeaconTimingFine actuator
chains ~5–7 register ops, so the ~0.5–1.2 ms USB jitter (and the ~1.3 ms closed-loop
uplink-TA residual) is a transport floor — a PCIe MMIO path would collapse it
toward µs.

docs/timing-accuracy.md — NTP / PTP over Wi-Fi vs TSF

Measured on two machines associated to the same AP:

Method Precision over Wi-Fi Timestamp source
NTP (chrony -Q, software TS) ~0.76 ms RMS (quiet); tens of ms under load software
PTP (ptp4l) does not run
devourer TSF downlink ~0.25 µs RMS 802.11 MAC hardware
  • ~3000× tighter than NTP, because the MAC latches the TSF below the
    CSMA/queue/power-save layer whose RTT jitter (measured 1.6 → 110 ms under
    load) bounds software-timestamped protocols.
  • PTP can't run: ethtool -T = PTP Hardware Clock: none; grepping the
    reference/ vendor drivers for SOF_TIMESTAMPING/SIOCSHWTSTAMP/skb_hwtstamps/
    get_ts_info finds nothing — neither vendor nor in-tree driver exposes the HW
    timestamp to the kernel API, though both read the TSF internally. devourer
    surfaces it (RxPacket.tsfl), which is what enables sub-µs sync.

Caveats kept explicit in the doc: devourer's figure is one-way relative precision
(TSF is 1 µs resolution, sub-µs via averaging), NTP's is the healthy-link daemon
offset, and FTM ranging can beat a one-way TSF on absolute accuracy.

Testing

ctest green; multi-config build clean (reglat builds in USB-only and PCIe
configs); PCIe path verified on a Radxa X4 (RTL8821CE) via vfio-pci.

🤖 Generated with Claude Code

josephnef and others added 3 commits July 10, 2026 11:03
… vs PCIe MMIO)

One binary that times RtlAdapter::rtw_read32 in a tight loop over whichever
transport it opens — USB vendor-control by default, PCIe BAR2 MMIO when
DEVOURER_PCIE_BDF is set (the PCIe path compiles only with DEVOURER_PCIE, via the
devourer PUBLIC DEVOURER_HAVE_PCIE define). Same call on both buses = a fair
comparison of the per-op latency + jitter that bound AdjustBeaconTimingFine (a TSF
read-modify-write) and hence the closed-loop uplink timing advance.

Measured on the bench (same reglat.cpp):
  USB  8822EU        mean ~68 us/op   jitter(p99-p50) ~64 us
  PCIe 8821CE MMIO   mean ~2.2 us/op  jitter ~0.08 us
=> PCIe ~30x faster, ~600-900x lower jitter — quantifies why the USB actuator
   jitter (~5-7 chained ops -> ~0.5-1.2 ms) would collapse to ~us on a PCIe MMIO
   path, i.e. the USB transport, not the sync method, is the closed-loop TA floor.

Added as a plain add_executable (built in all configs; USB path only when PCIE
is off). No library change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…/PCIe latency

Answer the recurring "how accurate vs NTP/PTP over Wi-Fi?" question with measured
numbers from a two-node bench, methodology, and honest caveats:

- NTP (chrony, software timestamps): ~0.76 ms RMS on a quiet link, tens of ms
  under Wi-Fi power-save/contention.
- PTP (ptp4l): does not run — neither the in-tree nor the reference/ vendor
  drivers expose the hardware timestamp to the kernel timestamping API
  (ethtool -T: none), though both read the TSF internally.
- devourer TSF downlink: ~0.25 us RMS residual — the MAC latches the timestamp
  below the CSMA/queue/power-save layer whose RTT jitter (measured 1.6->110 ms
  under load) bounds NTP/PTP. ~3000x tighter, and the reason PTP can't run.
- Transport: reglat shows USB ~68 us/op vs PCIe MMIO ~2.2 us/op (jitter ~64 vs
  ~0.08 us) — the actuator/uplink-TA floor is the transport, not the method.

Caveats kept explicit: devourer's number is one-way relative precision (TSF is
1 us resolution, sub-us via averaging), NTP's is the healthy-link daemon offset,
and FTM ranging can beat a one-way TSF on absolute accuracy. Indexed in README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
libusb.h pulls in <windows.h>, which defines a max() macro, so std::max(...) fails
to compile under MSVC (C2589). Clamp the sample count manually instead. No behavior
change; GCC/Clang unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef josephnef merged commit 59073d4 into master Jul 10, 2026
15 checks passed
@josephnef josephnef deleted the transport-latency-bench branch July 10, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant