Skip to content

Commit

Permalink
Merge pull request #220 from bearcove/h2load
Browse files Browse the repository at this point in the history
feat: Run h2load in CI
  • Loading branch information
fasterthanlime authored Aug 15, 2024
2 parents 26faf62 + de1d1ce commit 44f643d
Show file tree
Hide file tree
Showing 9 changed files with 341 additions and 148 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ jobs:
cache-target: release
bins: cargo-codspeed

- name: Install h2load
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo apt-get install -y nghttp2-client
- name: Build the benchmark target(s)
run: cargo codspeed build

Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ httpwg-over-tcp *args='':
--package httpwg-cli
export TEST_PROTO=h2
export PORT=8001
export RUST_LOG=${RUST_LOG:-info}
./target/release/httpwg --address localhost:8001 "$@" -- ./target/release/httpwg-loona

instruments:
Expand Down
6 changes: 5 additions & 1 deletion crates/buffet/src/net/net_uring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,17 @@ impl TcpListener {
pub async fn bind(addr: SocketAddr) -> std::io::Result<Self> {
let addr: socket2::SockAddr = addr.into();
let socket = socket2::Socket::new(addr.domain(), socket2::Type::STREAM, None)?;

socket.set_nodelay(true)?;

// FIXME: don't hardcode
socket.set_reuse_port(true)?;
socket.set_reuse_address(true)?;
socket.bind(&addr)?;

// FIXME: magic values
socket.listen(16)?;
socket.listen(256)?;

let fd = socket.as_raw_fd();
std::mem::forget(socket);

Expand Down
66 changes: 44 additions & 22 deletions crates/httpwg-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ struct Args {
/// the timeout for connections (in milliseconds)
connect_timeout: Option<u64>,

/// the timeout to wait for a frame (in milliseconds)
frame_timeout: Option<u64>,

/// which tests to run
filter: Option<String>,

Expand Down Expand Up @@ -60,7 +63,16 @@ fn parse_args() -> eyre::Result<Args> {
}
});
}
lexopt::Arg::Long("connect-timeout") | lexopt::Arg::Short('t') => {
lexopt::Arg::Long("frame-timeout") => {
args.frame_timeout = Some(
parser
.value()?
.into_string_result()?
.parse()
.map_err(|e| eyre::eyre!("Failed to parse frame timeout: {}", e))?,
);
}
lexopt::Arg::Long("connect-timeout") => {
args.connect_timeout = Some(
parser
.value()?
Expand Down Expand Up @@ -90,7 +102,8 @@ fn print_usage() -> eyre::Result<()> {
Options:
-a, --address <ADDRESS> The address/port the server will listen on
-t, --connect-timeout <MS> The timeout for connections in milliseconds
--connect-timeout <MS> The timeout for connections in milliseconds
--frame-timeout <MS> The timeout to wait for a frame in milliseconds
-f, --filter <FILTER> Which tests to run
-v, --verbose Print verbose output
Expand Down Expand Up @@ -137,12 +150,16 @@ async fn async_main(mut args: Args) -> eyre::Result<()> {
Some(timeout) => Duration::from_millis(timeout),
None => Duration::from_millis(250),
};
let frame_timeout = match args.frame_timeout {
Some(timeout) => Duration::from_millis(timeout),
None => Duration::from_millis(250),
};
let conf = Rc::new(Config {
timeout: connect_timeout,
timeout: frame_timeout,
..Default::default()
});

eprintln!("Will run tests against {addr} with a connect timeout of {connect_timeout:?}");
eprintln!("Will run tests against {addr}");

// this works around an oddity of Just when forwarding positional arguments
args.server_binary.retain(|s| !s.is_empty());
Expand Down Expand Up @@ -186,18 +203,21 @@ async fn async_main(mut args: Args) -> eyre::Result<()> {
eprintln!("No server binary specified");
};

eprintln!("Waiting until server is listening on {addr}");
let max_startup_time = Duration::from_secs(1);
let sleep_time = Duration::from_millis(100);
eprintln!("Waiting until server is listening on {addr} (up to {max_startup_time:?})");
let start = std::time::Instant::now();
let duration = Duration::from_secs(1);
while start.elapsed() < duration {
match tokio::time::timeout(Duration::from_millis(100), TcpStream::connect(addr)).await {
loop {
match tokio::time::timeout(sleep_time, TcpStream::connect(addr)).await {
Ok(Ok(_)) => break,
_ => tokio::time::sleep(Duration::from_millis(100)).await,
_ => {
if start.elapsed() >= max_startup_time {
panic!("Server did not start listening within {max_startup_time:?}");
}
tokio::time::sleep(sleep_time).await
}
}
}
if start.elapsed() >= duration {
panic!("Server did not start listening within 3 seconds");
}

let mut local_set = tokio::task::LocalSet::new();

Expand All @@ -221,13 +241,18 @@ async fn async_main(mut args: Args) -> eyre::Result<()> {
}

num_tests += 1;
let stream =
tokio::time::timeout(Duration::from_millis(250), TcpStream::connect(addr))
.await
.unwrap()
.unwrap();
let stream = tokio::time::timeout(connect_timeout, TcpStream::connect(addr))
.await
.unwrap_or_else(|_| {
panic!(
"tested server failed to accept connction within {connect_timeout:?}"
)
})
.unwrap();
eprintln!("Holding {num_tests} connections");
let conn = Conn::new(conf.clone(), stream);
let num_passed = num_passed.clone();

let test = async move {
if args.verbose {
eprintln!("🔷 Running test: {}", test_name);
Expand All @@ -244,18 +269,15 @@ async fn async_main(mut args: Args) -> eyre::Result<()> {
}
}
};
local_set.spawn_local(async move {
{
test.await;
}
});
local_set.spawn_local(test);
if sequential {
(&mut local_set).await;
}
}
}
}

eprintln!("Awaiting local set");
local_set.await;
let num_passed = *num_passed.borrow();

Expand Down
16 changes: 16 additions & 0 deletions crates/httpwg-loona/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,25 @@ description = """
A reference HTTP 1+2 server for httpwg, powered by loona
"""

[lib]
name = "httpwg_loona"
path = "src/lib.rs"

[[bin]]
name = "httpwg-loona"
path = "src/main.rs"

[[bench]]
name = "h2load"
harness = false

[dependencies]
color-eyre = "0.6.3"
loona = { version = "0.2.1", path = "../loona" }
buffet = { version = "0.2.1", path = "../buffet" }
tracing = { version = "0.1.40", features = ["release_max_level_debug"] }
tracing-subscriber = "0.3.18"
tokio = { version = "1.39.2", features = ["macros", "sync", "process"] }

[dev-dependencies]
codspeed-criterion-compat = "2.6.0"
13 changes: 13 additions & 0 deletions crates/httpwg-loona/benches/h2load.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
use httpwg_loona::{Mode, Proto};

pub fn h2load(c: &mut Criterion) {
c.bench_function("h2load", |b| {
b.iter(|| {
httpwg_loona::do_main(0, Proto::H2, Mode::H2Load);
})
});
}

criterion_group!(benches, h2load);
criterion_main!(benches);
Loading

0 comments on commit 44f643d

Please sign in to comment.