Skip to content

Commit

Permalink
Merge branch 'feat-more-ecn' of github.com:larseggert/neqo into feat-…
Browse files Browse the repository at this point in the history
…more-ecn
  • Loading branch information
larseggert committed Mar 26, 2024
2 parents 3ee0b93 + cd3d937 commit 7a11060
Show file tree
Hide file tree
Showing 47 changed files with 669 additions and 479 deletions.
6 changes: 2 additions & 4 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# neqo has no test coverage for its example client, server and interop test
# neqo has no test coverage for its example client and server
ignore:
- "neqo-client"
- "neqo-interop"
- "neqo-server"
- "neqo-bin"

# Do not notify until at least three results have been uploaded from the CI pipeline.
# (This corresponds to the three main platforms we support: Linux, macOS, and Windows.)
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/rust/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ runs:

- name: Install Rust tools
shell: bash
run: cargo +${{ inputs.version }} binstall --no-confirm cargo-llvm-cov cargo-nextest flamegraph cargo-hack cargo-mutants
run: cargo +${{ inputs.version }} binstall --no-confirm cargo-llvm-cov cargo-nextest flamegraph cargo-hack cargo-mutants hyperfine

# sccache slows CI down, so we leave it disabled.
# Leaving the steps below commented out, so we can re-evaluate enabling it later.
Expand Down
170 changes: 119 additions & 51 deletions .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ name: Bench
on:
workflow_call:
workflow_dispatch:
schedule:
# Run at 1 AM each day, so there is a `main`-branch baseline in the cache.
- cron: '0 1 * * *'
env:
CARGO_PROFILE_BENCH_BUILD_OVERRIDE_DEBUG: true
CARGO_PROFILE_RELEASE_DEBUG: true
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
TOOLCHAIN: nightly
RUSTFLAGS: -C link-arg=-fuse-ld=lld -C link-arg=-Wl,--no-rosegment, -C force-frame-pointers=yes
PERF_CMD: record -o perf.data -F997 --call-graph fp -g
PERF_OPT: record -F997 --call-graph fp -g

jobs:
bench:
Expand All @@ -20,9 +23,17 @@ jobs:
shell: bash

steps:
- name: Checkout
- name: Checkout neqo
uses: actions/checkout@v4

- name: Checkout msquic
uses: actions/checkout@v4
with:
repository: microsoft/msquic
ref: main
path: msquic
submodules: true

- name: Set PATH
run: echo "/home/bench/.cargo/bin" >> "${GITHUB_PATH}"

Expand All @@ -35,10 +46,17 @@ jobs:
- name: Fetch and build NSS and NSPR
uses: ./.github/actions/nss

- name: Build
- name: Build neqo
run: |
cargo "+$TOOLCHAIN" bench --features bench --no-run
cargo "+$TOOLCHAIN" build --release --bin neqo-client --bin neqo-server
cargo "+$TOOLCHAIN" build --release
- name: Build msquic
run: |
mkdir -p msquic/build
cd msquic/build
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DQUIC_BUILD_TOOLS=1 -DQUIC_BUILD_PERF=1 ..
cmake --build .
- name: Download cached main-branch results
id: criterion-cache
Expand All @@ -58,71 +76,115 @@ jobs:
taskset -c 0 nice -n -20 \
cargo "+$TOOLCHAIN" bench --features bench -- --noplot | tee results.txt
# Pin the transfer benchmark to core 0 and run it at elevated priority inside perf.
# Work around https://github.com/flamegraph-rs/flamegraph/issues/248 by passing explicit perf arguments.
- name: Profile cargo bench transfer
run: |
# This re-runs part of the previous step, and would hence overwrite part of the criterion results.
# Avoid that by shuffling the directories around so this run uses its own results directory.
mv target/criterion target/criterion-bench
mv target/criterion-transfer-profile target/criterion || true
taskset -c 0 nice -n -20 \
cargo "+$TOOLCHAIN" flamegraph -v -c "$PERF_CMD" --features bench --bench transfer -- \
--bench --exact "Run multiple transfers with varying seeds" --noplot
# And now restore the directories.
mv target/criterion target/criterion-transfer-profile
mv target/criterion-bench target/criterion
- name: Profile client/server transfer
run: |
{ mkdir server; \
cd server; \
taskset -c 0 nice -n -20 \
cargo "+$TOOLCHAIN" flamegraph -v -c "$PERF_CMD" \
--bin neqo-server -- --db ../test-fixture/db "$HOST:4433" || true; } &
mkdir client; \
cd client; \
time taskset -c 1 nice -n -20 \
cargo "+$TOOLCHAIN" flamegraph -v -c "$PERF_CMD" \
--bin neqo-client -- --output-dir . "https://$HOST:4433/$SIZE"
killall -INT neqo-server
cd ${{ github.workspace }}
[ "$(wc -c < client/"$SIZE")" -eq "$SIZE" ] || exit 1
# Compare various configurations of neqo against msquic, and gather perf data
# during the hyperfine runs.
- name: Compare neqo and msquic
env:
HOST: localhost
SIZE: 1073741824 # 1 GB
HOST: 127.0.0.1
PORT: 4433
SIZE: 134217728 # 128 MB
run: |
TMP=$(mktemp -d)
# Make a cert and key for msquic.
openssl req -nodes -new -x509 -keyout "$TMP/key" -out "$TMP/cert" -subj "/CN=DOMAIN" 2>/dev/null
# Make a test file for msquic to serve.
truncate -s "$SIZE" "$TMP/$SIZE"
# Define the commands to run for each client and server.
declare -A client_cmd=(
["neqo"]="target/release/neqo-client _cc _pacing --output-dir . -o -a hq-interop -Q 1 https://$HOST:$PORT/$SIZE"
["msquic"]="msquic/build/bin/Release/quicinterop -test:D -custom:$HOST -port:$PORT -urls:https://$HOST:$PORT/$SIZE"
)
declare -A server_cmd=(
["neqo"]="target/release/neqo-server _cc _pacing -o -a hq-interop -Q 1 $HOST:$PORT 2> /dev/null"
["msquic"]="msquic/build/bin/Release/quicinteropserver -root:$TMP -listen:$HOST -port:$PORT -file:$TMP/cert -key:$TMP/key -noexit > /dev/null || true"
)
# Replace various placeholders in the commands with the actual values.
# Also generate an extension to append to the file name.
function transmogrify {
CMD=$1
local cc=$2
local pacing=$3
if [ "$cc" != "" ]; then
CMD=${CMD//_cc/--cc $cc}
EXT="-$cc"
fi
if [ "$pacing" == "on" ]; then
CMD=${CMD//_pacing/}
EXT="$EXT-pacing"
else
CMD=${CMD//_pacing/--no-pacing}
EXT="$EXT-nopacing"
fi
}
for server in msquic neqo; do
for client in msquic neqo; do
# msquic doesn't let us configure the congestion control or pacing.
if [ "$client" == "msquic" ] && [ "$server" == "msquic" ]; then
cc_opt=("")
pacing_opt=("")
else
cc_opt=("reno" "cubic")
pacing_opt=("on" "")
fi
for cc in "${cc_opt[@]}"; do
for pacing in "${pacing_opt[@]}"; do
# Make a tag string for this test, for the results.
TAG="$client,$server,$cc,$pacing"
echo "Running benchmarks for $TAG" | tee -a comparison.txt
transmogrify "${server_cmd[$server]}" "$cc" "$pacing"
# shellcheck disable=SC2086
taskset -c 0 nice -n -20 \
perf $PERF_OPT -o "$client-$server$EXT.server.perf" $CMD &
PID=$!
transmogrify "${client_cmd[$client]}" "$cc" "$pacing"
# shellcheck disable=SC2086
taskset -c 1 nice -n -20 \
perf $PERF_OPT -o "$client-$server$EXT.client.perf" \
hyperfine -N --output null -w 1 -s "sleep 1" -n "$TAG" -u millisecond --export-markdown step.md "$CMD" |
tee -a comparison.txt
echo >> comparison.txt
kill $PID
cat step.md >> steps.md
# Sanity check the size of the last retrieved file.
[ "$(wc -c <"$SIZE")" -eq "$SIZE" ] || exit 1
done
done
done
done
# Merge the results tables generated by hyperfine into a single table.
echo "Transfer of $SIZE bytes over loopback." > comparison.md
awk '(!/^\| Command/ || !c++) && (!/^\|:/ || !d++)' < steps.md |\
sed -E 's/`//g; s/^\|:/\|:---\|:---\|:---\|:/g; s/,/ \| /g; s/^\| Command/\| Client \| Server \| CC \| Pacing/g' >> comparison.md
rm -r "$TMP"
# Re-enable turboboost, hyperthreading and use powersave governor.
- name: Restore machine
run: sudo /root/bin/unprep.sh
if: success() || failure() || cancelled()

- name: Convert for profiler.firefox.com
- name: Post-process perf data
run: |
perf script -i perf.data -F +pid > transfer.perf &
perf script -i client/perf.data -F +pid > client.perf &
perf script -i server/perf.data -F +pid > server.perf &
for f in *.perf; do
# Convert for profiler.firefox.com
perf script -i "$f" -F +pid > "$f.fx" &
# Generate perf reports
perf report -i "$f" --no-children --stdio > "$f.txt" &
# Generate flamegraphs
flamegraph --perfdata "$f" --palette rust -o "${f//.perf/.svg}" &
done
wait
mv flamegraph.svg transfer.svg
mv client/flamegraph.svg client.svg
mv server/flamegraph.svg server.svg
rm neqo.svg
- name: Generate perf reports
run: |
perf report -i perf.data --no-children --stdio > transfer.perf.txt &
perf report -i client/perf.data --no-children --stdio > client.perf.txt &
perf report -i server/perf.data --no-children --stdio > server.perf.txt &
wait
- name: Format results as Markdown
id: results
run: |
{
echo "### Benchmark results"
echo
} > results.md
SHA=$(cat target/criterion/baseline-sha.txt)
SHA=$(cat target/criterion/baseline-sha.txt || true)
if [ -n "$SHA" ]; then
{
echo "Performance differences relative to $SHA."
Expand All @@ -136,6 +198,11 @@ jobs:
-e 's/^([a-z0-9].*)$/* **\1**/gi' \
-e 's/(change:[^%]*% )([^%]*%)(.*)/\1**\2**\3/gi' \
>> results.md
{
echo "### Client/server transfer results"
cat comparison.md
} >> results.md
cat results.md > "$GITHUB_STEP_SUMMARY"
- name: Remember main-branch push URL
if: github.ref == 'refs/heads/main'
Expand All @@ -162,6 +229,7 @@ jobs:
path: |
*.svg
*.perf
*.perf.fx
*.txt
results.*
target/criterion*
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
- name: Run tests and determine coverage
run: |
# shellcheck disable=SC2086
cargo +${{ matrix.rust-toolchain }} llvm-cov nextest $BUILD_TYPE --all-targets --features ci --no-fail-fast --lcov --output-path lcov.info
cargo +${{ matrix.rust-toolchain }} llvm-cov nextest $BUILD_TYPE --features ci --no-fail-fast --lcov --output-path lcov.info
cargo +${{ matrix.rust-toolchain }} bench --features bench --no-run
- name: Run client/server transfer
Expand All @@ -122,6 +122,8 @@ jobs:
cargo +${{ matrix.rust-toolchain }} build $BUILD_TYPE --bin neqo-client --bin neqo-server
"target/$BUILD_DIR/neqo-server" "$HOST:4433" &
PID=$!
# Give the server time to start.
sleep 1
"target/$BUILD_DIR/neqo-client" --output-dir . "https://$HOST:4433/$SIZE"
kill $PID
[ "$(wc -c <"$SIZE")" -eq "$SIZE" ] || exit 1
Expand All @@ -146,7 +148,7 @@ jobs:
# respective default features only. Can reveal warnings otherwise
# hidden given that a plain cargo clippy combines all features of the
# workspace. See e.g. https://github.com/mozilla/neqo/pull/1695.
cargo +${{ matrix.rust-toolchain }} hack clippy --all-targets -- -D warnings || ${{ matrix.rust-toolchain == 'nightly' }}
cargo +${{ matrix.rust-toolchain }} hack clippy --all-targets --feature-powerset --exclude-features gecko -- -D warnings || ${{ matrix.rust-toolchain == 'nightly' }}
if: success() || failure()

- name: Check rustdoc links
Expand Down
29 changes: 21 additions & 8 deletions .github/workflows/mutants.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
name: Find mutants
on:
schedule:
- cron: '42 3 * * 2,5' # Runs at 03:42 UTC (m and h chosen arbitrarily) twice a week.
workflow_dispatch:
pull_request:
branches: ["main"]
paths-ignore: ["*.md", "*.png", "*.svg", "LICENSE-*"]
Expand All @@ -9,16 +12,13 @@ concurrency:
cancel-in-progress: true

jobs:
incremental-mutants:
mutants:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Relative diff
run: git diff origin/${{ github.base_ref }}.. > pr.diff

- name: Install dependencies
env:
DEBIAN_FRONTEND: noninteractive
Expand All @@ -34,16 +34,29 @@ jobs:
with:
version: stable

- name: Mutants
- name: Find incremental mutants
if: github.event_name == 'pull_request'
run: |
# Don't fail the build if mutants fail, for now.
git diff origin/${{ github.base_ref }}.. > pr.diff
set -o pipefail
cargo mutants --test-tool=nextest --no-shuffle -j 2 -vV --in-diff pr.diff | tee results.txt || true
echo 'TITLE=Incremental Mutants' >> "$GITHUB_ENV"
- name: Find mutants
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
run: |
set -o pipefail
cargo mutants --test-tool=nextest -vV --in-place | tee results.txt || true
echo 'TITLE=All Mutants' >> "$GITHUB_ENV"
- name: Post step summary
if: always()
run: |
{
echo "### Mutants"
echo "### $TITLE"
echo "See https://mutants.rs/using-results.html for more information."
echo '```'
cat results.txt
sed 's/\x1b\[[0-9;]*[mGKHF]//g' results.txt
echo '```'
} > "$GITHUB_STEP_SUMMARY"
Expand Down
13 changes: 5 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/target/
**/*.rs.bk
Cargo.lock
/db
.DS_Store
*.qlog
*~
/.vscode/
.idea
*.qlog
*.swp
/qns/.last-update-*
/lcov.info
/target/
Cargo.lock
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ rust-version = "1.74.0"
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -1 }

[profile.release]
lto = "fat"

[profile.bench]
# Inherits from the "release" profile, so just provide overrides here:
# https://doc.rust-lang.org/cargo/reference/profiles.html#release
Expand Down
4 changes: 3 additions & 1 deletion neqo-bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ workspace = true
[dependencies]
# neqo-bin is not used in Firefox, so we can be liberal with dependency versions
clap = { version = "4.4", default-features = false, features = ["std", "color", "help", "usage", "error-context", "suggestions", "derive"] }
clap-verbosity-flag = { version = "2.2", default-features = false }
futures = { version = "0.3", default-features = false, features = ["alloc"] }
hex = { version = "0.4", default-features = false, features = ["std"] }
log = { version = "0.4", default-features = false }
neqo-common = { path = "./../neqo-common", features = ["udp"] }
neqo-common = { path = "./../neqo-common" }
neqo-crypto = { path = "./../neqo-crypto" }
neqo-http3 = { path = "./../neqo-http3" }
neqo-qpack = { path = "./../neqo-qpack" }
neqo-transport = { path = "./../neqo-transport" }
qlog = { version = "0.12", default-features = false }
quinn-udp = { git = "https://github.com/quinn-rs/quinn/", rev = "a947962131aba8a6521253d03cc948b20098a2d6" }
regex = { version = "1.9", default-features = false, features = ["unicode-perl"] }
tokio = { version = "1", default-features = false, features = ["net", "time", "macros", "rt", "rt-multi-thread"] }
url = { version = "2.5", default-features = false }
Expand Down
Loading

0 comments on commit 7a11060

Please sign in to comment.