Skip to content

Split send/recv reporting in bidir tests#57

Merged
lance0 merged 4 commits intomasterfrom
bidir-split-reporting
Apr 17, 2026
Merged

Split send/recv reporting in bidir tests#57
lance0 merged 4 commits intomasterfrom
bidir-split-reporting

Conversation

@lance0
Copy link
Copy Markdown
Owner

@lance0 lance0 commented Apr 17, 2026

Summary

Resolves #56. --bidir now reports per-direction bytes and throughput instead of just the combined sum, which was misleading on asymmetric links — users had to run xfr and xfr -R separately to get the numbers they actually wanted.

Example output (bidir)

Plain text:

Duration:    2.20s
Transfer:    Send: 4.52 GB    Recv: 7.42 GB    (Total: 11.94 GB)
Throughput:  Send: 17.64 Gbps  Recv: 28.94 Gbps  (Total: 46.58 Gbps)

JSON adds bytes_sent, bytes_received, throughput_send_mbps, throughput_recv_mbps alongside the existing bytes_total / throughput_mbps.

CSV gets four matching columns.

TUI shows ↑ 17.64 Gbps / ↓ 28.94 Gbps in the throughput panel, live during the test.

Design notes

  • Backward compat: new fields are Option<T> with serde defaults — older clients ignore them, older servers leave them None (client falls back to combined total)
  • Populated only for bidir tests; unidirectional tests keep the existing single-line format
  • Direction semantics: bytes_sent in TestResult/AggregateInterval means "bytes the client sent" (its upload direction). Server-local counters are swapped before emission so the client reads its own direction correctly.
  • Server tracks per-direction last_bytes_sent / last_bytes_received in StreamStats so AggregateInterval can carry real interval throughput per direction (not just end-of-test totals)
  • Per-stream split in StreamResult deferred to a follow-up — MVP is aggregate only

Test plan

  • cargo fmt --check
  • cargo clippy --all-features --all-targets -- -D warnings
  • cargo test --all-features — 93 unit + 55 integration + 18 protocol tests pass (3 new regression tests)
  • Manual smoke: bidir plain, bidir JSON (shows split), unidir plain, unidir JSON (correctly omits split)
  • Direction correctness verified: on localhost bidir, client's Send (default 128KB buffer) is slower than Recv (from server's 4MB high-speed buffer), matching expected asymmetry
  • Backward compat: new fields are optional, graceful degradation on mismatched versions

lance0 added 4 commits April 17, 2026 13:58
For --bidir tests, expose per-direction bytes and throughput so
asymmetric-link measurements are meaningful. Unidirectional tests are
unchanged: existing bytes_total / throughput_mbps are the single-
direction number and the new fields are serde-skipped as None.

Protocol (protocol.rs):
- TestResult gains optional bytes_sent, bytes_received,
  throughput_send_mbps, throughput_recv_mbps
- AggregateInterval gains the same fields (populated in a follow-up)

Stats (stats.rs):
- TestStats::total_bytes_sent() / total_bytes_received() aggregate
  per-stream atomics that already tracked each direction separately

Server (serve.rs):
- New directional_totals() helper computes per-direction totals when
  the test is bidir, returns all-None otherwise
- Wired into both run_test (TCP) and run_quic_test (QUIC) result
  construction

Output:
- plain.rs: three-column 'Send / Recv / (Total:)' format for bidir
- csv.rs: four new columns appended; empty for unidir
- json.rs: automatic via serde skip_serializing_if

No changes to client-side overlay — server is authoritative for both
directions. Per-interval split and per-stream split deferred to
follow-ups once the summary-level change lands.
TUI stats panel renders '↑ X / ↓ Y' when direction is Bidir and the
server has reported per-direction throughput. Falls back to the
combined throughput otherwise (older servers, unidir, early intervals
before any progress).

Tests added:
- stats::total_bytes_sent / total_bytes_received split correctness
- output_plain shows 'Send/Recv/(Total:)' for bidir, single-line for
  unidir
- integration: bidir TestResult populates the split Options; unidir
  leaves them None
- CHANGELOG [Unreleased] now lists the bidir split feature alongside
  the existing #54 teardown fixes
- ROADMAP marks #56 as shipped
- docs/FEATURES.md bidir section includes the new plain-text output
  sample, JSON field names, CSV columns, and TUI ↑/↓ rendering
Two issues surfaced in review:

1. TestResult send/recv were reversed from the client's perspective. Server-local
   stats.total_bytes_sent() is what the server sent — which, from the client's
   POV that reads TestResult, is what the client *received*. Swap in
   directional_totals() so the wire format matches the client's expectation
   (bytes_sent = bytes the client sent).

2. TUI never showed the live ↑/↓ during a running test because only TestResult
   carried the split; AggregateInterval/TestProgress didn't. Track per-direction
   interval deltas in StreamStats (last_bytes_sent / last_bytes_received),
   extend IntervalStats, add to_aggregate_with_direction() that swaps and
   populates AggregateInterval's new fields for bidir intervals, thread
   through TestProgress and on_progress() so the TUI shows the split live.
@lance0 lance0 merged commit 8d496f6 into master Apr 17, 2026
7 checks passed
@lance0 lance0 deleted the bidir-split-reporting branch April 17, 2026 19:03
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.

[feature request] separate upload/download in bidirectional tests

1 participant