399 lines
12 KiB
Rust
399 lines
12 KiB
Rust
|
// Comparisons between Rust built-ins and memchr.
|
|||
|
//
|
|||
|
// Copyright (C) 2014-2021 Ryan Specialty Group, LLC.
|
|||
|
//
|
|||
|
// This file is part of TAME.
|
|||
|
//
|
|||
|
// This program is free software: you can redistribute it and/or modify
|
|||
|
// it under the terms of the GNU General Public License as published by
|
|||
|
// the Free Software Foundation, either version 3 of the License, or
|
|||
|
// (at your option) any later version.
|
|||
|
//
|
|||
|
// This program is distributed in the hope that it will be useful,
|
|||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
// GNU General Public License for more details.
|
|||
|
//
|
|||
|
// You should have received a copy of the GNU General Public License
|
|||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|
|||
|
#![feature(test)]
|
|||
|
|
|||
|
//! Comparisons between Rust built-ins and memchr.
|
|||
|
//!
|
|||
|
//! The intent of these benchmarks are to determine how significant of a
|
|||
|
//! benefit the more traditional approach in C (`memchr`) provides over
|
|||
|
//! Rust's built-ins in various situations.
|
|||
|
//!
|
|||
|
//! See the [`memchr`] crate for more information.
|
|||
|
|
|||
|
extern crate memchr;
|
|||
|
extern crate tamer;
|
|||
|
extern crate test;
|
|||
|
|
|||
|
use test::Bencher;
|
|||
|
|
|||
|
fn gen_strs(n: usize, suffix: &str) -> Vec<String> {
|
|||
|
(0..n).map(|n| n.to_string() + suffix).collect()
|
|||
|
}
|
|||
|
|
|||
|
mod small_str {
|
|||
|
use super::*;
|
|||
|
|
|||
|
mod one {
|
|||
|
use super::*;
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_char_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foobar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(!s.contains(':')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_byte_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foobar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(!s.as_bytes().contains(&b':')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foobar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(memchr::memchr(b':', s.as_bytes()).is_none())
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_char_mid_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foo:bar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter().map(|s| assert!(s.contains(':'))).for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
fn rust_contains_one_byte_mid_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foo:bar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(s.as_bytes().contains(&b':')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr_mid_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foo:bar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(memchr::memchr(b':', s.as_bytes()).is_some())
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
mod two {
|
|||
|
use super::*;
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_two_char_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foobar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(!s.contains(&[':', '>'][..])))
|
|||
|
.for_each(drop)
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr2_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foobar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(
|
|||
|
memchr::memchr2(b':', b'>', s.as_bytes()).is_none()
|
|||
|
)
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_two_char_mid_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foo>bar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(s.contains(&[':', '>'][..])))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr2_mid_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, "foo>bar");
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(
|
|||
|
memchr::memchr2(b':', b'>', s.as_bytes()).is_some()
|
|||
|
)
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
mod large_str {
|
|||
|
use super::*;
|
|||
|
|
|||
|
// Granted, this isn't large compared to some of the strings the linker
|
|||
|
// deals with, but the linker also isn't searching those strings.
|
|||
|
const LG_STR: &'static str = r#"
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
: It contains a unique char near the beginning.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
@ And a unique char near the end.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
This is a line of a longer string to test efficiency of searches.
|
|||
|
"#;
|
|||
|
|
|||
|
mod one {
|
|||
|
use super::*;
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_char_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(!s.contains('_')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_byte_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(!s.as_bytes().contains(&b'_')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(memchr::memchr(b'_', s.as_bytes()).is_none())
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_char_early_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter().map(|s| assert!(s.contains(':'))).for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_byte_early_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(s.as_bytes().contains(&b':')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr_early_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(memchr::memchr(b':', s.as_bytes()).is_some())
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_char_late_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter().map(|s| assert!(s.contains('@'))).for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_one_byte_late_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(s.as_bytes().contains(&b'@')))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr_late_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(memchr::memchr(b'@', s.as_bytes()).is_some())
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
mod two {
|
|||
|
use super::*;
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_two_char_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(!s.contains(&['_', '!'][..])))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr2_non_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(
|
|||
|
memchr::memchr2(b'_', b'!', s.as_bytes()).is_none()
|
|||
|
)
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_two_char_early_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(s.contains(&['_', ':'][..])))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr2_early_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(
|
|||
|
memchr::memchr2(b'_', b':', s.as_bytes()).is_some()
|
|||
|
)
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn rust_contains_two_char_late_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| assert!(s.contains(&['_', '@'][..])))
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
#[bench]
|
|||
|
fn memchr2_late_match(bench: &mut Bencher) {
|
|||
|
let strs = gen_strs(1000, LG_STR);
|
|||
|
|
|||
|
bench.iter(|| {
|
|||
|
strs.iter()
|
|||
|
.map(|s| {
|
|||
|
assert!(
|
|||
|
memchr::memchr2(b'_', b'@', s.as_bytes()).is_some()
|
|||
|
)
|
|||
|
})
|
|||
|
.for_each(drop);
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
}
|