// reglat.cpp — register round-trip latency of the transport: USB vendor-control // transfer vs PCIe BAR2 MMIO. Times RtlAdapter::rtw_read32 in a tight loop — the // SAME call on both buses, so it's a fair USB-vs-PCIe comparison of the per-op // latency and jitter that bound AdjustBeaconTimingFine (read-modify-write of the // TSF) and hence the closed-loop uplink timing advance. No bring-up: the read // works right after claim (USB) / vfio-map (PCIe). // // USB: sudo ./build/reglat (DEVOURER_PID/VID pick the adapter) // PCIe: sudo DEVOURER_PCIE_BDF=0000:01:00.0 ./build/reglat (vfio-bind first: // sudo tests/pcie_vfio_bind.sh 0000:01:00.0) // // Bench numbers (this rig): USB 8822EU ~66 us/op (jitter p99-p50 ~48 us); PCIe // 8821CE MMIO ~2.2 us/op (jitter ~0.09 us) — ~30x faster, ~600x lower jitter. #include #include #include #include #include #include #include #include #include "RtlAdapter.h" #include "UsbOpen.h" #include "logger.h" #if defined(DEVOURER_HAVE_PCIE) #include "PcieTransport.h" #endif static int N = 3000; static constexpr uint32_t kReg = 0x00F0; // SYS_CFG1 — safe read-only, any state static void report(const char *what, RtlAdapter &a) { std::vector us(N); for (int i = 0; i < N; i++) { auto t0 = std::chrono::steady_clock::now(); volatile uint32_t v = a.rtw_read32(kReg); (void)v; us[i] = std::chrono::duration( std::chrono::steady_clock::now() - t0) .count(); } std::sort(us.begin(), us.end()); double sum = 0; for (double x : us) sum += x; auto q = [&](double p) { return us[(int)(p * N)]; }; printf("%s rtw_read32(0x%04x) x%d: mean=%.3f p50=%.3f p90=%.3f p99=%.3f " "min=%.3f max=%.3f us jitter(p99-p50)=%.3f\n", what, kReg, N, sum / N, q(.50), q(.90), q(.99), us.front(), us.back(), q(.99) - q(.50)); } int main() { auto lg = std::make_shared(); if (const char *n = std::getenv("DEVOURER_REGLAT_N")) { int nn = atoi(n); // (not std::max: defines a max() macro on MSVC) N = nn > 100 ? nn : 100; } #if defined(DEVOURER_HAVE_PCIE) if (const char *bdf = std::getenv("DEVOURER_PCIE_BDF")) { auto t = devourer::PcieTransport::Open(bdf, lg); if (!t) { fprintf(stderr, "pcie open failed for %s (vfio-bound?)\n", bdf); return 1; } RtlAdapter a(t, lg, {}); report("PCIe MMIO", a); return 0; } #endif libusb_context *ctx = nullptr; libusb_init(&ctx); libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_WARNING); uint16_t vid = 0x0bda, pid = 0; if (const char *v = std::getenv("DEVOURER_VID")) vid = (uint16_t)strtoul(v, 0, 0); if (const char *p = std::getenv("DEVOURER_PID")) pid = (uint16_t)strtoul(p, 0, 0); auto *h = libusb_open_device_with_vid_pid(ctx, vid, pid); if (!h) { fprintf(stderr, "usb open %04x:%04x failed (set DEVOURER_PID)\n", vid, pid); return 1; } std::shared_ptr lk; if (devourer::claim_interface_then_reset(h, devourer::find_wifi_interface(h), lg, true, lk) != 0) return 1; RtlAdapter a(h, lg, ctx, lk, {}); report("USB ctrl-xfer", a); return 0; }