Rollup merge of #55932 - Turbo87:to_digit, r=alexcrichton
core/char: Speed up `to_digit()` for `radix <= 10` I noticed that `char::to_digit()` seemed to do a bit of extra work for handling `[a-zA-Z]` characters. Since `to_digit(10)` seems to be the most common case (at least in the `rust` codebase) I thought it might be valuable to create a fast path for that case, and according to the benchmarks that I added in one of the commits it seems to pay off. I also created another fast path for the `radix < 10` case, which also seems to have a positive effect. It is very well possible that I'm measuring something entirely unrelated though, so please verify these numbers and let me know if I missed something! ### Before ``` # Run 1 test char::methods::bench_to_digit_radix_10 ... bench: 16,265 ns/iter (+/- 1,774) test char::methods::bench_to_digit_radix_16 ... bench: 13,938 ns/iter (+/- 2,479) test char::methods::bench_to_digit_radix_2 ... bench: 13,090 ns/iter (+/- 524) test char::methods::bench_to_digit_radix_36 ... bench: 14,236 ns/iter (+/- 1,949) # Run 2 test char::methods::bench_to_digit_radix_10 ... bench: 16,176 ns/iter (+/- 1,589) test char::methods::bench_to_digit_radix_16 ... bench: 13,896 ns/iter (+/- 3,140) test char::methods::bench_to_digit_radix_2 ... bench: 13,158 ns/iter (+/- 1,112) test char::methods::bench_to_digit_radix_36 ... bench: 14,206 ns/iter (+/- 1,312) # Run 3 test char::methods::bench_to_digit_radix_10 ... bench: 16,221 ns/iter (+/- 2,423) test char::methods::bench_to_digit_radix_16 ... bench: 14,361 ns/iter (+/- 3,926) test char::methods::bench_to_digit_radix_2 ... bench: 13,097 ns/iter (+/- 671) test char::methods::bench_to_digit_radix_36 ... bench: 14,388 ns/iter (+/- 1,068) ``` ### After ``` # Run 1 test char::methods::bench_to_digit_radix_10 ... bench: 11,521 ns/iter (+/- 552) test char::methods::bench_to_digit_radix_16 ... bench: 12,926 ns/iter (+/- 684) test char::methods::bench_to_digit_radix_2 ... bench: 11,266 ns/iter (+/- 1,085) test char::methods::bench_to_digit_radix_36 ... bench: 14,213 ns/iter (+/- 614) # Run 2 test char::methods::bench_to_digit_radix_10 ... bench: 11,424 ns/iter (+/- 1,042) test char::methods::bench_to_digit_radix_16 ... bench: 12,854 ns/iter (+/- 1,193) test char::methods::bench_to_digit_radix_2 ... bench: 11,193 ns/iter (+/- 716) test char::methods::bench_to_digit_radix_36 ... bench: 14,249 ns/iter (+/- 3,514) # Run 3 test char::methods::bench_to_digit_radix_10 ... bench: 11,469 ns/iter (+/- 685) test char::methods::bench_to_digit_radix_16 ... bench: 12,852 ns/iter (+/- 568) test char::methods::bench_to_digit_radix_2 ... bench: 11,275 ns/iter (+/- 1,356) test char::methods::bench_to_digit_radix_36 ... bench: 14,188 ns/iter (+/- 1,501) ``` I ran the benchmark using: ```sh python x.py bench src/libcore --stage 1 --keep-stage 0 --test-args "bench_to_digit" ```
This commit is contained in:
commit
f40f04bcc1
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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())
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
mod methods;
|
|
@ -15,6 +15,7 @@ extern crate core;
|
|||
extern crate test;
|
||||
|
||||
mod any;
|
||||
mod char;
|
||||
mod hash;
|
||||
mod iter;
|
||||
mod num;
|
||||
|
|
|
@ -121,15 +121,24 @@ impl char {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn to_digit(self, radix: u32) -> Option<u32> {
|
||||
if radix > 36 {
|
||||
panic!("to_digit: radix is too high (maximum 36)");
|
||||
}
|
||||
let val = match self {
|
||||
'0' ..= '9' => self as u32 - '0' as u32,
|
||||
'a' ..= 'z' => self as u32 - 'a' as u32 + 10,
|
||||
'A' ..= 'Z' => self as u32 - 'A' as u32 + 10,
|
||||
_ => return None,
|
||||
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
|
||||
|
||||
// the code is split up here to improve execution speed for cases where
|
||||
// the `radix` is constant and 10 or smaller
|
||||
let val = if radix <= 10 {
|
||||
match self {
|
||||
'0' ..= '9' => self as u32 - '0' as u32,
|
||||
_ => return None,
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
'0'..='9' => self as u32 - '0' as u32,
|
||||
'a'..='z' => self as u32 - 'a' as u32 + 10,
|
||||
'A'..='Z' => self as u32 - 'A' as u32 + 10,
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
|
||||
if val < radix { Some(val) }
|
||||
else { None }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue