Skip to content

feat: record the first join as a latency DAG (3RTT T01) - #7

Merged
tbarbugli merged 5 commits into
factory/3rttfrom
3rtt/t01-join-dag
Sep 30, 2026
Merged

tbarbugli merged 5 commits into
factory/3rttfrom
3rtt/t01-join-dag

Conversation

@tbarbugli

Copy link
Copy Markdown
Member

3RTT task T01. Replaces ConnectionTiming (folds in #2) with jointrace: the first join is recorded as a DAG of spans, so a trace shows which steps run in parallel, which chain is critical, and every network step in round trips of its peer. Builds on #5.

What's in it

  • jointrace package: Span{Name, After, Parent, Start, End, Kind, Peer, Note}, with the node names from research/join-dag.md as constants.
    • Trace.CriticalPath() walks back from the terminal step (pub.rtp/sub.rtp), following the dependency that finished last.
    • Trace.String() draws the DAG with a gantt column and marks the critical path; json.Marshal(trace) gives a flat Report.
  • Call.JoinTrace() and Call.OnJoinTrace(fn). The handler fires once media flows both ways, or after JoinTraceTimeout. Reconnects after the first join seal the trace.
  • httptrace detail (.dns, .tcp, .tls, .request, .first_byte) on:
    • the coordinator REST join,
    • the coordinator and SFU websockets, via the new internal/wsdial,
    • the SFU twirp RPCs.
  • A .server span from Server-Timing when the server sends one.
  • RTT per peer: coordinator and SFU from the TCP connect, UDP from the ICE selected pair.
  • WithNetworkDelay(rtt), for tests and benches only. Every connection the client opens is delayed rtt/2 each way, in order, and a TCP connect takes one RTT. This covers coordinator REST and WS, the location hint, SFU WS and twirp, and ICE UDP via SettingEngine.SetNet.
  • signal.WithDialContext, signal.WithTLSConfig, testutil.WithTLS().

Tests

  • jointrace: the critical path through parallel branches, gaps counted as wait, a JSON round trip, a render golden (go test ./jointrace -update), httptrace phases and Server-Timing over a delayed TLS server, a traced wss dial at 3 RTT, and a recording cost check (< 1 ms per join).
  • internal/netdelay: TCP connect and echo, and UDP echo, each 100 ms ± 5%; order kept over 500 writes; deadlines.
  • A full join against fakesfu with real pion peers both ways:
    • Every applicable node is present, each after its dependencies.
    • The critical path total is within 5 ms of Join → last first RTP.
  • The same join with WithNetworkDelay(100ms) over TLS: sfu.ws.dial is 3 RTT and sfu.join is 1 RTT, each ± 10%, and the SFU and UDP RTTs are 100 ms ± 10%.
  • make ci is green.

Example (fake SFU over TLS, WithNetworkDelay(100ms)):

critical path: pcs.create > sfu.ws.dial > sfu.join > sub.debounce > sub.offer > sub.sendanswer > sub.ice > sub.dtls > sub.rtp
  1405.4 ms = 10.83 RTT (1089.4 ms network) + 314.3 ms timers + 1.8 ms local; 0.0 ms unaccounted waiting

tbarbugli and others added 5 commits September 29, 2026 12:15
Call.ConnectionTiming and Call.OnConnectionTiming expose when the
coordinator join, the SFU websocket and join, and each peer connection's
signaling, ICE, DTLS and first RTP happened, so callers can print where
connection setup time goes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Delays every write and read by rtt/2 in order, and a TCP connect by one
rtt, on stream conns, packet conns and a pion transport.Net for ICE.
For tests and benches only.
…dialer

Reports TLS, request and first-byte times to the context's
httptrace.ClientTrace, and leaves DNS and connect to the dial function,
as net/http does.
Replaces ConnectionTiming with jointrace: each step of the join is a span
with its dependencies, kind (net, local, timer) and peer, so the trace
shows which branches run in parallel and which chain is critical.

- Call.JoinTrace and Call.OnJoinTrace, fired when media flows both ways
  or after JoinTraceTimeout.
- httptrace detail (DNS, TCP, TLS, request, first byte) for the
  coordinator REST call, the coordinator and SFU websockets and the SFU
  RPCs; Server-Timing when the server sends it.
- RTT per peer from the TCP connect and the ICE selected pair; every
  network span is also expressed in round trips of its peer.
- Trace.String draws the DAG with the critical path marked; the trace
  marshals to a JSON report.
- WithNetworkDelay, for tests and benches: every connection the client
  opens, UDP included, behaves as if it crossed a network with that RTT.
- signal.WithDialContext and signal.WithTLSConfig; testutil.WithTLS.
@tbarbugli
tbarbugli marked this pull request as ready for review September 30, 2026 15:27
@tbarbugli
tbarbugli merged commit 8828dfe into factory/3rtt Sep 30, 2026
1 check passed
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