# irtt-client ## NAME irtt-client - IRTT-compatible stream client ## SYNOPSIS `irtt-client` [*OPTIONS*] [*[LABEL=]TARGET[@hmac=KEY]*]... `irtt-client` `--list-columns` ## DESCRIPTION `irtt-client` probes one or more IRTT-compatible servers over UDP and prints per-probe measurement events as they arrive, plus a final summary for eligible runs. ## TARGETS Every target argument accepts `[LABEL=]TARGET[@hmac=KEY]`. An optional `LABEL=` prefix assigns the logical target name used in output; without it, the target string itself is used as the label. Labeled and unlabeled targets can be freely mixed in one argument list. Prefer explicit labels for long-running dynamic target sets: the label is the stable target identity across replacements. ```sh irtt-client host-a:2112 irtt-client eu=host-a:2112 us=host-b:2112 irtt-client host-a:2112 eu=host-b:2112 irtt-client --hmac default-secret eu=host-a:2112@hmac=eu-secret public=host-b:2112@hmac= ``` Targets without `@hmac=` inherit the global `--hmac` value. `@hmac=KEY` overrides it for that target, and `@hmac=` explicitly disables HMAC for that target. The modifier uses `@`, not a shell command separator; quote an argument if its key needs shell quoting. A literal `@` immediately before `hmac=` in the target portion is written as `\@`. Multiple targets are probed concurrently. By default, a multi-target session uses **staggered** pacing, spacing active targets across the probe interval; pass `--pacing burst` to send one probe to every active target back-to-back once per interval instead. Final per-target summaries print in the order targets were supplied on the command line, not the order in which they finish or their labels sort alphabetically. ## FINITE VERSUS CONTINUOUS OPERATION `--duration` controls the run length: - Any nonzero duration (default `10s`) is a **finite** run: probing stops after that long, and a final summary is always printed for table output (see [OUTPUT](#output) below — CSV, TSV, and JSON Lines never print one). - `--duration 0` is **continuous**: the client runs until interrupted (`Ctrl-C`). For table output, a final summary is printed only if the run was interrupted; an uninterrupted continuous run (one that exits for another reason) does not get one. See [MEASUREMENTS AND MEMORY](#measurements-and-memory) below for why this distinction also determines what statistics can be computed and how much memory a long run retains. ## OUTPUT ### `--format FORMAT` One of four event-row formats, default `table`: - `table`: human-readable terminal output; the only format that prints a final summary. - `csv`: comma-separated output. - `tsv`: tab-separated output. - `jsonl`: one JSON object per event. CSV, TSV, and JSON Lines default to **all** columns for structured export; `table` defaults to a compact column set and hides `echo_sent` rows. An explicit `--columns` selection other than `default` shows all event rows, including `echo_sent`; `--columns default` is equivalent to omitting the option and keeps `echo_sent` hidden for table output. ### `--columns COLUMNS` / `-c COLUMNS` Comma-separated event row columns, or the special values `default` (the format's default set) or `all` (every column). List every available column, its meaning, and its aliases with: ```sh irtt-client --list-columns ``` (`--list-columns` does not require a target.) ### `--header auto|always|never` Header policy for `table`, `csv`, and `tsv` output (default `auto`). JSON Lines never prints a header line. ### `--verbose` Includes extra fields in table output and final summaries. Has no effect on CSV, TSV, or JSON Lines output either way — those formats show their default all-column set or an explicit `--columns` selection exactly as given, regardless of `--verbose`. ### Examples ```sh irtt-client --format table irtt-client --format jsonl irtt-client --format csv --columns event,seq,remote,effective_rtt_us ``` A stream containing only effective RTT values in microseconds: ```sh irtt-client --format tsv --columns effective_rtt_us --header never ``` ## MEASUREMENT FIELDS Useful measurement columns: - `raw_rtt_us`: client-observed send-to-receive RTT. Always userspace-timed and unaffected by kernel timestamp preference (below). - `adjusted_rtt_us`: RTT adjusted for server processing when available. Can be negative when server processing exceeds the measured raw RTT. - `effective_rtt_us`: `adjusted_rtt_us` when available, otherwise `raw_rtt_us`. - `rd_us` / `sd_us` (selectable with the longer aliases `receive_delay_us` / `send_delay_us`, but always emitted under the short names): one-way delay estimates. Can be negative because of clock skew between client and server. - `ipdv_us`: inter-packet delay variation. - `server_processing_us`: time spent processing the packet at the server. - `kernel_rx_ns`: kernel receive timestamp, in Unix nanoseconds, when captured (see below). ### Kernel timestamps (Linux) On Linux, one-way delay estimates prefer a kernel-captured timestamp over userspace timing for this client's own send/receive endpoint, where the platform and socket support it, reducing the effect of scheduling and queuing delay. The peer's reported endpoint gets the same preference when it is the `irtt-server` applet running on Linux; against another IRTT-compatible server, whatever wall-clock value it reports is used as-is. This is best-effort: an unsupported or implausible kernel timestamp falls back to userspace timing. `raw_rtt_us` is unaffected either way; `adjusted_rtt_us`/`effective_rtt_us` can still shift slightly, since server processing time is derived from the same server receive endpoint. ## MEASUREMENTS AND MEMORY Finite and continuous modes make a different tradeoff between exact statistics and bounded memory. **Finite mode** retains exact timing samples (and adjacent-sequence IPDV state) so the final summary can report exact medians. Retained memory therefore grows with the number of probes sent, at a small constant cost per probe (on the order of a few hundred bytes of retained sample state per probe per target, before allocator overhead) — a very long finite run at a short interval is the case to plan capacity for. The client warns on stderr when its own estimate of this retained state crosses roughly 128 MiB, and again more strongly past roughly 512 MiB and 1 GiB; treat those numbers as practical guidance, not a promised RSS ceiling, since allocator and OS overhead sit outside the estimate. **Continuous mode** (`--duration 0`) does not retain a growing sample history: running statistics keep count/min/max/mean/variance only, so exact medians are unavailable. It still keeps a bounded adjacent-sequence IPDV store, capped at 4,096 sequences per target, so nearby replies can still form IPDV pairs. Retained statistics state therefore approaches a fixed per-target bound rather than growing with elapsed run time. Reply classification (independent of the statistics choice above) is also bounded per target: each of the pending, timed-out, and completed/duplicate sequence stores has its own 4,096-entry limit — not one shared total across the three. A full pending store makes the client fail and drain that target as resource-exhausted rather than wait for capacity to free. Timed-out and completed state evict their oldest entries, so a sufficiently old late reply can still be seen and counted, but no longer has retained send state for measurements such as RTT. Overall, retained state scales with the **number of configured targets** and these fixed per-target limits, not with total probes sent in continuous mode. Output is written as events arrive rather than accumulated; the managed event stream feeding it is itself bounded and lossy (16,384 events), so a sufficiently slow consumer can miss events, in which case the client reports that resulting output/statistics may be incomplete. For capacity planning on constrained devices (for example an OpenWrt router): a finite run's statistics memory is roughly proportional to `targets × probes_sent`, while a continuous run's statistics memory approaches a fixed multiple of `targets` regardless of how long it runs. ## PEER CLOSE AND EXIT BEHAVIOR A peer closing a finite run is accepted as a terminal, successful outcome. In continuous mode, an uninterrupted peer closure is treated as an error — the client exits nonzero — so a process supervisor can restart it; an interrupted run (`Ctrl-C`) never reports peer closure as an error, whichever mode it was in. ## EXIT STATUS `0` on success (including a finite run's ordinary completion, and an interrupted run of either mode). Nonzero if the managed driver failed, if an uninterrupted continuous run ended by peer closure, or if the run was not interrupted and no target completed successfully. An interrupted run never fails on the last of these conditions — for example, interrupting a continuous run whose only target never opened still exits `0`. ## SERVER FILL REQUEST `--sfill DESCRIPTOR` requests the server's echo-reply payload fill: `none` (zero-filled), `rand` (random bytes), or `pattern:HEX` (a repeating hexadecimal pattern). See `irtt-server(1)` SERVER FILL for what the server does with an unset or unparseable request. ## EXAMPLES ```sh irtt-client netperf-eu.bufferbloat.net:2112 irtt-client netperf-eu.bufferbloat.net:2112 --duration 30s --interval 100ms irtt-client netperf-eu.bufferbloat.net:2112 --duration 0 irtt-client host-a:2112 host-b:2112 --pacing burst ``` ## SEE ALSO `irtt-tui(1)`, `irtt-server(1)`, `irtt-rs(1)`, and `irtt-client --help` for the full option list, including HMAC, clock/timestamp negotiation, DSCP, and TTL flags.