-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Many is_ascii_ methods are slower than they have to be #65127
Comments
(I can’t seem to find the relevant part in the middle of this discord stream…) I’m not sure what you mean by “corrupt”. But maybe Once upon a time That said, would it actually be faster? Maybe the optimizer already does its job well. If you want to work on this, consider adding some benchmark to show that code duplication is worth it. |
Oh it seems the Discord link is a bit buggy. Try searching for |
I think the minimal standard here should be a benchmark before we change the implementation. Can you provide that? |
I'm not that experienced with Rust yet, sorry. I just wanted to point out this possible performance regression. cmp edi, 128
jae .LBB0_1
add dil, -65
mov al, 1
cmp dil, 25
ja .LBB0_1
ret vs. add edi, -65
cmp edi, 26
setb al
ret |
Looking at the assembly, it seems that the problem is the These three functions produce identical assembly: pub fn foo(c: char) -> bool {
match c as u8 {
65..=90 => true,
_ => false
}
}
pub fn bar(c: char) -> bool {
match c {
'A'..='Z' => true,
_ => false,
}
}
pub fn baz(c: char) -> bool {
(c as u8).is_ascii_uppercase()
} So, it seems that the I could make a PR for this. |
Here are some benchmarks: #![feature(test)]
extern crate test;
use test::Bencher;
#[inline(always)]
fn custom_ascii_uppercase_without_ascii_check(c: char) -> bool {
match c {
'A'..='Z' => true,
_ => false,
}
}
#[inline(always)]
fn custom_ascii_uppercase_with_ascii_check_builtin_is_ascii(c: char) -> bool {
c.is_ascii() && match c {
'A'..='Z' => true,
_ => false,
}
}
#[inline(always)]
fn custom_ascii_uppercase_with_ascii_check_custom_is_ascii_convert_to_u8(c: char) -> bool {
c as u8 <= 0x7fu8 && match c {
'A'..='Z' => true,
_ => false,
}
}
#[inline(always)]
fn custom_ascii_uppercase_with_ascii_check_custom_is_ascii_convert_to_u32(c: char) -> bool {
c as u32 <= 0x7fu32 && match c {
'A'..='Z' => true,
_ => false,
}
}
#[bench]
fn bench_custom_ascii_uppercase_without_ascii_check(b: &mut Bencher) {
let x = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
b.iter(|| {
for c in x.chars() {
test::black_box(custom_ascii_uppercase_without_ascii_check(c));
}
});
}
#[bench]
fn bench_custom_ascii_uppercase_with_ascii_check_builtin_is_ascii(b: &mut Bencher) {
let x = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
b.iter(|| {
for c in x.chars() {
test::black_box(custom_ascii_uppercase_with_ascii_check_builtin_is_ascii(c));
}
});
}
#[bench]
fn bench_custom_ascii_uppercase_with_ascii_check_custom_is_ascii_convert_to_u8(b: &mut Bencher) {
let x = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
b.iter(|| {
for c in x.chars() {
test::black_box(custom_ascii_uppercase_with_ascii_check_custom_is_ascii_convert_to_u8(c));
}
});
}
#[bench]
fn bench_custom_ascii_uppercase_with_ascii_check_custom_is_ascii_convert_to_u32(b: &mut Bencher) {
let x = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
b.iter(|| {
for c in x.chars() {
test::black_box(custom_ascii_uppercase_with_ascii_check_custom_is_ascii_convert_to_u32(c));
}
});
}
#[bench]
fn bench_builtin_ascii_uppercase(b: &mut Bencher) {
let x = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
b.iter(|| {
for c in x.chars() {
test::black_box(c.is_ascii_uppercase());
}
});
}
So it seems that removing the |
|
I noticed this
is_ascii
check:rust/src/libcore/char/methods.rs
Line 1078 in 6187684
Then someone told me it's there because of the
as u8
. If you pass a non-ASCII char, theas u8
would corrupt that char. That's why theis_ascii
check is there before it. But then I wondered: why isn't this just cast to a bigger data type that includes all Unicode code points? This method (and others) are slower than they have to be.Also see this discussion in Discord with more valuable information: https://discordapp.com/channels/442252698964721669/443150878111694848/629982972052897792.
The text was updated successfully, but these errors were encountered: