Skip to content

feat(stats): add HyStart++ stats#3432

Merged
omansfeld merged 8 commits into
mozilla:mainfrom
omansfeld:hystart_metrics
Mar 16, 2026
Merged

feat(stats): add HyStart++ stats#3432
omansfeld merged 8 commits into
mozilla:mainfrom
omansfeld:hystart_metrics

Conversation

@omansfeld
Copy link
Copy Markdown
Collaborator

@omansfeld omansfeld commented Mar 10, 2026

Depends on #3278. I will rebase once that lands on main. Only commits belonging to this PR are the following:

add slow_start_exit_reason stat

  • CongestionEvent if loss or ecn
  • Heuristic if algorithm (e.g. HyStart++)

add css_rounds_finished stat
add css_entries stat to count how often css was entered

The two CSS stats can be used to judge how often HyStart++ spuriously enters CSS and thus spends (unnecessary) time in throttled growth. In a perfect world we'd have 1 css entry and 5 rounds finished. If values are wildly increased that might point to an inefficiency.

The exit reason stat can be used to judge how well HyStart++ (or another heuristic) performs at detecting an exit point before packet loss occurs. Can also be used as a filter when recording stats on the firefox side as glean probes, e.g. to differentiate slow_start_exit_accuracy (introduced in this bug) for heuristic and congestion event based exits.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.17%. Comparing base (bf77765) to head (fbafbe9).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3432      +/-   ##
==========================================
- Coverage   94.30%   94.17%   -0.13%     
==========================================
  Files         127      131       +4     
  Lines       38708    39041     +333     
  Branches    38708    39041     +333     
==========================================
+ Hits        36502    36768     +266     
- Misses       1365     1424      +59     
- Partials      841      849       +8     
Flag Coverage Δ
freebsd 93.20% <100.00%> (-0.11%) ⬇️
linux 94.28% <100.00%> (+<0.01%) ⬆️
macos 94.16% <100.00%> (-0.01%) ⬇️
windows 94.27% <100.00%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
neqo-common 98.49% <ø> (ø)
neqo-crypto 86.90% <ø> (ø)
neqo-http3 93.91% <ø> (ø)
neqo-qpack 94.81% <ø> (ø)
neqo-transport 95.20% <100.00%> (-0.05%) ⬇️
neqo-udp 82.97% <ø> (ø)
mtu 86.61% <ø> (ø)

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 10, 2026

Merging this PR will not alter performance

✅ 24 untouched benchmarks
⏩ 27 skipped benchmarks1


Comparing omansfeld:hystart_metrics (fbafbe9) with main (bf77765)

Open in CodSpeed

Footnotes

  1. 27 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@omansfeld omansfeld marked this pull request as ready for review March 13, 2026 14:46
Copilot AI review requested due to automatic review settings March 13, 2026 14:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds additional congestion-control statistics to better observe HyStart++ behavior and slow-start exits, integrating them into the transport stats surface and updating CC/tests accordingly.

Changes:

  • Introduces SlowStartExitReason and records slow_start_exit_reason when leaving slow start via congestion events vs heuristic exit.
  • Adds HyStart++ CSS counters (css_entries, css_rounds_finished) and increments them inside the HyStart++ implementation.
  • Updates debug formatting and HyStart++/classic CC tests to cover the new stats.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
neqo-transport/src/stats.rs Adds the new exit reason enum + new congestion control stats fields; updates Stats debug output.
neqo-transport/src/cc/hystart.rs Increments CSS entry/round counters during HyStart++ processing.
neqo-transport/src/cc/classic_slow_start.rs Updates the slow start trait impl signature to accept stats mutably.
neqo-transport/src/cc/classic_cc.rs Records slow_start_exit_reason for heuristic exits and congestion events; updates tests accordingly.
neqo-transport/src/cc/tests/hystart.rs Extends HyStart++ tests to validate the new stats.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread neqo-transport/src/stats.rs
Comment thread neqo-transport/src/stats.rs Outdated
Comment thread neqo-transport/src/stats.rs
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Oskar Mansfeld <dev@omansfeld.net>
@github-actions
Copy link
Copy Markdown
Contributor

Client/server transfer results

Performance differences relative to 6a953c2.

Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.

Client vs. server (params) Mean ± σ Min Max MiB/s ± σ Δ main Δ main
neqo-neqo-cubic-nopacing 95.2 ± 4.3 85.9 104.8 336.0 ± 7.4 💚 -1.3 -1.3%
neqo-neqo-newreno-nopacing 95.8 ± 4.2 87.5 104.7 334.2 ± 7.6 💚 -2.3 -2.3%
neqo-quiche-cubic 191.0 ± 3.9 185.6 203.2 167.5 ± 8.2 💚 -2.4 -1.3%

Table above only shows statistically significant changes. See all results below.

All results

Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.

Client vs. server (params) Mean ± σ Min Max MiB/s ± σ Δ main Δ main
google-google-nopacing 463.7 ± 4.9 457.0 480.2 69.0 ± 6.5
google-neqo-cubic 276.5 ± 5.1 265.1 296.9 115.8 ± 6.3 -0.3 -0.1%
msquic-msquic-nopacing 220.9 ± 91.4 140.4 561.1 144.9 ± 0.4
msquic-neqo-cubic 248.6 ± 115.5 151.4 645.5 128.7 ± 0.3 -21.4 -7.9%
neqo-google-cubic 772.0 ± 4.4 764.9 787.6 41.5 ± 7.3 -0.2 -0.0%
neqo-msquic-cubic 158.3 ± 4.5 151.2 168.7 202.2 ± 7.1 -1.2 -0.7%
neqo-neqo-cubic 96.6 ± 4.5 87.2 106.4 331.3 ± 7.1 0.1 0.1%
neqo-neqo-cubic-nopacing 95.2 ± 4.3 85.9 104.8 336.0 ± 7.4 💚 -1.3 -1.3%
neqo-neqo-newreno 97.0 ± 5.0 86.5 108.5 330.0 ± 6.4 -1.3 -1.3%
neqo-neqo-newreno-nopacing 95.8 ± 4.2 87.5 104.7 334.2 ± 7.6 💚 -2.3 -2.3%
neqo-quiche-cubic 191.0 ± 3.9 185.6 203.2 167.5 ± 8.2 💚 -2.4 -1.3%
neqo-s2n-cubic 218.3 ± 4.3 209.7 232.1 146.6 ± 7.4 -0.3 -0.2%
quiche-neqo-cubic 182.2 ± 5.6 170.8 197.7 175.7 ± 5.7 -0.9 -0.5%
quiche-quiche-nopacing 141.5 ± 5.1 134.4 167.6 226.1 ± 6.3
s2n-neqo-cubic 175.2 ± 5.1 164.1 187.4 182.6 ± 6.3 -0.5 -0.3%
s2n-s2n-nopacing 249.9 ± 28.3 231.7 349.7 128.0 ± 1.1

Download data for profiler.firefox.com or download performance comparison data.

Comment thread neqo-transport/src/stats.rs Outdated
Comment thread neqo-transport/src/stats.rs Outdated
@omansfeld omansfeld enabled auto-merge March 16, 2026 11:23
@omansfeld omansfeld added this pull request to the merge queue Mar 16, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Benchmark results

Significant performance differences relative to bf77765.

transfer/walltime/pacing-false/same-seed: 💔 Performance has regressed by +3.2665%.
       time:   [80.279 ms 80.340 ms 80.406 ms]
       change: [+3.0475% +3.2665% +3.4320] (p = 0.00 < 0.05)
       Performance has regressed.
Found 4 outliers among 100 measurements (4.00%)
2 (2.00%) high mild
2 (2.00%) high severe
All results
transfer/1-conn/1-100mb-resp (aka. Download)/mtu-1504: No change in performance detected.
       time:   [202.18 ms 202.55 ms 202.94 ms]
       thrpt:  [492.76 MiB/s 493.70 MiB/s 494.61 MiB/s]
change:
       time:   [-0.6060% -0.3014% +0.0053] (p = 0.05 > 0.05)
       thrpt:  [-0.0053% +0.3023% +0.6097]
       No change in performance detected.
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high severe
transfer/1-conn/10_000-parallel-1b-resp (aka. RPS)/mtu-1504: No change in performance detected.
       time:   [284.40 ms 286.19 ms 288.01 ms]
       thrpt:  [34.721 Kelem/s 34.942 Kelem/s 35.162 Kelem/s]
change:
       time:   [-0.5411% +0.4177% +1.3542] (p = 0.39 > 0.05)
       thrpt:  [-1.3361% -0.4160% +0.5440]
       No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
transfer/1-conn/1-1b-resp (aka. HPS)/mtu-1504: No change in performance detected.
       time:   [38.552 ms 38.725 ms 38.919 ms]
       thrpt:  [25.694   B/s 25.823   B/s 25.939   B/s]
change:
       time:   [-0.4553% +0.1236% +0.7920] (p = 0.69 > 0.05)
       thrpt:  [-0.7858% -0.1234% +0.4573]
       No change in performance detected.
Found 11 outliers among 100 measurements (11.00%)
2 (2.00%) low mild
3 (3.00%) high mild
6 (6.00%) high severe
transfer/1-conn/1-100mb-req (aka. Upload)/mtu-1504: Change within noise threshold.
       time:   [203.69 ms 204.16 ms 204.75 ms]
       thrpt:  [488.40 MiB/s 489.82 MiB/s 490.94 MiB/s]
change:
       time:   [-1.1756% -0.8715% -0.5155] (p = 0.00 < 0.05)
       thrpt:  [+0.5181% +0.8792% +1.1896]
       Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe
streams/walltime/1-streams/each-1000-bytes: Change within noise threshold.
       time:   [590.75 µs 593.37 µs 596.28 µs]
       change: [+0.4261% +1.1468% +1.8402] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 16 outliers among 100 measurements (16.00%)
2 (2.00%) low mild
14 (14.00%) high severe
streams/walltime/1000-streams/each-1-bytes: Change within noise threshold.
       time:   [12.430 ms 12.451 ms 12.473 ms]
       change: [+0.3085% +0.7733% +1.1301] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
streams/walltime/1000-streams/each-1000-bytes: No change in performance detected.
       time:   [44.712 ms 44.807 ms 44.957 ms]
       change: [-0.3287% -0.0829% +0.2467] (p = 0.66 > 0.05)
       No change in performance detected.
Found 4 outliers among 100 measurements (4.00%)
1 (1.00%) low mild
2 (2.00%) high mild
1 (1.00%) high severe
transfer/walltime/pacing-false/varying-seeds: Change within noise threshold.
       time:   [78.912 ms 79.019 ms 79.172 ms]
       change: [+1.3339% +1.4967% +1.7261] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 6 outliers among 100 measurements (6.00%)
1 (1.00%) low mild
3 (3.00%) high mild
2 (2.00%) high severe
transfer/walltime/pacing-true/varying-seeds: Change within noise threshold.
       time:   [80.308 ms 80.406 ms 80.543 ms]
       change: [+0.9533% +1.1907% +1.4058] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high severe
transfer/walltime/pacing-false/same-seed: 💔 Performance has regressed by +3.2665%.
       time:   [80.279 ms 80.340 ms 80.406 ms]
       change: [+3.0475% +3.2665% +3.4320] (p = 0.00 < 0.05)
       Performance has regressed.
Found 4 outliers among 100 measurements (4.00%)
2 (2.00%) high mild
2 (2.00%) high severe
transfer/walltime/pacing-true/same-seed: Change within noise threshold.
       time:   [80.345 ms 80.450 ms 80.605 ms]
       change: [+0.9532% +1.1326% +1.3631] (p = 0.00 < 0.05)
       Change within noise threshold.
Found 4 outliers among 100 measurements (4.00%)
2 (2.00%) high mild
2 (2.00%) high severe

Download data for profiler.firefox.com or download performance comparison data.

@github-actions
Copy link
Copy Markdown
Contributor

Failed Interop Tests

QUIC Interop Runner, client vs. server, differences relative to main at bf77765.

neqo-pr as clientneqo-pr as server
neqo-pr vs. go-x-net: BP BA
neqo-pr vs. haproxy: 🚀M ⚠️C1 BP BA
neqo-pr vs. kwik: S L1 C1 BP BA
neqo-pr vs. linuxquic: run cancelled after 20 min
neqo-pr vs. lsquic: L1 C1
neqo-pr vs. msquic: A L1 C1
neqo-pr vs. mvfst: H DC LR M R Z 3 B U A L1 L2 C1 C2 6 BP BA
neqo-pr vs. neqo: Z A
neqo-pr vs. nginx: ⚠️C1 BP BA
neqo-pr vs. ngtcp2: CM
neqo-pr vs. picoquic: A
neqo-pr vs. quic-go: A
neqo-pr vs. quiche: BP BA
neqo-pr vs. s2n-quic: BA CM
neqo-pr vs. tquic: S BP BA
neqo-pr vs. xquic: A 🚀C1 BA
aioquic vs. neqo-pr: Z 🚀L1 CM
go-x-net vs. neqo-pr: CM
kwik vs. neqo-pr: Z BP BA CM
linuxquic vs. neqo-pr: Z
lsquic vs. neqo-pr: Z
msquic vs. neqo-pr: Z 🚀BP BA CM
mvfst vs. neqo-pr: Z A L1 C1 CM
neqo vs. neqo-pr: Z A
openssl vs. neqo-pr: LR M A CM
picoquic vs. neqo-pr: Z CM
quic-go vs. neqo-pr: CM
quiche vs. neqo-pr: Z CM
quinn vs. neqo-pr: Z V2 CM
s2n-quic vs. neqo-pr: ⚠️B CM
tquic vs. neqo-pr: Z CM
xquic vs. neqo-pr: M CM
All results

Succeeded Interop Tests

QUIC Interop Runner, client vs. server

neqo-pr as client

neqo-pr as server

Unsupported Interop Tests

QUIC Interop Runner, client vs. server

neqo-pr as client

neqo-pr as server

Merged via the queue into mozilla:main with commit 07f7838 Mar 16, 2026
176 of 178 checks passed
@omansfeld omansfeld deleted the hystart_metrics branch March 16, 2026 11:51
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.

3 participants