From 4131786127bb1633a2731108195055b52d7a8cf6 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sat, 11 Mar 2023 23:20:02 +0000 Subject: [PATCH] remove old benchmarks --- actix-http/Cargo.toml | 16 -- actix-http/benches/quality-value.rs | 97 ----------- actix-http/benches/status-line.rs | 214 ------------------------- actix-http/benches/uninit-headers.rs | 135 ---------------- actix-http/benches/write-camel-case.rs | 93 ----------- 5 files changed, 555 deletions(-) delete mode 100644 actix-http/benches/quality-value.rs delete mode 100644 actix-http/benches/status-line.rs delete mode 100644 actix-http/benches/uninit-headers.rs delete mode 100644 actix-http/benches/write-camel-case.rs diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 07e412a2c..ce653f440 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -124,19 +124,3 @@ tokio = { version = "1.24.2", features = ["net", "rt", "macros"] } [[example]] name = "ws" required-features = ["ws", "rustls"] - -[[bench]] -name = "write-camel-case" -harness = false - -[[bench]] -name = "status-line" -harness = false - -[[bench]] -name = "uninit-headers" -harness = false - -[[bench]] -name = "quality-value" -harness = false diff --git a/actix-http/benches/quality-value.rs b/actix-http/benches/quality-value.rs deleted file mode 100644 index 0ed274ded..000000000 --- a/actix-http/benches/quality-value.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![allow(clippy::uninlined_format_args)] - -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; - -const CODES: &[u16] = &[0, 1000, 201, 800, 550]; - -fn bench_quality_display_impls(c: &mut Criterion) { - let mut group = c.benchmark_group("quality value display impls"); - - for i in CODES.iter() { - group.bench_with_input(BenchmarkId::new("New (fast?)", i), i, |b, &i| { - b.iter(|| _new::Quality(i).to_string()) - }); - - group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| { - b.iter(|| _naive::Quality(i).to_string()) - }); - } - - group.finish(); -} - -criterion_group!(benches, bench_quality_display_impls); -criterion_main!(benches); - -mod _new { - use std::fmt; - - pub struct Quality(pub(crate) u16); - - impl fmt::Display for Quality { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - 0 => f.write_str("0"), - 1000 => f.write_str("1"), - - // some number in the range 1–999 - x => { - f.write_str("0.")?; - - // this implementation avoids string allocation otherwise required - // for `.trim_end_matches('0')` - - if x < 10 { - f.write_str("00")?; - // 0 is handled so it's not possible to have a trailing 0, we can just return - itoa_fmt(f, x) - } else if x < 100 { - f.write_str("0")?; - if x % 10 == 0 { - // trailing 0, divide by 10 and write - itoa_fmt(f, x / 10) - } else { - itoa_fmt(f, x) - } - } else { - // x is in range 101–999 - - if x % 100 == 0 { - // two trailing 0s, divide by 100 and write - itoa_fmt(f, x / 100) - } else if x % 10 == 0 { - // one trailing 0, divide by 10 and write - itoa_fmt(f, x / 10) - } else { - itoa_fmt(f, x) - } - } - } - } - } - } - - pub fn itoa_fmt(mut wr: W, value: V) -> fmt::Result { - let mut buf = itoa::Buffer::new(); - wr.write_str(buf.format(value)) - } -} - -mod _naive { - use std::fmt; - - pub struct Quality(pub(crate) u16); - - impl fmt::Display for Quality { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - 0 => f.write_str("0"), - 1000 => f.write_str("1"), - - x => { - write!(f, "{}", format!("{:03}", x).trim_end_matches('0')) - } - } - } - } -} diff --git a/actix-http/benches/status-line.rs b/actix-http/benches/status-line.rs deleted file mode 100644 index 9fe099478..000000000 --- a/actix-http/benches/status-line.rs +++ /dev/null @@ -1,214 +0,0 @@ -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; - -use bytes::BytesMut; -use http::Version; - -const CODES: &[u16] = &[201, 303, 404, 515]; - -fn bench_write_status_line_11(c: &mut Criterion) { - let mut group = c.benchmark_group("write_status_line v1.1"); - - let version = Version::HTTP_11; - - for i in CODES.iter() { - group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _original::write_status_line(version, i, &mut b); - }) - }); - - group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _new::write_status_line(version, i, &mut b); - }) - }); - - group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _naive::write_status_line(version, i, &mut b); - }) - }); - } - - group.finish(); -} - -fn bench_write_status_line_10(c: &mut Criterion) { - let mut group = c.benchmark_group("write_status_line v1.0"); - - let version = Version::HTTP_10; - - for i in CODES.iter() { - group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _original::write_status_line(version, i, &mut b); - }) - }); - - group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _new::write_status_line(version, i, &mut b); - }) - }); - - group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _naive::write_status_line(version, i, &mut b); - }) - }); - } - - group.finish(); -} - -fn bench_write_status_line_09(c: &mut Criterion) { - let mut group = c.benchmark_group("write_status_line v0.9"); - - let version = Version::HTTP_09; - - for i in CODES.iter() { - group.bench_with_input(BenchmarkId::new("Original (unsafe)", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _original::write_status_line(version, i, &mut b); - }) - }); - - group.bench_with_input(BenchmarkId::new("New (safe)", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _new::write_status_line(version, i, &mut b); - }) - }); - - group.bench_with_input(BenchmarkId::new("Naive", i), i, |b, &i| { - b.iter(|| { - let mut b = BytesMut::with_capacity(35); - _naive::write_status_line(version, i, &mut b); - }) - }); - } - - group.finish(); -} - -criterion_group!( - benches, - bench_write_status_line_11, - bench_write_status_line_10, - bench_write_status_line_09 -); -criterion_main!(benches); - -mod _naive { - use bytes::{BufMut, BytesMut}; - use http::Version; - - pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) { - match version { - Version::HTTP_11 => bytes.put_slice(b"HTTP/1.1 "), - Version::HTTP_10 => bytes.put_slice(b"HTTP/1.0 "), - Version::HTTP_09 => bytes.put_slice(b"HTTP/0.9 "), - _ => { - // other HTTP version handlers do not use this method - } - } - - bytes.put_slice(n.to_string().as_bytes()); - } -} - -mod _new { - use bytes::{BufMut, BytesMut}; - use http::Version; - - const DIGITS_START: u8 = b'0'; - - pub(crate) fn write_status_line(version: Version, n: u16, bytes: &mut BytesMut) { - match version { - Version::HTTP_11 => bytes.put_slice(b"HTTP/1.1 "), - Version::HTTP_10 => bytes.put_slice(b"HTTP/1.0 "), - Version::HTTP_09 => bytes.put_slice(b"HTTP/0.9 "), - _ => { - // other HTTP version handlers do not use this method - } - } - - let d100 = (n / 100) as u8; - let d10 = ((n / 10) % 10) as u8; - let d1 = (n % 10) as u8; - - bytes.put_u8(DIGITS_START + d100); - bytes.put_u8(DIGITS_START + d10); - bytes.put_u8(DIGITS_START + d1); - - bytes.put_u8(b' '); - } -} - -mod _original { - use std::ptr; - - use bytes::{BufMut, BytesMut}; - use http::Version; - - const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\ - 2021222324252627282930313233343536373839\ - 4041424344454647484950515253545556575859\ - 6061626364656667686970717273747576777879\ - 8081828384858687888990919293949596979899"; - - pub(crate) const STATUS_LINE_BUF_SIZE: usize = 13; - - pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) { - let mut buf: [u8; STATUS_LINE_BUF_SIZE] = *b"HTTP/1.1 "; - - match version { - Version::HTTP_2 => buf[5] = b'2', - Version::HTTP_10 => buf[7] = b'0', - Version::HTTP_09 => { - buf[5] = b'0'; - buf[7] = b'9'; - } - _ => {} - } - - let mut curr: isize = 12; - let buf_ptr = buf.as_mut_ptr(); - let lut_ptr = DEC_DIGITS_LUT.as_ptr(); - let four = n > 999; - - // decode 2 more chars, if > 2 chars - let d1 = (n % 100) << 1; - n /= 100; - curr -= 2; - unsafe { - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2); - } - - // decode last 1 or 2 chars - if n < 10 { - curr -= 1; - unsafe { - *buf_ptr.offset(curr) = (n as u8) + b'0'; - } - } else { - let d1 = n << 1; - curr -= 2; - unsafe { - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(curr), 2); - } - } - - bytes.put_slice(&buf); - if four { - bytes.put_u8(b' '); - } - } -} diff --git a/actix-http/benches/uninit-headers.rs b/actix-http/benches/uninit-headers.rs deleted file mode 100644 index 688c64d6e..000000000 --- a/actix-http/benches/uninit-headers.rs +++ /dev/null @@ -1,135 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion}; - -use bytes::BytesMut; - -// A Miri run detects UB, seen on this playground: -// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f5d9aa166aa48df8dca05fce2b6c3915 - -fn bench_header_parsing(c: &mut Criterion) { - c.bench_function("Original (Unsound) [short]", |b| { - b.iter(|| { - let mut buf = BytesMut::from(REQ_SHORT); - _original::parse_headers(&mut buf); - }) - }); - - c.bench_function("New (safe) [short]", |b| { - b.iter(|| { - let mut buf = BytesMut::from(REQ_SHORT); - _new::parse_headers(&mut buf); - }) - }); - - c.bench_function("Original (Unsound) [realistic]", |b| { - b.iter(|| { - let mut buf = BytesMut::from(REQ); - _original::parse_headers(&mut buf); - }) - }); - - c.bench_function("New (safe) [realistic]", |b| { - b.iter(|| { - let mut buf = BytesMut::from(REQ); - _new::parse_headers(&mut buf); - }) - }); -} - -criterion_group!(benches, bench_header_parsing); -criterion_main!(benches); - -const MAX_HEADERS: usize = 96; - -const EMPTY_HEADER_ARRAY: [httparse::Header<'static>; MAX_HEADERS] = - [httparse::EMPTY_HEADER; MAX_HEADERS]; - -#[derive(Clone, Copy)] -struct HeaderIndex { - name: (usize, usize), - value: (usize, usize), -} - -const EMPTY_HEADER_INDEX: HeaderIndex = HeaderIndex { - name: (0, 0), - value: (0, 0), -}; - -const EMPTY_HEADER_INDEX_ARRAY: [HeaderIndex; MAX_HEADERS] = [EMPTY_HEADER_INDEX; MAX_HEADERS]; - -impl HeaderIndex { - fn record(bytes: &[u8], headers: &[httparse::Header<'_>], indices: &mut [HeaderIndex]) { - let bytes_ptr = bytes.as_ptr() as usize; - for (header, indices) in headers.iter().zip(indices.iter_mut()) { - let name_start = header.name.as_ptr() as usize - bytes_ptr; - let name_end = name_start + header.name.len(); - indices.name = (name_start, name_end); - let value_start = header.value.as_ptr() as usize - bytes_ptr; - let value_end = value_start + header.value.len(); - indices.value = (value_start, value_end); - } - } -} - -// test cases taken from: -// https://github.com/seanmonstar/httparse/blob/master/benches/parse.rs - -const REQ_SHORT: &[u8] = b"\ -GET / HTTP/1.0\r\n\ -Host: example.com\r\n\ -Cookie: session=60; user_id=1\r\n\r\n"; - -const REQ: &[u8] = b"\ -GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n\ -Host: www.kittyhell.com\r\n\ -User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 Pathtraq/0.9\r\n\ -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n\ -Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n\ -Accept-Encoding: gzip,deflate\r\n\ -Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n\ -Keep-Alive: 115\r\n\ -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"; - -mod _new { - use super::*; - - pub fn parse_headers(src: &mut BytesMut) -> usize { - let mut headers: [HeaderIndex; MAX_HEADERS] = EMPTY_HEADER_INDEX_ARRAY; - let mut parsed: [httparse::Header<'_>; MAX_HEADERS] = EMPTY_HEADER_ARRAY; - - let mut req = httparse::Request::new(&mut parsed); - match req.parse(src).unwrap() { - httparse::Status::Complete(_len) => { - HeaderIndex::record(src, req.headers, &mut headers); - req.headers.len() - } - _ => unreachable!(), - } - } -} - -mod _original { - use super::*; - - use std::mem::MaybeUninit; - - pub fn parse_headers(src: &mut BytesMut) -> usize { - #![allow(invalid_value, clippy::uninit_assumed_init)] - - let mut headers: [HeaderIndex; MAX_HEADERS] = - unsafe { MaybeUninit::uninit().assume_init() }; - - #[allow(invalid_value)] - let mut parsed: [httparse::Header<'_>; MAX_HEADERS] = - unsafe { MaybeUninit::uninit().assume_init() }; - - let mut req = httparse::Request::new(&mut parsed); - match req.parse(src).unwrap() { - httparse::Status::Complete(_len) => { - HeaderIndex::record(src, req.headers, &mut headers); - req.headers.len() - } - _ => unreachable!(), - } - } -} diff --git a/actix-http/benches/write-camel-case.rs b/actix-http/benches/write-camel-case.rs deleted file mode 100644 index ccf09b37e..000000000 --- a/actix-http/benches/write-camel-case.rs +++ /dev/null @@ -1,93 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; - -fn bench_write_camel_case(c: &mut Criterion) { - let mut group = c.benchmark_group("write_camel_case"); - - let names = ["connection", "Transfer-Encoding", "transfer-encoding"]; - - for &i in &names { - let bts = i.as_bytes(); - - group.bench_with_input(BenchmarkId::new("Original", i), bts, |b, bts| { - b.iter(|| { - let mut buf = black_box([0; 24]); - _original::write_camel_case(black_box(bts), &mut buf) - }); - }); - - group.bench_with_input(BenchmarkId::new("New", i), bts, |b, bts| { - b.iter(|| { - let mut buf = black_box([0; 24]); - let len = black_box(bts.len()); - _new::write_camel_case(black_box(bts), buf.as_mut_ptr(), len) - }); - }); - } - - group.finish(); -} - -criterion_group!(benches, bench_write_camel_case); -criterion_main!(benches); - -mod _new { - pub fn write_camel_case(value: &[u8], buf: *mut u8, len: usize) { - // first copy entire (potentially wrong) slice to output - let buffer = unsafe { - std::ptr::copy_nonoverlapping(value.as_ptr(), buf, len); - std::slice::from_raw_parts_mut(buf, len) - }; - - let mut iter = value.iter(); - - // first character should be uppercase - if let Some(c @ b'a'..=b'z') = iter.next() { - buffer[0] = c & 0b1101_1111; - } - - // track 1 ahead of the current position since that's the location being assigned to - let mut index = 2; - - // remaining characters after hyphens should also be uppercase - while let Some(&c) = iter.next() { - if c == b'-' { - // advance iter by one and uppercase if needed - if let Some(c @ b'a'..=b'z') = iter.next() { - buffer[index] = c & 0b1101_1111; - } - } - - index += 1; - } - } -} - -mod _original { - pub fn write_camel_case(value: &[u8], buffer: &mut [u8]) { - let mut index = 0; - let key = value; - let mut key_iter = key.iter(); - - if let Some(c) = key_iter.next() { - if *c >= b'a' && *c <= b'z' { - buffer[index] = *c ^ b' '; - index += 1; - } - } else { - return; - } - - while let Some(c) = key_iter.next() { - buffer[index] = *c; - index += 1; - if *c == b'-' { - if let Some(c) = key_iter.next() { - if *c >= b'a' && *c <= b'z' { - buffer[index] = *c ^ b' '; - index += 1; - } - } - } - } - } -}