Skip to content

Commit

Permalink
Apply black_box to known bench inputs (#151)
Browse files Browse the repository at this point in the history
This has the effect of slowing down many of the benchmarks, which
implies that the compiler has been able to constant-fold some of the
computations.

Signed-off-by: Andrew Aylett <andrew@aylett.co.uk>
Co-authored-by: Sean McArthur <sean@seanmonstar.com>
  • Loading branch information
andrewaylett and seanmonstar committed Jan 29, 2024
1 parent d596c9d commit 1f7b2a4
Showing 1 changed file with 67 additions and 52 deletions.
119 changes: 67 additions & 52 deletions benches/parse.rs
@@ -1,7 +1,6 @@

use std::time::Duration;

use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput, BatchSize};

const REQ_SHORT: &[u8] = b"\
GET / HTTP/1.0\r\n\
Expand All @@ -21,25 +20,37 @@ Connection: keep-alive\r\n\
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n";

fn req(c: &mut Criterion) {
let mut headers = [httparse::Header{ name: "", value: &[] }; 16];
let mut req = httparse::Request::new(&mut headers);

c.benchmark_group("req")
.throughput(Throughput::Bytes(REQ.len() as u64))
.bench_function("req", |b| b.iter(|| {
assert_eq!(black_box(req.parse(REQ).unwrap()), httparse::Status::Complete(REQ.len()));
}));
.bench_function("req", |b| b.iter_batched_ref(|| {
[httparse::Header {
name: "",
value: &[],
}; 16]
},|headers| {
let mut req = httparse::Request::new(headers);
assert_eq!(
black_box(req.parse(REQ).unwrap()),
httparse::Status::Complete(REQ.len())
);
}, BatchSize::SmallInput));
}

fn req_short(c: &mut Criterion) {
let mut headers = [httparse::Header{ name: "", value: &[] }; 16];
let mut req = httparse::Request::new(&mut headers);

c.benchmark_group("req_short")
.throughput(Throughput::Bytes(REQ_SHORT.len() as u64))
.bench_function("req_short", |b| b.iter(|| {
assert_eq!(black_box(req.parse(REQ_SHORT).unwrap()), httparse::Status::Complete(REQ_SHORT.len()));
}));
.bench_function("req_short", |b| b.iter_batched_ref(|| {
[httparse::Header {
name: "",
value: &[],
}; 16]
},|headers| {
let mut req = httparse::Request::new(headers);
assert_eq!(
req.parse(black_box(REQ_SHORT)).unwrap(),
httparse::Status::Complete(REQ_SHORT.len())
);
}, BatchSize::SmallInput));
}

const RESP_SHORT: &[u8] = b"\
Expand All @@ -62,43 +73,54 @@ Connection: keep-alive\r\n\
Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; __utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; __utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral|padding=under256\r\n\r\n";

fn resp(c: &mut Criterion) {
let mut headers = [httparse::Header{ name: "", value: &[] }; 16];
let mut resp = httparse::Response::new(&mut headers);

c.benchmark_group("resp")
.throughput(Throughput::Bytes(RESP.len() as u64))
.bench_function("resp", |b| b.iter(|| {
assert_eq!(black_box(resp.parse(RESP).unwrap()), httparse::Status::Complete(RESP.len()));
}));
.bench_function("resp", |b| b.iter_batched_ref(|| {
[httparse::Header {
name: "",
value: &[],
}; 16]
}, |headers| {
let mut resp = httparse::Response::new(headers);
assert_eq!(
resp.parse(black_box(RESP)).unwrap(),
httparse::Status::Complete(RESP.len())
);
}, BatchSize::SmallInput));
}

fn resp_short(c: &mut Criterion) {
let mut headers = [httparse::Header{ name: "", value: &[] }; 16];
let mut resp = httparse::Response::new(&mut headers);

c.benchmark_group("resp_short")
.throughput(Throughput::Bytes(RESP_SHORT.len() as u64))
.bench_function("resp_short", |b| b.iter(|| {
assert_eq!(black_box(resp.parse(RESP_SHORT).unwrap()), httparse::Status::Complete(RESP_SHORT.len()));
}));
.bench_function("resp_short", |b| b.iter_batched_ref(|| {
[httparse::Header {
name: "",
value: &[],
}; 16]
},
|headers| {
let mut resp = httparse::Response::new(headers);
assert_eq!(
resp.parse(black_box(RESP_SHORT)).unwrap(),
httparse::Status::Complete(RESP_SHORT.len())
);
}, BatchSize::SmallInput));
}

fn uri(c: &mut Criterion) {
fn _uri(c: &mut Criterion, name: &str, input: &'static [u8]) {
c.benchmark_group("uri")
.throughput(Throughput::Bytes(input.len() as u64))
.bench_function(name, |b| b.iter(|| {
black_box({
let mut b = httparse::_benchable::Bytes::new(input);
httparse::_benchable::parse_uri(&mut b).unwrap()
});
let mut b = httparse::_benchable::Bytes::new(black_box(input));
httparse::_benchable::parse_uri(&mut b).unwrap()
}));
}

const S: &[u8] = b" ";
const CHUNK64: &[u8] = b"/wp-content/uploads/2022/08/31/hello-kitty-darth-vader-pink.webp";
let chunk_4k = CHUNK64.repeat(64);

// 1b to 4096b
for p in 0..=12 {
let n = 1 << p;
Expand All @@ -108,37 +130,34 @@ fn uri(c: &mut Criterion) {

fn header(c: &mut Criterion) {
fn _header(c: &mut Criterion, name: &str, input: &'static [u8]) {
let mut headers = [httparse::EMPTY_HEADER; 128];
c.benchmark_group("header")
.throughput(Throughput::Bytes(input.len() as u64))
.bench_function(name, |b| b.iter(|| {
{
let _ = httparse::parse_headers(input, &mut headers).unwrap();
};
black_box(());
}));
.bench_function(name, |b| b.iter_batched_ref(|| [httparse::EMPTY_HEADER; 128],|headers| {
let status = httparse::parse_headers(black_box(input), headers).unwrap();
black_box(status.unwrap()).0
}, BatchSize::SmallInput));
}

const RN: &[u8] = b"\r\n";
const RNRN: &[u8] = b"\r\n\r\n";
const TINY_RN: &[u8] = b"a: b\r\n"; // minimal header line
const XFOOBAR: &[u8] = b"X-Foobar";
let xfoobar_4k = XFOOBAR.repeat(4096/XFOOBAR.len());

// header names 1b to 4096b
for p in 0..=12 {
let n = 1 << p;
let payload = [&xfoobar_4k[..n], b": b", RNRN].concat().leak();
_header(c, &format!("name_{}b", n), payload);
}

// header values 1b to 4096b
for p in 0..=12 {
let n = 1 << p;
let payload = [b"a: ", &xfoobar_4k[..n], RNRN].concat().leak();
_header(c, &format!("value_{}b", n), payload);
}

// 1 to 128
for p in 0..=7 {
let n = 1 << p;
Expand All @@ -151,13 +170,11 @@ fn version(c: &mut Criterion) {
c.benchmark_group("version")
.throughput(Throughput::Bytes(input.len() as u64))
.bench_function(name, |b| b.iter(|| {
black_box({
let mut b = httparse::_benchable::Bytes::new(input);
httparse::_benchable::parse_version(&mut b).unwrap()
});
let mut b = httparse::_benchable::Bytes::new(black_box(input));
httparse::_benchable::parse_version(&mut b).unwrap()
}));
}

_version(c, "http10", b"HTTP/1.0\r\n");
_version(c, "http11", b"HTTP/1.1\r\n");
_version(c, "partial", b"HTTP/1.");
Expand All @@ -168,13 +185,11 @@ fn method(c: &mut Criterion) {
c.benchmark_group("method")
.throughput(Throughput::Bytes(input.len() as u64))
.bench_function(name, |b| b.iter(|| {
black_box({
let mut b = httparse::_benchable::Bytes::new(input);
httparse::_benchable::parse_method(&mut b).unwrap()
});
let mut b = httparse::_benchable::Bytes::new(black_box(input));
httparse::_benchable::parse_method(&mut b).unwrap()
}));
}

// Common methods should be fast-pathed
const COMMON_METHODS: &[&str] = &["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"];
for method in COMMON_METHODS {
Expand Down

0 comments on commit 1f7b2a4

Please sign in to comment.