From 98f61a3195663465bc2f65287fbcbe14761fe6a8 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 18:03:06 +0100 Subject: [PATCH 1/5] core/benches: Add `char::to_digit()` benchmarks --- src/libcore/benches/char/methods.rs | 42 +++++++++++++++++++++++++++++ src/libcore/benches/char/mod.rs | 11 ++++++++ src/libcore/benches/lib.rs | 1 + 3 files changed, 54 insertions(+) create mode 100644 src/libcore/benches/char/methods.rs create mode 100644 src/libcore/benches/char/mod.rs diff --git a/src/libcore/benches/char/methods.rs b/src/libcore/benches/char/methods.rs new file mode 100644 index 0000000000000..faf820d871cfa --- /dev/null +++ b/src/libcore/benches/char/methods.rs @@ -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 or the MIT license +// , 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()) +} diff --git a/src/libcore/benches/char/mod.rs b/src/libcore/benches/char/mod.rs new file mode 100644 index 0000000000000..a656e82cb61e6 --- /dev/null +++ b/src/libcore/benches/char/mod.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod methods; diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index ced77d779182a..d44f1577d56b0 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -15,6 +15,7 @@ extern crate core; extern crate test; mod any; +mod char; mod hash; mod iter; mod num; From 04aade83f2785d6ca43049ff89026ed930f792f1 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 17:49:38 +0100 Subject: [PATCH 2/5] core/char: Replace condition + `panic!()` with `assert!()` --- src/libcore/char/methods.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 35181afea3da6..fc212aa4f2086 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -121,9 +121,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_digit(self, radix: u32) -> Option { - if radix > 36 { - panic!("to_digit: radix is too high (maximum 36)"); - } + assert!(radix <= 36, "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, From 17f08fecfd81479e04fc5ea7590cecdb429c7ce3 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 18:05:46 +0100 Subject: [PATCH 3/5] core/char: Speed up `to_digit()` for `radix <= 10` ### 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) ``` --- src/libcore/char/methods.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index fc212aa4f2086..46b201f7bbf2c 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -122,12 +122,27 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { assert!(radix <= 36, "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, + if radix == 10 { + return match self { + '0' ..= '9' => Some(self as u32 - '0' as u32), + _ => None, + }; + } + + 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 } } From 64a517265297cc1d4e9e116dcbb06561c063c3d4 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 14 Nov 2018 08:55:53 +0100 Subject: [PATCH 4/5] core/char: Drop `radix == 10` special case This seems to perform equally well --- src/libcore/char/methods.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 46b201f7bbf2c..4207b3c776c7e 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -122,14 +122,7 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); - if radix == 10 { - return match self { - '0' ..= '9' => Some(self as u32 - '0' as u32), - _ => None, - }; - } - - let val = if radix < 10 { + let val = if radix <= 10 { match self { '0' ..= '9' => self as u32 - '0' as u32, _ => return None, From 7843e2792dce0f20d23b3c1cca51652013bef0ea Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 14 Nov 2018 11:26:00 +0100 Subject: [PATCH 5/5] core/char: Add comment to `to_digit()` --- src/libcore/char/methods.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 4207b3c776c7e..d6fcff644acf6 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -122,6 +122,9 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { 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,