summaryrefslogtreecommitdiffstats
path: root/library/core/benches
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/benches')
-rw-r--r--library/core/benches/any.rs12
-rw-r--r--library/core/benches/ascii.rs353
-rw-r--r--library/core/benches/ascii/is_ascii.rs82
-rw-r--r--library/core/benches/char/methods.rs77
-rw-r--r--library/core/benches/char/mod.rs1
-rw-r--r--library/core/benches/fmt.rs150
-rw-r--r--library/core/benches/hash/mod.rs1
-rw-r--r--library/core/benches/hash/sip.rs123
-rw-r--r--library/core/benches/iter.rs393
-rw-r--r--library/core/benches/lib.rs28
-rw-r--r--library/core/benches/num/dec2flt/mod.rs57
-rw-r--r--library/core/benches/num/flt2dec/mod.rs37
-rw-r--r--library/core/benches/num/flt2dec/strategy/dragon.rs76
-rw-r--r--library/core/benches/num/flt2dec/strategy/grisu.rs83
-rw-r--r--library/core/benches/num/int_log/mod.rs58
-rw-r--r--library/core/benches/num/mod.rs108
-rw-r--r--library/core/benches/ops.rs19
-rw-r--r--library/core/benches/pattern.rs42
-rw-r--r--library/core/benches/slice.rs164
-rw-r--r--library/core/benches/str.rs10
-rw-r--r--library/core/benches/str/char_count.rs107
-rw-r--r--library/core/benches/str/corpora.rs88
22 files changed, 2069 insertions, 0 deletions
diff --git a/library/core/benches/any.rs b/library/core/benches/any.rs
new file mode 100644
index 000000000..53099b782
--- /dev/null
+++ b/library/core/benches/any.rs
@@ -0,0 +1,12 @@
+use core::any::*;
+use test::{black_box, Bencher};
+
+#[bench]
+fn bench_downcast_ref(b: &mut Bencher) {
+ b.iter(|| {
+ let mut x = 0;
+ let mut y = &mut x as &mut dyn Any;
+ black_box(&mut y);
+ black_box(y.downcast_ref::<isize>() == Some(&0));
+ });
+}
diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs
new file mode 100644
index 000000000..64938745a
--- /dev/null
+++ b/library/core/benches/ascii.rs
@@ -0,0 +1,353 @@
+mod is_ascii;
+
+// Lower-case ASCII 'a' is the first byte that has its highest bit set
+// after wrap-adding 0x1F:
+//
+// b'a' + 0x1F == 0x80 == 0b1000_0000
+// b'z' + 0x1F == 0x98 == 0b1001_1000
+//
+// Lower-case ASCII 'z' is the last byte that has its highest bit unset
+// after wrap-adding 0x05:
+//
+// b'a' + 0x05 == 0x66 == 0b0110_0110
+// b'z' + 0x05 == 0x7F == 0b0111_1111
+//
+// … except for 0xFB to 0xFF, but those are in the range of bytes
+// that have the highest bit unset again after adding 0x1F.
+//
+// So `(byte + 0x1f) & !(byte + 5)` has its highest bit set
+// iff `byte` is a lower-case ASCII letter.
+//
+// Lower-case ASCII letters all have the 0x20 bit set.
+// (Two positions right of 0x80, the highest bit.)
+// Unsetting that bit produces the same letter, in upper-case.
+//
+// Therefore:
+fn branchless_to_ascii_upper_case(byte: u8) -> u8 {
+ byte & !((byte.wrapping_add(0x1f) & !byte.wrapping_add(0x05) & 0x80) >> 2)
+}
+
+macro_rules! benches {
+ ($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => {
+ benches! {@
+ $( fn $name($arg: &mut [u8]) $body )+
+ $( fn $is_(bytes: &mut [u8]) { bytes.iter().all(u8::$is_) } )+
+ }
+ };
+
+ (@$( fn $name: ident($arg: ident: &mut [u8]) $body: block )+) => {
+ benches!(mod short SHORT $($name $arg $body)+);
+ benches!(mod medium MEDIUM $($name $arg $body)+);
+ benches!(mod long LONG $($name $arg $body)+);
+ };
+
+ (mod $mod_name: ident $input: ident $($name: ident $arg: ident $body: block)+) => {
+ mod $mod_name {
+ use super::*;
+
+ $(
+ #[bench]
+ fn $name(bencher: &mut Bencher) {
+ bencher.bytes = $input.len() as u64;
+ bencher.iter(|| {
+ let mut vec = $input.as_bytes().to_vec();
+ {
+ let $arg = &mut vec[..];
+ black_box($body);
+ }
+ vec
+ })
+ }
+ )+
+ }
+ }
+}
+
+use test::black_box;
+use test::Bencher;
+
+const ASCII_CASE_MASK: u8 = 0b0010_0000;
+
+benches! {
+ fn case00_alloc_only(_bytes: &mut [u8]) {}
+
+ fn case01_black_box_read_each_byte(bytes: &mut [u8]) {
+ for byte in bytes {
+ black_box(*byte);
+ }
+ }
+
+ fn case02_lookup_table(bytes: &mut [u8]) {
+ for byte in bytes {
+ *byte = ASCII_UPPERCASE_MAP[*byte as usize]
+ }
+ }
+
+ fn case03_branch_and_subtract(bytes: &mut [u8]) {
+ for byte in bytes {
+ *byte = if b'a' <= *byte && *byte <= b'z' {
+ *byte - b'a' + b'A'
+ } else {
+ *byte
+ }
+ }
+ }
+
+ fn case04_branch_and_mask(bytes: &mut [u8]) {
+ for byte in bytes {
+ *byte = if b'a' <= *byte && *byte <= b'z' {
+ *byte & !0x20
+ } else {
+ *byte
+ }
+ }
+ }
+
+ fn case05_branchless(bytes: &mut [u8]) {
+ for byte in bytes {
+ *byte = branchless_to_ascii_upper_case(*byte)
+ }
+ }
+
+ fn case06_libcore(bytes: &mut [u8]) {
+ bytes.make_ascii_uppercase()
+ }
+
+ fn case07_fake_simd_u32(bytes: &mut [u8]) {
+ // SAFETY: transmuting a sequence of `u8` to `u32` is always fine
+ let (before, aligned, after) = unsafe {
+ bytes.align_to_mut::<u32>()
+ };
+ for byte in before {
+ *byte = branchless_to_ascii_upper_case(*byte)
+ }
+ for word in aligned {
+ // FIXME: this is incorrect for some byte values:
+ // addition within a byte can carry/overflow into the next byte.
+ // Test case: b"\xFFz "
+ *word &= !(
+ (
+ word.wrapping_add(0x1f1f1f1f) &
+ !word.wrapping_add(0x05050505) &
+ 0x80808080
+ ) >> 2
+ )
+ }
+ for byte in after {
+ *byte = branchless_to_ascii_upper_case(*byte)
+ }
+ }
+
+ fn case08_fake_simd_u64(bytes: &mut [u8]) {
+ // SAFETY: transmuting a sequence of `u8` to `u64` is always fine
+ let (before, aligned, after) = unsafe {
+ bytes.align_to_mut::<u64>()
+ };
+ for byte in before {
+ *byte = branchless_to_ascii_upper_case(*byte)
+ }
+ for word in aligned {
+ // FIXME: like above, this is incorrect for some byte values.
+ *word &= !(
+ (
+ word.wrapping_add(0x1f1f1f1f_1f1f1f1f) &
+ !word.wrapping_add(0x05050505_05050505) &
+ 0x80808080_80808080
+ ) >> 2
+ )
+ }
+ for byte in after {
+ *byte = branchless_to_ascii_upper_case(*byte)
+ }
+ }
+
+ fn case09_mask_mult_bool_branchy_lookup_table(bytes: &mut [u8]) {
+ fn is_ascii_lowercase(b: u8) -> bool {
+ if b >= 0x80 { return false }
+ match ASCII_CHARACTER_CLASS[b as usize] {
+ L | Lx => true,
+ _ => false,
+ }
+ }
+ for byte in bytes {
+ *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8))
+ }
+ }
+
+ fn case10_mask_mult_bool_lookup_table(bytes: &mut [u8]) {
+ fn is_ascii_lowercase(b: u8) -> bool {
+ match ASCII_CHARACTER_CLASS[b as usize] {
+ L | Lx => true,
+ _ => false
+ }
+ }
+ for byte in bytes {
+ *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8))
+ }
+ }
+
+ fn case11_mask_mult_bool_match_range(bytes: &mut [u8]) {
+ fn is_ascii_lowercase(b: u8) -> bool {
+ match b {
+ b'a'..=b'z' => true,
+ _ => false
+ }
+ }
+ for byte in bytes {
+ *byte &= !(0x20 * (is_ascii_lowercase(*byte) as u8))
+ }
+ }
+
+ fn case12_mask_shifted_bool_match_range(bytes: &mut [u8]) {
+ fn is_ascii_lowercase(b: u8) -> bool {
+ match b {
+ b'a'..=b'z' => true,
+ _ => false
+ }
+ }
+ for byte in bytes {
+ *byte &= !((is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK)
+ }
+ }
+
+ fn case13_subtract_shifted_bool_match_range(bytes: &mut [u8]) {
+ fn is_ascii_lowercase(b: u8) -> bool {
+ match b {
+ b'a'..=b'z' => true,
+ _ => false
+ }
+ }
+ for byte in bytes {
+ *byte -= (is_ascii_lowercase(*byte) as u8) * ASCII_CASE_MASK
+ }
+ }
+
+ fn case14_subtract_multiplied_bool_match_range(bytes: &mut [u8]) {
+ fn is_ascii_lowercase(b: u8) -> bool {
+ match b {
+ b'a'..=b'z' => true,
+ _ => false
+ }
+ }
+ for byte in bytes {
+ *byte -= (b'a' - b'A') * is_ascii_lowercase(*byte) as u8
+ }
+ }
+
+ @iter
+
+ is_ascii,
+ is_ascii_alphabetic,
+ is_ascii_uppercase,
+ is_ascii_lowercase,
+ is_ascii_alphanumeric,
+ is_ascii_digit,
+ is_ascii_hexdigit,
+ is_ascii_punctuation,
+ is_ascii_graphic,
+ is_ascii_whitespace,
+ is_ascii_control,
+}
+
+macro_rules! repeat {
+ ($s: expr) => {
+ concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s)
+ };
+}
+
+const SHORT: &str = "Alice's";
+const MEDIUM: &str = "Alice's Adventures in Wonderland";
+const LONG: &str = repeat!(
+ r#"
+ La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850)
+ Alice's Adventures in Wonderland (1865)
+ Phantasmagoria and Other Poems (1869)
+ Through the Looking-Glass, and What Alice Found There
+ (includes "Jabberwocky" and "The Walrus and the Carpenter") (1871)
+ The Hunting of the Snark (1876)
+ Rhyme? And Reason? (1883) – shares some contents with the 1869 collection,
+ including the long poem "Phantasmagoria"
+ A Tangled Tale (1885)
+ Sylvie and Bruno (1889)
+ Sylvie and Bruno Concluded (1893)
+ Pillow Problems (1893)
+ What the Tortoise Said to Achilles (1895)
+ Three Sunsets and Other Poems (1898)
+ The Manlet (1903)[106]
+"#
+);
+
+#[rustfmt::skip]
+const ASCII_UPPERCASE_MAP: [u8; 256] = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ b' ', b'!', b'"', b'#', b'$', b'%', b'&', b'\'',
+ b'(', b')', b'*', b'+', b',', b'-', b'.', b'/',
+ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
+ b'8', b'9', b':', b';', b'<', b'=', b'>', b'?',
+ b'@', b'A', b'B', b'C', b'D', b'E', b'F', b'G',
+ b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
+ b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
+ b'X', b'Y', b'Z', b'[', b'\\', b']', b'^', b'_',
+ b'`',
+
+ b'A', b'B', b'C', b'D', b'E', b'F', b'G',
+ b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
+ b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W',
+ b'X', b'Y', b'Z',
+
+ b'{', b'|', b'}', b'~', 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+enum AsciiCharacterClass {
+ C, // control
+ Cw, // control whitespace
+ W, // whitespace
+ D, // digit
+ L, // lowercase
+ Lx, // lowercase hex digit
+ U, // uppercase
+ Ux, // uppercase hex digit
+ P, // punctuation
+ N, // Non-ASCII
+}
+use self::AsciiCharacterClass::*;
+
+#[rustfmt::skip]
+static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [
+// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
+ C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
+ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_
+ W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_
+ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_
+ P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_
+ U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_
+ P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_
+ L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+];
diff --git a/library/core/benches/ascii/is_ascii.rs b/library/core/benches/ascii/is_ascii.rs
new file mode 100644
index 000000000..a42a1dcfe
--- /dev/null
+++ b/library/core/benches/ascii/is_ascii.rs
@@ -0,0 +1,82 @@
+use super::{LONG, MEDIUM, SHORT};
+use test::black_box;
+use test::Bencher;
+
+macro_rules! benches {
+ ($( fn $name: ident($arg: ident: &[u8]) $body: block )+) => {
+ benches!(mod short SHORT[..] $($name $arg $body)+);
+ benches!(mod medium MEDIUM[..] $($name $arg $body)+);
+ benches!(mod long LONG[..] $($name $arg $body)+);
+ // Ensure we benchmark cases where the functions are called with strings
+ // that are not perfectly aligned or have a length which is not a
+ // multiple of size_of::<usize>() (or both)
+ benches!(mod unaligned_head MEDIUM[1..] $($name $arg $body)+);
+ benches!(mod unaligned_tail MEDIUM[..(MEDIUM.len() - 1)] $($name $arg $body)+);
+ benches!(mod unaligned_both MEDIUM[1..(MEDIUM.len() - 1)] $($name $arg $body)+);
+ };
+
+ (mod $mod_name: ident $input: ident [$range: expr] $($name: ident $arg: ident $body: block)+) => {
+ mod $mod_name {
+ use super::*;
+ $(
+ #[bench]
+ fn $name(bencher: &mut Bencher) {
+ bencher.bytes = $input[$range].len() as u64;
+ let mut vec = $input.as_bytes().to_vec();
+ bencher.iter(|| {
+ let $arg: &[u8] = &black_box(&mut vec)[$range];
+ black_box($body)
+ })
+ }
+ )+
+ }
+ };
+}
+
+benches! {
+ fn case00_libcore(bytes: &[u8]) {
+ bytes.is_ascii()
+ }
+
+ fn case01_iter_all(bytes: &[u8]) {
+ bytes.iter().all(|b| b.is_ascii())
+ }
+
+ fn case02_align_to(bytes: &[u8]) {
+ is_ascii_align_to(bytes)
+ }
+
+ fn case03_align_to_unrolled(bytes: &[u8]) {
+ is_ascii_align_to_unrolled(bytes)
+ }
+}
+
+// These are separate since it's easier to debug errors if they don't go through
+// macro expansion first.
+fn is_ascii_align_to(bytes: &[u8]) -> bool {
+ if bytes.len() < core::mem::size_of::<usize>() {
+ return bytes.iter().all(|b| b.is_ascii());
+ }
+ // SAFETY: transmuting a sequence of `u8` to `usize` is always fine
+ let (head, body, tail) = unsafe { bytes.align_to::<usize>() };
+ head.iter().all(|b| b.is_ascii())
+ && body.iter().all(|w| !contains_nonascii(*w))
+ && tail.iter().all(|b| b.is_ascii())
+}
+
+fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool {
+ if bytes.len() < core::mem::size_of::<usize>() {
+ return bytes.iter().all(|b| b.is_ascii());
+ }
+ // SAFETY: transmuting a sequence of `u8` to `[usize; 2]` is always fine
+ let (head, body, tail) = unsafe { bytes.align_to::<[usize; 2]>() };
+ head.iter().all(|b| b.is_ascii())
+ && body.iter().all(|w| !contains_nonascii(w[0] | w[1]))
+ && tail.iter().all(|b| b.is_ascii())
+}
+
+#[inline]
+fn contains_nonascii(v: usize) -> bool {
+ const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; core::mem::size_of::<usize>()]);
+ (NONASCII_MASK & v) != 0
+}
diff --git a/library/core/benches/char/methods.rs b/library/core/benches/char/methods.rs
new file mode 100644
index 000000000..9408f83c3
--- /dev/null
+++ b/library/core/benches/char/methods.rs
@@ -0,0 +1,77 @@
+use test::Bencher;
+
+const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9'];
+const RADIX: [u32; 5] = [2, 8, 10, 16, 32];
+
+#[bench]
+fn bench_to_digit_radix_2(b: &mut Bencher) {
+ b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(2)).min())
+}
+
+#[bench]
+fn bench_to_digit_radix_10(b: &mut Bencher) {
+ b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(10)).min())
+}
+
+#[bench]
+fn bench_to_digit_radix_16(b: &mut Bencher) {
+ b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(16)).min())
+}
+
+#[bench]
+fn bench_to_digit_radix_36(b: &mut Bencher) {
+ b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(36)).min())
+}
+
+#[bench]
+fn bench_to_digit_radix_var(b: &mut Bencher) {
+ b.iter(|| {
+ CHARS
+ .iter()
+ .cycle()
+ .zip(RADIX.iter().cycle())
+ .take(10_000)
+ .map(|(c, radix)| c.to_digit(*radix))
+ .min()
+ })
+}
+
+#[bench]
+fn bench_to_ascii_uppercase(b: &mut Bencher) {
+ b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min())
+}
+
+#[bench]
+fn bench_to_ascii_lowercase(b: &mut Bencher) {
+ b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min())
+}
+
+#[bench]
+fn bench_ascii_mix_to_uppercase(b: &mut Bencher) {
+ b.iter(|| (0..=255).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
+}
+
+#[bench]
+fn bench_ascii_mix_to_lowercase(b: &mut Bencher) {
+ b.iter(|| (0..=255).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
+}
+
+#[bench]
+fn bench_ascii_char_to_uppercase(b: &mut Bencher) {
+ b.iter(|| (0..=127).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
+}
+
+#[bench]
+fn bench_ascii_char_to_lowercase(b: &mut Bencher) {
+ b.iter(|| (0..=127).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
+}
+
+#[bench]
+fn bench_non_ascii_char_to_uppercase(b: &mut Bencher) {
+ b.iter(|| (128..=255).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
+}
+
+#[bench]
+fn bench_non_ascii_char_to_lowercase(b: &mut Bencher) {
+ b.iter(|| (128..=255).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
+}
diff --git a/library/core/benches/char/mod.rs b/library/core/benches/char/mod.rs
new file mode 100644
index 000000000..9ca51a768
--- /dev/null
+++ b/library/core/benches/char/mod.rs
@@ -0,0 +1 @@
+mod methods;
diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs
new file mode 100644
index 000000000..ff726ff75
--- /dev/null
+++ b/library/core/benches/fmt.rs
@@ -0,0 +1,150 @@
+use std::fmt::{self, Write as FmtWrite};
+use std::io::{self, Write as IoWrite};
+use test::Bencher;
+
+#[bench]
+fn write_vec_value(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ for _ in 0..1000 {
+ mem.write_all("abc".as_bytes()).unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_ref(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ wr.write_all("abc".as_bytes()).unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_macro1(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ write!(wr, "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_macro2(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ write!(wr, "{}", "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_macro_debug(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ write!(wr, "{:?}", "☃").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_value(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ for _ in 0..1000 {
+ mem.write_str("abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_ref(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ wr.write_str("abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro1(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ for _ in 0..1000 {
+ write!(mem, "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro2(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ write!(wr, "{}", "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro_debug(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ write!(wr, "{:?}", "☃").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro_debug_ascii(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ write!(wr, "{:?}", "Hello, World!").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_u128_max(bh: &mut Bencher) {
+ bh.iter(|| {
+ test::black_box(format!("{}", u128::MAX));
+ });
+}
+
+#[bench]
+fn write_u128_min(bh: &mut Bencher) {
+ bh.iter(|| {
+ let s = format!("{}", 0u128);
+ test::black_box(s);
+ });
+}
+
+#[bench]
+fn write_u64_max(bh: &mut Bencher) {
+ bh.iter(|| {
+ test::black_box(format!("{}", u64::MAX));
+ });
+}
+
+#[bench]
+fn write_u64_min(bh: &mut Bencher) {
+ bh.iter(|| {
+ test::black_box(format!("{}", 0u64));
+ });
+}
diff --git a/library/core/benches/hash/mod.rs b/library/core/benches/hash/mod.rs
new file mode 100644
index 000000000..4f2e152b6
--- /dev/null
+++ b/library/core/benches/hash/mod.rs
@@ -0,0 +1 @@
+mod sip;
diff --git a/library/core/benches/hash/sip.rs b/library/core/benches/hash/sip.rs
new file mode 100644
index 000000000..725c864dc
--- /dev/null
+++ b/library/core/benches/hash/sip.rs
@@ -0,0 +1,123 @@
+#![allow(deprecated)]
+
+use core::hash::*;
+use test::{black_box, Bencher};
+
+fn hash_bytes<H: Hasher>(mut s: H, x: &[u8]) -> u64 {
+ Hasher::write(&mut s, x);
+ s.finish()
+}
+
+fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
+ x.hash(&mut st);
+ st.finish()
+}
+
+fn hash<T: Hash>(x: &T) -> u64 {
+ hash_with(SipHasher::new(), x)
+}
+
+#[bench]
+fn bench_str_under_8_bytes(b: &mut Bencher) {
+ let s = "foo";
+ b.iter(|| {
+ assert_eq!(hash(&s), 16262950014981195938);
+ })
+}
+
+#[bench]
+fn bench_str_of_8_bytes(b: &mut Bencher) {
+ let s = "foobar78";
+ b.iter(|| {
+ assert_eq!(hash(&s), 4898293253460910787);
+ })
+}
+
+#[bench]
+fn bench_str_over_8_bytes(b: &mut Bencher) {
+ let s = "foobarbaz0";
+ b.iter(|| {
+ assert_eq!(hash(&s), 10581415515220175264);
+ })
+}
+
+#[bench]
+fn bench_long_str(b: &mut Bencher) {
+ let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
+ irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
+ officia deserunt mollit anim id est laborum.";
+ b.iter(|| {
+ assert_eq!(hash(&s), 17717065544121360093);
+ })
+}
+
+#[bench]
+fn bench_u32(b: &mut Bencher) {
+ let u = 162629500u32;
+ let u = black_box(u);
+ b.iter(|| hash(&u));
+ b.bytes = 8;
+}
+
+#[bench]
+fn bench_u32_keyed(b: &mut Bencher) {
+ let u = 162629500u32;
+ let u = black_box(u);
+ let k1 = black_box(0x1);
+ let k2 = black_box(0x2);
+ b.iter(|| hash_with(SipHasher::new_with_keys(k1, k2), &u));
+ b.bytes = 8;
+}
+
+#[bench]
+fn bench_u64(b: &mut Bencher) {
+ let u = 16262950014981195938u64;
+ let u = black_box(u);
+ b.iter(|| hash(&u));
+ b.bytes = 8;
+}
+
+#[bench]
+fn bench_bytes_4(b: &mut Bencher) {
+ let data = black_box([b' '; 4]);
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
+ b.bytes = 4;
+}
+
+#[bench]
+fn bench_bytes_7(b: &mut Bencher) {
+ let data = black_box([b' '; 7]);
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
+ b.bytes = 7;
+}
+
+#[bench]
+fn bench_bytes_8(b: &mut Bencher) {
+ let data = black_box([b' '; 8]);
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
+ b.bytes = 8;
+}
+
+#[bench]
+fn bench_bytes_a_16(b: &mut Bencher) {
+ let data = black_box([b' '; 16]);
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
+ b.bytes = 16;
+}
+
+#[bench]
+fn bench_bytes_b_32(b: &mut Bencher) {
+ let data = black_box([b' '; 32]);
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
+ b.bytes = 32;
+}
+
+#[bench]
+fn bench_bytes_c_128(b: &mut Bencher) {
+ let data = black_box([b' '; 128]);
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
+ b.bytes = 128;
+}
diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs
new file mode 100644
index 000000000..0abe20e4c
--- /dev/null
+++ b/library/core/benches/iter.rs
@@ -0,0 +1,393 @@
+use core::iter::*;
+use test::{black_box, Bencher};
+
+#[bench]
+fn bench_rposition(b: &mut Bencher) {
+ let it: Vec<usize> = (0..300).collect();
+ b.iter(|| {
+ it.iter().rposition(|&x| x <= 150);
+ });
+}
+
+#[bench]
+fn bench_skip_while(b: &mut Bencher) {
+ b.iter(|| {
+ let it = 0..100;
+ let mut sum = 0;
+ it.skip_while(|&x| {
+ sum += x;
+ sum < 4000
+ })
+ .all(|_| true);
+ });
+}
+
+#[bench]
+fn bench_multiple_take(b: &mut Bencher) {
+ let mut it = (0..42).cycle();
+ b.iter(|| {
+ let n = it.next().unwrap();
+ for _ in 0..n {
+ it.clone().take(it.next().unwrap()).all(|_| true);
+ }
+ });
+}
+
+fn scatter(x: i32) -> i32 {
+ (x * 31) % 127
+}
+
+#[bench]
+fn bench_max_by_key(b: &mut Bencher) {
+ b.iter(|| {
+ let it = 0..100;
+ it.map(black_box).max_by_key(|&x| scatter(x))
+ })
+}
+
+// https://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/
+#[bench]
+fn bench_max_by_key2(b: &mut Bencher) {
+ fn max_index_iter(array: &[i32]) -> usize {
+ array.iter().enumerate().max_by_key(|&(_, item)| item).unwrap().0
+ }
+
+ let mut data = vec![0; 1638];
+ data[514] = 9999;
+
+ b.iter(|| max_index_iter(&data));
+}
+
+#[bench]
+fn bench_max(b: &mut Bencher) {
+ b.iter(|| {
+ let it = 0..100;
+ it.map(black_box).map(scatter).max()
+ })
+}
+
+pub fn copy_zip(xs: &[u8], ys: &mut [u8]) {
+ for (a, b) in ys.iter_mut().zip(xs) {
+ *a = *b;
+ }
+}
+
+pub fn add_zip(xs: &[f32], ys: &mut [f32]) {
+ for (a, b) in ys.iter_mut().zip(xs) {
+ *a += *b;
+ }
+}
+
+#[bench]
+fn bench_zip_copy(b: &mut Bencher) {
+ let source = vec![0u8; 16 * 1024];
+ let mut dst = black_box(vec![0u8; 16 * 1024]);
+ b.iter(|| copy_zip(&source, &mut dst))
+}
+
+#[bench]
+fn bench_zip_add(b: &mut Bencher) {
+ let source = vec![1.; 16 * 1024];
+ let mut dst = vec![0.; 16 * 1024];
+ b.iter(|| add_zip(&source, &mut dst));
+}
+
+/// `Iterator::for_each` implemented as a plain loop.
+fn for_each_loop<I, F>(iter: I, mut f: F)
+where
+ I: Iterator,
+ F: FnMut(I::Item),
+{
+ for item in iter {
+ f(item);
+ }
+}
+
+/// `Iterator::for_each` implemented with `fold` for internal iteration.
+/// (except when `by_ref()` effectively disables that optimization.)
+fn for_each_fold<I, F>(iter: I, mut f: F)
+where
+ I: Iterator,
+ F: FnMut(I::Item),
+{
+ iter.fold((), move |(), item| f(item));
+}
+
+#[bench]
+fn bench_for_each_chain_loop(b: &mut Bencher) {
+ b.iter(|| {
+ let mut acc = 0;
+ let iter = (0i64..1000000).chain(0..1000000).map(black_box);
+ for_each_loop(iter, |x| acc += x);
+ acc
+ });
+}
+
+#[bench]
+fn bench_for_each_chain_fold(b: &mut Bencher) {
+ b.iter(|| {
+ let mut acc = 0;
+ let iter = (0i64..1000000).chain(0..1000000).map(black_box);
+ for_each_fold(iter, |x| acc += x);
+ acc
+ });
+}
+
+#[bench]
+fn bench_for_each_chain_ref_fold(b: &mut Bencher) {
+ b.iter(|| {
+ let mut acc = 0;
+ let mut iter = (0i64..1000000).chain(0..1000000).map(black_box);
+ for_each_fold(iter.by_ref(), |x| acc += x);
+ acc
+ });
+}
+
+/// Helper to benchmark `sum` for iterators taken by value which
+/// can optimize `fold`, and by reference which cannot.
+macro_rules! bench_sums {
+ ($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => {
+ #[bench]
+ fn $bench_sum(b: &mut Bencher) {
+ b.iter(|| -> i64 { $iter.map(black_box).sum() });
+ }
+
+ #[bench]
+ fn $bench_ref_sum(b: &mut Bencher) {
+ b.iter(|| -> i64 { $iter.map(black_box).by_ref().sum() });
+ }
+ };
+}
+
+bench_sums! {
+ bench_flat_map_sum,
+ bench_flat_map_ref_sum,
+ (0i64..1000).flat_map(|x| x..x+1000)
+}
+
+bench_sums! {
+ bench_flat_map_chain_sum,
+ bench_flat_map_chain_ref_sum,
+ (0i64..1000000).flat_map(|x| once(x).chain(once(x)))
+}
+
+bench_sums! {
+ bench_enumerate_sum,
+ bench_enumerate_ref_sum,
+ (0i64..1000000).enumerate().map(|(i, x)| x * i as i64)
+}
+
+bench_sums! {
+ bench_enumerate_chain_sum,
+ bench_enumerate_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64)
+}
+
+bench_sums! {
+ bench_filter_sum,
+ bench_filter_ref_sum,
+ (0i64..1000000).filter(|x| x % 3 == 0)
+}
+
+bench_sums! {
+ bench_filter_chain_sum,
+ bench_filter_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).filter(|x| x % 3 == 0)
+}
+
+bench_sums! {
+ bench_filter_map_sum,
+ bench_filter_map_ref_sum,
+ (0i64..1000000).filter_map(|x| x.checked_mul(x))
+}
+
+bench_sums! {
+ bench_filter_map_chain_sum,
+ bench_filter_map_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x))
+}
+
+bench_sums! {
+ bench_fuse_sum,
+ bench_fuse_ref_sum,
+ (0i64..1000000).fuse()
+}
+
+bench_sums! {
+ bench_fuse_chain_sum,
+ bench_fuse_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).fuse()
+}
+
+bench_sums! {
+ bench_inspect_sum,
+ bench_inspect_ref_sum,
+ (0i64..1000000).inspect(|_| {})
+}
+
+bench_sums! {
+ bench_inspect_chain_sum,
+ bench_inspect_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).inspect(|_| {})
+}
+
+bench_sums! {
+ bench_peekable_sum,
+ bench_peekable_ref_sum,
+ (0i64..1000000).peekable()
+}
+
+bench_sums! {
+ bench_peekable_chain_sum,
+ bench_peekable_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).peekable()
+}
+
+bench_sums! {
+ bench_skip_sum,
+ bench_skip_ref_sum,
+ (0i64..1000000).skip(1000)
+}
+
+bench_sums! {
+ bench_skip_chain_sum,
+ bench_skip_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).skip(1000)
+}
+
+bench_sums! {
+ bench_skip_while_sum,
+ bench_skip_while_ref_sum,
+ (0i64..1000000).skip_while(|&x| x < 1000)
+}
+
+bench_sums! {
+ bench_skip_while_chain_sum,
+ bench_skip_while_chain_ref_sum,
+ (0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000)
+}
+
+bench_sums! {
+ bench_take_while_chain_sum,
+ bench_take_while_chain_ref_sum,
+ (0i64..1000000).chain(1000000..).take_while(|&x| x < 1111111)
+}
+
+bench_sums! {
+ bench_cycle_take_sum,
+ bench_cycle_take_ref_sum,
+ (0..10000).cycle().take(1000000)
+}
+
+bench_sums! {
+ bench_cycle_skip_take_sum,
+ bench_cycle_skip_take_ref_sum,
+ (0..100000).cycle().skip(1000000).take(1000000)
+}
+
+bench_sums! {
+ bench_cycle_take_skip_sum,
+ bench_cycle_take_skip_ref_sum,
+ (0..100000).cycle().take(1000000).skip(100000)
+}
+
+bench_sums! {
+ bench_skip_cycle_skip_zip_add_sum,
+ bench_skip_cycle_skip_zip_add_ref_sum,
+ (0..100000).skip(100).cycle().skip(100)
+ .zip((0..100000).cycle().skip(10))
+ .map(|(a,b)| a+b)
+ .skip(100000)
+ .take(1000000)
+}
+
+// Checks whether Skip<Zip<A,B>> is as fast as Zip<Skip<A>, Skip<B>>, from
+// https://users.rust-lang.org/t/performance-difference-between-iterator-zip-and-skip-order/15743
+#[bench]
+fn bench_zip_then_skip(b: &mut Bencher) {
+ let v: Vec<_> = (0..100_000).collect();
+ let t: Vec<_> = (0..100_000).collect();
+
+ b.iter(|| {
+ let s = v
+ .iter()
+ .zip(t.iter())
+ .skip(10000)
+ .take_while(|t| *t.0 < 10100)
+ .map(|(a, b)| *a + *b)
+ .sum::<u64>();
+ assert_eq!(s, 2009900);
+ });
+}
+#[bench]
+fn bench_skip_then_zip(b: &mut Bencher) {
+ let v: Vec<_> = (0..100_000).collect();
+ let t: Vec<_> = (0..100_000).collect();
+
+ b.iter(|| {
+ let s = v
+ .iter()
+ .skip(10000)
+ .zip(t.iter().skip(10000))
+ .take_while(|t| *t.0 < 10100)
+ .map(|(a, b)| *a + *b)
+ .sum::<u64>();
+ assert_eq!(s, 2009900);
+ });
+}
+
+#[bench]
+fn bench_filter_count(b: &mut Bencher) {
+ b.iter(|| (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count())
+}
+
+#[bench]
+fn bench_filter_ref_count(b: &mut Bencher) {
+ b.iter(|| (0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count())
+}
+
+#[bench]
+fn bench_filter_chain_count(b: &mut Bencher) {
+ b.iter(|| (0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count())
+}
+
+#[bench]
+fn bench_filter_chain_ref_count(b: &mut Bencher) {
+ b.iter(|| {
+ (0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()
+ })
+}
+
+#[bench]
+fn bench_partial_cmp(b: &mut Bencher) {
+ b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box)))
+}
+
+#[bench]
+fn bench_lt(b: &mut Bencher) {
+ b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box)))
+}
+
+#[bench]
+fn bench_trusted_random_access_adapters(b: &mut Bencher) {
+ let vec1: Vec<_> = (0usize..100000).collect();
+ let vec2 = black_box(vec1.clone());
+ b.iter(|| {
+ let mut iter = vec1
+ .iter()
+ .copied()
+ .enumerate()
+ .map(|(idx, e)| idx.wrapping_add(e))
+ .zip(vec2.iter().copied())
+ .map(|(a, b)| a.wrapping_add(b))
+ .fuse();
+ let mut acc: usize = 0;
+ let size = iter.size();
+ for i in 0..size {
+ // SAFETY: TRA requirements are satisfied by 0..size iteration and then dropping the
+ // iterator.
+ acc = acc.wrapping_add(unsafe { iter.__iterator_get_unchecked(i) });
+ }
+ acc
+ })
+}
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
new file mode 100644
index 000000000..a6c174d2f
--- /dev/null
+++ b/library/core/benches/lib.rs
@@ -0,0 +1,28 @@
+// wasm32 does not support benches (no time).
+#![cfg(not(target_arch = "wasm32"))]
+#![feature(flt2dec)]
+#![feature(int_log)]
+#![feature(test)]
+#![feature(trusted_random_access)]
+
+extern crate test;
+
+mod any;
+mod ascii;
+mod char;
+mod fmt;
+mod hash;
+mod iter;
+mod num;
+mod ops;
+mod pattern;
+mod slice;
+mod str;
+
+/// Returns a `rand::Rng` seeded with a consistent seed.
+///
+/// This is done to avoid introducing nondeterminism in benchmark results.
+fn bench_rng() -> rand_xorshift::XorShiftRng {
+ const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ rand::SeedableRng::from_seed(SEED)
+}
diff --git a/library/core/benches/num/dec2flt/mod.rs b/library/core/benches/num/dec2flt/mod.rs
new file mode 100644
index 000000000..305baa687
--- /dev/null
+++ b/library/core/benches/num/dec2flt/mod.rs
@@ -0,0 +1,57 @@
+use test::Bencher;
+
+#[bench]
+fn bench_0(b: &mut Bencher) {
+ b.iter(|| "0.0".parse::<f64>());
+}
+
+#[bench]
+fn bench_42(b: &mut Bencher) {
+ b.iter(|| "42".parse::<f64>());
+}
+
+#[bench]
+fn bench_huge_int(b: &mut Bencher) {
+ // 2^128 - 1
+ b.iter(|| "170141183460469231731687303715884105727".parse::<f64>());
+}
+
+#[bench]
+fn bench_short_decimal(b: &mut Bencher) {
+ b.iter(|| "1234.5678".parse::<f64>());
+}
+
+#[bench]
+fn bench_pi_long(b: &mut Bencher) {
+ b.iter(|| "3.14159265358979323846264338327950288".parse::<f64>());
+}
+
+#[bench]
+fn bench_pi_short(b: &mut Bencher) {
+ b.iter(|| "3.141592653589793".parse::<f64>())
+}
+
+#[bench]
+fn bench_1e150(b: &mut Bencher) {
+ b.iter(|| "1e150".parse::<f64>());
+}
+
+#[bench]
+fn bench_long_decimal_and_exp(b: &mut Bencher) {
+ b.iter(|| "727501488517303786137132964064381141071e-123".parse::<f64>());
+}
+
+#[bench]
+fn bench_min_subnormal(b: &mut Bencher) {
+ b.iter(|| "5e-324".parse::<f64>());
+}
+
+#[bench]
+fn bench_min_normal(b: &mut Bencher) {
+ b.iter(|| "2.2250738585072014e-308".parse::<f64>());
+}
+
+#[bench]
+fn bench_max(b: &mut Bencher) {
+ b.iter(|| "1.7976931348623157e308".parse::<f64>());
+}
diff --git a/library/core/benches/num/flt2dec/mod.rs b/library/core/benches/num/flt2dec/mod.rs
new file mode 100644
index 000000000..32fd5e626
--- /dev/null
+++ b/library/core/benches/num/flt2dec/mod.rs
@@ -0,0 +1,37 @@
+mod strategy {
+ mod dragon;
+ mod grisu;
+}
+
+use core::num::flt2dec::MAX_SIG_DIGITS;
+use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
+use std::io::Write;
+use std::vec::Vec;
+use test::Bencher;
+
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+ match decode(v).1 {
+ FullDecoded::Finite(decoded) => decoded,
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
+ }
+}
+
+#[bench]
+fn bench_small_shortest(b: &mut Bencher) {
+ let mut buf = Vec::with_capacity(20);
+
+ b.iter(|| {
+ buf.clear();
+ write!(&mut buf, "{}", 3.1415926f64).unwrap()
+ });
+}
+
+#[bench]
+fn bench_big_shortest(b: &mut Bencher) {
+ let mut buf = Vec::with_capacity(300);
+
+ b.iter(|| {
+ buf.clear();
+ write!(&mut buf, "{}", f64::MAX).unwrap()
+ });
+}
diff --git a/library/core/benches/num/flt2dec/strategy/dragon.rs b/library/core/benches/num/flt2dec/strategy/dragon.rs
new file mode 100644
index 000000000..319b9773e
--- /dev/null
+++ b/library/core/benches/num/flt2dec/strategy/dragon.rs
@@ -0,0 +1,76 @@
+use super::super::*;
+use core::num::flt2dec::strategy::dragon::*;
+use std::mem::MaybeUninit;
+use test::Bencher;
+
+#[bench]
+fn bench_small_shortest(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
+ b.iter(|| {
+ format_shortest(&decoded, &mut buf);
+ });
+}
+
+#[bench]
+fn bench_big_shortest(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
+ b.iter(|| {
+ format_shortest(&decoded, &mut buf);
+ });
+}
+
+#[bench]
+fn bench_small_exact_3(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); 3];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_big_exact_3(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); 3];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_small_exact_12(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); 12];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_big_exact_12(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); 12];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_small_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_big_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs
new file mode 100644
index 000000000..8e47a046c
--- /dev/null
+++ b/library/core/benches/num/flt2dec/strategy/grisu.rs
@@ -0,0 +1,83 @@
+use super::super::*;
+use core::num::flt2dec::strategy::grisu::*;
+use std::mem::MaybeUninit;
+use test::Bencher;
+
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+ match decode(v).1 {
+ FullDecoded::Finite(decoded) => decoded,
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
+ }
+}
+
+#[bench]
+fn bench_small_shortest(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
+ b.iter(|| {
+ format_shortest(&decoded, &mut buf);
+ });
+}
+
+#[bench]
+fn bench_big_shortest(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS];
+ b.iter(|| {
+ format_shortest(&decoded, &mut buf);
+ });
+}
+
+#[bench]
+fn bench_small_exact_3(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); 3];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_big_exact_3(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); 3];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_small_exact_12(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); 12];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_big_exact_12(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); 12];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_small_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(3.141592f64);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
+
+#[bench]
+fn bench_big_exact_inf(b: &mut Bencher) {
+ let decoded = decode_finite(f64::MAX);
+ let mut buf = [MaybeUninit::new(0); 1024];
+ b.iter(|| {
+ format_exact(&decoded, &mut buf, i16::MIN);
+ });
+}
diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs
new file mode 100644
index 000000000..19864d2d4
--- /dev/null
+++ b/library/core/benches/num/int_log/mod.rs
@@ -0,0 +1,58 @@
+use rand::Rng;
+use test::{black_box, Bencher};
+
+macro_rules! int_log_bench {
+ ($t:ty, $predictable:ident, $random:ident, $random_small:ident) => {
+ #[bench]
+ fn $predictable(bench: &mut Bencher) {
+ bench.iter(|| {
+ for n in 0..(<$t>::BITS / 8) {
+ for i in 1..=(100 as $t) {
+ let x = black_box(i << (n * 8));
+ black_box(x.log10());
+ }
+ }
+ });
+ }
+
+ #[bench]
+ fn $random(bench: &mut Bencher) {
+ let mut rng = crate::bench_rng();
+ /* Exponentially distributed random numbers from the whole range of the type. */
+ let numbers: Vec<$t> = (0..256)
+ .map(|_| {
+ let x = rng.gen::<$t>() >> rng.gen_range(0, <$t>::BITS);
+ if x != 0 { x } else { 1 }
+ })
+ .collect();
+ bench.iter(|| {
+ for x in &numbers {
+ black_box(black_box(x).log10());
+ }
+ });
+ }
+
+ #[bench]
+ fn $random_small(bench: &mut Bencher) {
+ let mut rng = crate::bench_rng();
+ /* Exponentially distributed random numbers from the range 0..256. */
+ let numbers: Vec<$t> = (0..256)
+ .map(|_| {
+ let x = (rng.gen::<u8>() >> rng.gen_range(0, u8::BITS)) as $t;
+ if x != 0 { x } else { 1 }
+ })
+ .collect();
+ bench.iter(|| {
+ for x in &numbers {
+ black_box(black_box(x).log10());
+ }
+ });
+ }
+ };
+}
+
+int_log_bench! {u8, u8_log10_predictable, u8_log10_random, u8_log10_random_small}
+int_log_bench! {u16, u16_log10_predictable, u16_log10_random, u16_log10_random_small}
+int_log_bench! {u32, u32_log10_predictable, u32_log10_random, u32_log10_random_small}
+int_log_bench! {u64, u64_log10_predictable, u64_log10_random, u64_log10_random_small}
+int_log_bench! {u128, u128_log10_predictable, u128_log10_random, u128_log10_random_small}
diff --git a/library/core/benches/num/mod.rs b/library/core/benches/num/mod.rs
new file mode 100644
index 000000000..2f9cad272
--- /dev/null
+++ b/library/core/benches/num/mod.rs
@@ -0,0 +1,108 @@
+mod dec2flt;
+mod flt2dec;
+mod int_log;
+
+use std::str::FromStr;
+use test::Bencher;
+
+const ASCII_NUMBERS: [&str; 19] = [
+ "0",
+ "1",
+ "2",
+ "43",
+ "765",
+ "76567",
+ "987245987",
+ "-4aa32",
+ "1786235",
+ "8723095",
+ "f##5s",
+ "83638730",
+ "-2345",
+ "562aa43",
+ "-1",
+ "-0",
+ "abc",
+ "xyz",
+ "c0ffee",
+];
+
+macro_rules! from_str_bench {
+ ($mac:ident, $t:ty) => {
+ #[bench]
+ fn $mac(b: &mut Bencher) {
+ b.iter(|| {
+ ASCII_NUMBERS
+ .iter()
+ .cycle()
+ .take(5_000)
+ .filter_map(|s| <$t>::from_str(s).ok())
+ .max()
+ })
+ }
+ };
+}
+
+macro_rules! from_str_radix_bench {
+ ($mac:ident, $t:ty, $radix:expr) => {
+ #[bench]
+ fn $mac(b: &mut Bencher) {
+ b.iter(|| {
+ ASCII_NUMBERS
+ .iter()
+ .cycle()
+ .take(5_000)
+ .filter_map(|s| <$t>::from_str_radix(s, $radix).ok())
+ .max()
+ })
+ }
+ };
+}
+
+from_str_bench!(bench_u8_from_str, u8);
+from_str_radix_bench!(bench_u8_from_str_radix_2, u8, 2);
+from_str_radix_bench!(bench_u8_from_str_radix_10, u8, 10);
+from_str_radix_bench!(bench_u8_from_str_radix_16, u8, 16);
+from_str_radix_bench!(bench_u8_from_str_radix_36, u8, 36);
+
+from_str_bench!(bench_u16_from_str, u16);
+from_str_radix_bench!(bench_u16_from_str_radix_2, u16, 2);
+from_str_radix_bench!(bench_u16_from_str_radix_10, u16, 10);
+from_str_radix_bench!(bench_u16_from_str_radix_16, u16, 16);
+from_str_radix_bench!(bench_u16_from_str_radix_36, u16, 36);
+
+from_str_bench!(bench_u32_from_str, u32);
+from_str_radix_bench!(bench_u32_from_str_radix_2, u32, 2);
+from_str_radix_bench!(bench_u32_from_str_radix_10, u32, 10);
+from_str_radix_bench!(bench_u32_from_str_radix_16, u32, 16);
+from_str_radix_bench!(bench_u32_from_str_radix_36, u32, 36);
+
+from_str_bench!(bench_u64_from_str, u64);
+from_str_radix_bench!(bench_u64_from_str_radix_2, u64, 2);
+from_str_radix_bench!(bench_u64_from_str_radix_10, u64, 10);
+from_str_radix_bench!(bench_u64_from_str_radix_16, u64, 16);
+from_str_radix_bench!(bench_u64_from_str_radix_36, u64, 36);
+
+from_str_bench!(bench_i8_from_str, i8);
+from_str_radix_bench!(bench_i8_from_str_radix_2, i8, 2);
+from_str_radix_bench!(bench_i8_from_str_radix_10, i8, 10);
+from_str_radix_bench!(bench_i8_from_str_radix_16, i8, 16);
+from_str_radix_bench!(bench_i8_from_str_radix_36, i8, 36);
+
+from_str_bench!(bench_i16_from_str, i16);
+from_str_radix_bench!(bench_i16_from_str_radix_2, i16, 2);
+from_str_radix_bench!(bench_i16_from_str_radix_10, i16, 10);
+from_str_radix_bench!(bench_i16_from_str_radix_16, i16, 16);
+from_str_radix_bench!(bench_i16_from_str_radix_36, i16, 36);
+
+from_str_bench!(bench_i32_from_str, i32);
+from_str_radix_bench!(bench_i32_from_str_radix_2, i32, 2);
+from_str_radix_bench!(bench_i32_from_str_radix_10, i32, 10);
+from_str_radix_bench!(bench_i32_from_str_radix_16, i32, 16);
+from_str_radix_bench!(bench_i32_from_str_radix_36, i32, 36);
+
+from_str_bench!(bench_i64_from_str, i64);
+from_str_radix_bench!(bench_i64_from_str_radix_2, i64, 2);
+from_str_radix_bench!(bench_i64_from_str_radix_10, i64, 10);
+from_str_radix_bench!(bench_i64_from_str_radix_16, i64, 16);
+from_str_radix_bench!(bench_i64_from_str_radix_36, i64, 36);
diff --git a/library/core/benches/ops.rs b/library/core/benches/ops.rs
new file mode 100644
index 000000000..0a2be8a28
--- /dev/null
+++ b/library/core/benches/ops.rs
@@ -0,0 +1,19 @@
+use core::ops::*;
+use test::Bencher;
+
+// Overhead of dtors
+
+struct HasDtor {
+ _x: isize,
+}
+
+impl Drop for HasDtor {
+ fn drop(&mut self) {}
+}
+
+#[bench]
+fn alloc_obj_with_dtor(b: &mut Bencher) {
+ b.iter(|| {
+ HasDtor { _x: 10 };
+ })
+}
diff --git a/library/core/benches/pattern.rs b/library/core/benches/pattern.rs
new file mode 100644
index 000000000..480ac6f36
--- /dev/null
+++ b/library/core/benches/pattern.rs
@@ -0,0 +1,42 @@
+use test::black_box;
+use test::Bencher;
+
+#[bench]
+fn starts_with_char(b: &mut Bencher) {
+ let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+ b.iter(|| {
+ for _ in 0..1024 {
+ black_box(text.starts_with('k'));
+ }
+ })
+}
+
+#[bench]
+fn starts_with_str(b: &mut Bencher) {
+ let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+ b.iter(|| {
+ for _ in 0..1024 {
+ black_box(text.starts_with("k"));
+ }
+ })
+}
+
+#[bench]
+fn ends_with_char(b: &mut Bencher) {
+ let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+ b.iter(|| {
+ for _ in 0..1024 {
+ black_box(text.ends_with('k'));
+ }
+ })
+}
+
+#[bench]
+fn ends_with_str(b: &mut Bencher) {
+ let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+ b.iter(|| {
+ for _ in 0..1024 {
+ black_box(text.ends_with("k"));
+ }
+ })
+}
diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs
new file mode 100644
index 000000000..9b86a0ca9
--- /dev/null
+++ b/library/core/benches/slice.rs
@@ -0,0 +1,164 @@
+use test::black_box;
+use test::Bencher;
+
+enum Cache {
+ L1,
+ L2,
+ L3,
+}
+
+impl Cache {
+ fn size(&self) -> usize {
+ match self {
+ Cache::L1 => 1000, // 8kb
+ Cache::L2 => 10_000, // 80kb
+ Cache::L3 => 1_000_000, // 8Mb
+ }
+ }
+}
+
+fn binary_search<F>(b: &mut Bencher, cache: Cache, mapper: F)
+where
+ F: Fn(usize) -> usize,
+{
+ let size = cache.size();
+ let v = (0..size).map(&mapper).collect::<Vec<_>>();
+ let mut r = 0usize;
+ b.iter(move || {
+ // LCG constants from https://en.wikipedia.org/wiki/Numerical_Recipes.
+ r = r.wrapping_mul(1664525).wrapping_add(1013904223);
+ // Lookup the whole range to get 50% hits and 50% misses.
+ let i = mapper(r % size);
+ black_box(v.binary_search(&i).is_ok());
+ });
+}
+
+fn binary_search_worst_case(b: &mut Bencher, cache: Cache) {
+ let size = cache.size();
+
+ let mut v = vec![0; size];
+ let i = 1;
+ v[size - 1] = i;
+ b.iter(move || {
+ black_box(v.binary_search(&i).is_ok());
+ });
+}
+
+#[bench]
+fn binary_search_l1(b: &mut Bencher) {
+ binary_search(b, Cache::L1, |i| i * 2);
+}
+
+#[bench]
+fn binary_search_l2(b: &mut Bencher) {
+ binary_search(b, Cache::L2, |i| i * 2);
+}
+
+#[bench]
+fn binary_search_l3(b: &mut Bencher) {
+ binary_search(b, Cache::L3, |i| i * 2);
+}
+
+#[bench]
+fn binary_search_l1_with_dups(b: &mut Bencher) {
+ binary_search(b, Cache::L1, |i| i / 16 * 16);
+}
+
+#[bench]
+fn binary_search_l2_with_dups(b: &mut Bencher) {
+ binary_search(b, Cache::L2, |i| i / 16 * 16);
+}
+
+#[bench]
+fn binary_search_l3_with_dups(b: &mut Bencher) {
+ binary_search(b, Cache::L3, |i| i / 16 * 16);
+}
+
+#[bench]
+fn binary_search_l1_worst_case(b: &mut Bencher) {
+ binary_search_worst_case(b, Cache::L1);
+}
+
+#[bench]
+fn binary_search_l2_worst_case(b: &mut Bencher) {
+ binary_search_worst_case(b, Cache::L2);
+}
+
+#[bench]
+fn binary_search_l3_worst_case(b: &mut Bencher) {
+ binary_search_worst_case(b, Cache::L3);
+}
+
+#[derive(Clone)]
+struct Rgb(u8, u8, u8);
+
+impl Rgb {
+ fn gen(i: usize) -> Self {
+ Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42))
+ }
+}
+
+macro_rules! rotate {
+ ($fn:ident, $n:expr, $mapper:expr) => {
+ #[bench]
+ fn $fn(b: &mut Bencher) {
+ let mut x = (0usize..$n).map(&$mapper).collect::<Vec<_>>();
+ b.iter(|| {
+ for s in 0..x.len() {
+ x[..].rotate_right(s);
+ }
+ black_box(x[0].clone())
+ })
+ }
+ };
+}
+
+rotate!(rotate_u8, 32, |i| i as u8);
+rotate!(rotate_rgb, 32, Rgb::gen);
+rotate!(rotate_usize, 32, |i| i);
+rotate!(rotate_16_usize_4, 16, |i| [i; 4]);
+rotate!(rotate_16_usize_5, 16, |i| [i; 5]);
+rotate!(rotate_64_usize_4, 64, |i| [i; 4]);
+rotate!(rotate_64_usize_5, 64, |i| [i; 5]);
+
+macro_rules! swap_with_slice {
+ ($fn:ident, $n:expr, $mapper:expr) => {
+ #[bench]
+ fn $fn(b: &mut Bencher) {
+ let mut x = (0usize..$n).map(&$mapper).collect::<Vec<_>>();
+ let mut y = ($n..($n * 2)).map(&$mapper).collect::<Vec<_>>();
+ let mut skip = 0;
+ b.iter(|| {
+ for _ in 0..32 {
+ x[skip..].swap_with_slice(&mut y[..($n - skip)]);
+ skip = black_box(skip + 1) % 8;
+ }
+ black_box((x[$n / 3].clone(), y[$n * 2 / 3].clone()))
+ })
+ }
+ };
+}
+
+swap_with_slice!(swap_with_slice_u8_30, 30, |i| i as u8);
+swap_with_slice!(swap_with_slice_u8_3000, 3000, |i| i as u8);
+swap_with_slice!(swap_with_slice_rgb_30, 30, Rgb::gen);
+swap_with_slice!(swap_with_slice_rgb_3000, 3000, Rgb::gen);
+swap_with_slice!(swap_with_slice_usize_30, 30, |i| i);
+swap_with_slice!(swap_with_slice_usize_3000, 3000, |i| i);
+swap_with_slice!(swap_with_slice_4x_usize_30, 30, |i| [i; 4]);
+swap_with_slice!(swap_with_slice_4x_usize_3000, 3000, |i| [i; 4]);
+swap_with_slice!(swap_with_slice_5x_usize_30, 30, |i| [i; 5]);
+swap_with_slice!(swap_with_slice_5x_usize_3000, 3000, |i| [i; 5]);
+
+#[bench]
+fn fill_byte_sized(b: &mut Bencher) {
+ #[derive(Copy, Clone)]
+ struct NewType(u8);
+
+ let mut ary = [NewType(0); 1024];
+
+ b.iter(|| {
+ let slice = &mut ary[..];
+ black_box(slice.fill(black_box(NewType(42))));
+ });
+}
diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs
new file mode 100644
index 000000000..78865d81f
--- /dev/null
+++ b/library/core/benches/str.rs
@@ -0,0 +1,10 @@
+use std::str;
+use test::{black_box, Bencher};
+
+mod char_count;
+mod corpora;
+
+#[bench]
+fn str_validate_emoji(b: &mut Bencher) {
+ b.iter(|| str::from_utf8(black_box(corpora::emoji::LARGE.as_bytes())));
+}
diff --git a/library/core/benches/str/char_count.rs b/library/core/benches/str/char_count.rs
new file mode 100644
index 000000000..25d9b2e29
--- /dev/null
+++ b/library/core/benches/str/char_count.rs
@@ -0,0 +1,107 @@
+use super::corpora::*;
+use test::{black_box, Bencher};
+
+macro_rules! define_benches {
+ ($( fn $name: ident($arg: ident: &str) $body: block )+) => {
+ define_benches!(mod en_tiny, en::TINY, $($name $arg $body)+);
+ define_benches!(mod en_small, en::SMALL, $($name $arg $body)+);
+ define_benches!(mod en_medium, en::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod en_large, en::LARGE, $($name $arg $body)+);
+ define_benches!(mod en_huge, en::HUGE, $($name $arg $body)+);
+
+ define_benches!(mod zh_tiny, zh::TINY, $($name $arg $body)+);
+ define_benches!(mod zh_small, zh::SMALL, $($name $arg $body)+);
+ define_benches!(mod zh_medium, zh::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod zh_large, zh::LARGE, $($name $arg $body)+);
+ define_benches!(mod zh_huge, zh::HUGE, $($name $arg $body)+);
+
+ define_benches!(mod ru_tiny, ru::TINY, $($name $arg $body)+);
+ define_benches!(mod ru_small, ru::SMALL, $($name $arg $body)+);
+ define_benches!(mod ru_medium, ru::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod ru_large, ru::LARGE, $($name $arg $body)+);
+ define_benches!(mod ru_huge, ru::HUGE, $($name $arg $body)+);
+
+ define_benches!(mod emoji_tiny, emoji::TINY, $($name $arg $body)+);
+ define_benches!(mod emoji_small, emoji::SMALL, $($name $arg $body)+);
+ define_benches!(mod emoji_medium, emoji::MEDIUM, $($name $arg $body)+);
+ define_benches!(mod emoji_large, emoji::LARGE, $($name $arg $body)+);
+ define_benches!(mod emoji_huge, emoji::HUGE, $($name $arg $body)+);
+ };
+ (mod $mod_name: ident, $input: expr, $($name: ident $arg: ident $body: block)+) => {
+ mod $mod_name {
+ use super::*;
+ $(
+ #[bench]
+ fn $name(bencher: &mut Bencher) {
+ let input = $input;
+ bencher.bytes = input.len() as u64;
+ let mut input_s = input.to_string();
+ bencher.iter(|| {
+ let $arg: &str = &black_box(&mut input_s);
+ black_box($body)
+ })
+ }
+ )+
+ }
+ };
+}
+
+define_benches! {
+ fn case00_libcore(s: &str) {
+ libcore(s)
+ }
+
+ fn case01_filter_count_cont_bytes(s: &str) {
+ filter_count_cont_bytes(s)
+ }
+
+ fn case02_iter_increment(s: &str) {
+ iterator_increment(s)
+ }
+
+ fn case03_manual_char_len(s: &str) {
+ manual_char_len(s)
+ }
+}
+
+fn libcore(s: &str) -> usize {
+ s.chars().count()
+}
+
+#[inline]
+fn utf8_is_cont_byte(byte: u8) -> bool {
+ (byte as i8) < -64
+}
+
+fn filter_count_cont_bytes(s: &str) -> usize {
+ s.as_bytes().iter().filter(|&&byte| !utf8_is_cont_byte(byte)).count()
+}
+
+fn iterator_increment(s: &str) -> usize {
+ let mut c = 0;
+ for _ in s.chars() {
+ c += 1;
+ }
+ c
+}
+
+fn manual_char_len(s: &str) -> usize {
+ let s = s.as_bytes();
+ let mut c = 0;
+ let mut i = 0;
+ let l = s.len();
+ while i < l {
+ let b = s[i];
+ if b < 0x80 {
+ i += 1;
+ } else if b < 0xe0 {
+ i += 2;
+ } else if b < 0xf0 {
+ i += 3;
+ } else {
+ i += 4;
+ }
+ c += 1;
+ }
+ c
+}
diff --git a/library/core/benches/str/corpora.rs b/library/core/benches/str/corpora.rs
new file mode 100644
index 000000000..b4ac62506
--- /dev/null
+++ b/library/core/benches/str/corpora.rs
@@ -0,0 +1,88 @@
+//! Exposes a number of modules with different kinds of strings.
+//!
+//! Each module contains `&str` constants named `TINY`, `SMALL`, `MEDIUM`,
+//! `LARGE`, and `HUGE`.
+//!
+//! - The `TINY` string is generally around 8 bytes.
+//! - The `SMALL` string is generally around 30-40 bytes.
+//! - The `MEDIUM` string is generally around 600-700 bytes.
+//! - The `LARGE` string is the `MEDIUM` string repeated 8x, and is around 5kb.
+//! - The `HUGE` string is the `LARGE` string repeated 8x (or the `MEDIUM`
+//! string repeated 64x), and is around 40kb.
+//!
+//! Except for `mod emoji` (which is just a bunch of emoji), the strings were
+//! pulled from (localizations of) rust-lang.org.
+
+macro_rules! repeat8 {
+ ($s:expr) => {
+ concat!($s, $s, $s, $s, $s, $s, $s, $s)
+ };
+}
+
+macro_rules! define_consts {
+ ($s:literal) => {
+ pub const MEDIUM: &str = $s;
+ pub const LARGE: &str = repeat8!($s);
+ pub const HUGE: &str = repeat8!(repeat8!(repeat8!($s)));
+ };
+}
+
+pub mod en {
+ pub const TINY: &str = "Mary had";
+ pub const SMALL: &str = "Mary had a little lamb, Little lamb";
+ define_consts! {
+ "Rust is blazingly fast and memory-efficient: with no runtime or garbage
+ collector, it can power performance-critical services, run on embedded
+ devices, and easily integrate with other languages. Rust’s rich type system
+ and ownership model guarantee memory-safety and thread-safety — enabling you
+ to eliminate many classes of bugs at compile-time. Rust has great
+ documentation, a friendly compiler with useful error messages, and top-notch
+ tooling — an integrated package manager and build tool, smart multi-editor
+ support with auto-completion and type inspections, an auto-formatter, and
+ more."
+ }
+}
+
+pub mod zh {
+ pub const TINY: &str = "速度惊";
+ pub const SMALL: &str = "速度惊人且内存利用率极高";
+ define_consts! {
+ "Rust 速度惊人且内存利用率极高。由于\
+ 没有运行时和垃圾回收,它能够胜任对性能要\
+ 求特别高的服务,可以在嵌入式设备上运行,\
+ 还能轻松和其他语言集成。Rust 丰富的类型\
+ 系统和所有权模型保证了内存安全和线程安全,\
+ 让您在编译期就能够消除各种各样的错误。\
+ Rust 拥有出色的文档、友好的编译器和清晰\
+ 的错误提示信息, 还集成了一流的工具——\
+ 包管理器和构建工具, 智能地自动补全和类\
+ 型检验的多编辑器支持, 以及自动格式化代\
+ 码等等。"
+ }
+}
+
+pub mod ru {
+ pub const TINY: &str = "Сотни";
+ pub const SMALL: &str = "Сотни компаний по";
+ define_consts! {
+ "Сотни компаний по всему миру используют Rust в реальных\
+ проектах для быстрых кросс-платформенных решений с\
+ ограниченными ресурсами. Такие проекты, как Firefox,\
+ Dropbox и Cloudflare, используют Rust. Rust отлично\
+ подходит как для стартапов, так и для больших компаний,\
+ как для встраиваемых устройств, так и для масштабируемых\
+ web-сервисов. Мой самый большой комплимент Rust."
+ }
+}
+
+pub mod emoji {
+ pub const TINY: &str = "😀😃";
+ pub const SMALL: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘";
+ define_consts! {
+ "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶‍🌫️😏😒\
+ 🙄😬😮‍💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵‍💫🤯��🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨\
+ 😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊\
+ 💋💌💘💝💖💗💓��💕💟❣💔❤️‍🔥❤️‍🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💬👁️‍🗨️🗨🗯💭💤👋\
+ 🤚🖐✋🖖👌🤌🤏✌"
+ }
+}