-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
std::str: optimize is_utf8 & first_non_utf8_index. #12241
Conversation
This makes is_utf8 up to 40% faster Before: is_utf8_100_ascii ... bench: 123 ns/iter (+/- 9) is_utf8_100_multibyte ... bench: 134 ns/iter (+/- 7) from_utf8_lossy_100_ascii ... bench: 118 ns/iter (+/- 8) from_utf8_lossy_100_invalid ... bench: 378 ns/iter (+/- 12) from_utf8_lossy_100_multibyte ... bench: 135 ns/iter (+/- 5) from_utf8_lossy_invalid ... bench: 129 ns/iter (+/- 10) After: is_utf8_100_ascii ... bench: 77 ns/iter (+/- 4) is_utf8_100_multibyte ... bench: 96 ns/iter (+/- 9) from_utf8_lossy_100_ascii ... bench: 91 ns/iter (+/- 14) from_utf8_lossy_100_invalid ... bench: 414 ns/iter (+/- 30) from_utf8_lossy_100_multibyte ... bench: 119 ns/iter (+/- 10) from_utf8_lossy_invalid ... bench: 108 ns/iter (+/- 11)
I don't have a good explanation why cc @kballard |
I'm a little sad about all the new |
Well, it's having to manipulate pointers directly, so I find it unlikely that it can be anywhere near as efficient any other way. (e.g. manually stepping an iterator puts bounds checks on every access, like the old code.) |
I find it somewhat difficult to believe that it is impossible for safe code to reach this same level of performance. I'm not saying that this should have it all removed, but we're getting into the habit of reaching for |
@huonw |
I'm willing to r=me this, but I will defer to @alexcrichton's caution. |
Can this be implemented with a byte iterator? That would eliminate all bounds checks and you'd only have the |
@kballard both the new and old version are doing the same reallocations, so that doesn't explain why the timing is different between them. @alexcrichton the byte iterator is doing a bound check on every access (to see if it's at the end or not), and it's not being used in a tight loop, so I find it unlikely that LLVM will be able to streamline it well; I'll have a go though. |
@huonw Oh I see what you're saying. Perhaps |
@alexcrichton: Generally, iterator bounds checks are not optimized away at any level including LTO. It seems to me like LLVM does not have enough information. |
I investigated using iterators, results:
So the iterator versions is slightly faster than the current implementation (and with no |
Given how core a functionality |
If we do decide to go with this pointer approach, I'll write a proof of safety as comments in the source, as a substitute for compiler verification. |
Thank you for the thorough investigation, it's quite useful! I'm not quite ready to give up this battle though, I was curious why the pure-ascii case with iterators was so much slower than with pointers, so I did some investigation of my own. With this code I got these timings:
These results lead me to believe that the vector iterator isn't quite as good as it could be, and it's leading us to unsafe code in this implementation. With this in mind, I continue to be hesitant to merging this. I believe that the speedup from using unsafe code is at least partly a result of this vector iterator performance issue. |
Iterators in #12314. |
…t, r=jonas-schievink fix: revert float parsing "fix" to avoid macro-related panics Reverts rust-lang/rust-analyzer#12149 and the follow-up fixes, while keeping their tests. rust-lang/rust-analyzer#12149 has caused many unexpected panics related to macros, and the fixes for those are not straightforward and further complicate the MBE token conversion logic, which was already fairly hard to follow before these fixes.
This makes is_utf8 up to 40% faster
Before:
After: