// Comparisons between Rust built-ins and memchr. // // Copyright (C) 2014-2023 Ryan Specialty, 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 . #![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 { (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); }); } #[bench] 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); }); } } }