-
-
Notifications
You must be signed in to change notification settings - Fork 502
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
perf(lexer): use SIMD char search when parsing numbers #3250
Conversation
Your org has enabled the Graphite merge queue for merging into mainAdd the label “merge” to the PR and Graphite will automatically add it to the merge queue when it’s ready to merge. Or use the label “hotfix” to add to the merge queue as a hot fix. You must have a Graphite account and log in to Graphite in order to use the merge queue. Sign up using this link. |
CodSpeed Performance ReportMerging #3250 will not alter performanceComparing Summary
|
Looks like it doesn't help, so I'm closing this PR |
The benchmark probably doesn't have any relevant data, assigning @overlookmotel for a quick look. |
I can see 3 reasons why this appears to be slightly hurting performance rather than improving it:
oxc/crates/oxc_parser/src/lexer/mod.rs Lines 98 to 99 in eefb66f
But... if we want to optimize this, can I suggest a different approach? The lexer already iterates through the characters of the source code comprising the number, and deals with
@DonIsaac What do you think of that approach? Also, can I ask out of interest: What was your motivation for getting into this? Were you using Oxc on some input with lots of |
@overlookmotel Your suggestions look sound. I like the idea of underscore checking during lexing (as per suggestion 2). Since we already need to iterate over numbers there, we could skip the use of As for suggestion 1, I like the idea of storing underscore data within the number's My motivation for getting into this is that I've spent time optimizing other parts of Oxc before, but never the most important part: the lexer and parser. It's so heavily optimized it's hard to find anything that needs improving. I'm not experiencing any problems with underscores, it's just optimization for optimization's sake 😄 |
@DonIsaac Thanks for coming back.
A man after my own heart!
Yes, you're right, it is verbose and unwieldy. But there is a perf advantage to keeping What we can do is add explicit discriminants to Personally, my view is that as the lexer is the most primitive level of the stack, and everything else depends on it, it's acceptable to be quite nasty code, as long as it's as fast as possible. But that's just my opinion, feel free to disagree.
I actually see quite a lot of opportunity for further optimization in the lexer. For a start, everywhere we use the If by any chance you'd be interested in taking up that baton, I'd be very happy to talk it through with you. |
@@ -96,3 +96,42 @@ pub fn parse_big_int(s: &str, kind: Kind) -> Result<BigInt, &'static str> { | |||
}; | |||
BigInt::parse_bytes(s.as_bytes(), radix).ok_or("invalid bigint") | |||
} | |||
|
|||
#[inline] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a deoptimization I think, it will bust the cpu cache for loading so many CPU instructions, #[cold]
should be the better option here.
Remember, data oriented design, is thinking about the statistics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to contradict you Boshen, but I don't think #[cold]
is the right option here either.
#[cold]
is for telling the branch predictor "this function is rarely called", and so to assume another arm in a match
is more likely to be the one which executes (or same in an if
/else
branch). But in this case, without_underscores
is always called, so #[cold]
won't do anything.
If want to make sure the function doesn't get inlined, use #[inline(never)]
. Or just don't use any attribute, and let the compiler decide whether to inline or not. The latter is usually the best option.
So I agree with you that #[inline]
should be removed here, but probably not replaced with anything else.
FYI, I think I've over-used #[cold]
in the lexer, and could probably remove some of them. I know more now than I did in Jan!
numbers are pretty short, and underscores are rare, so this routine may need to be done differently. Feel free to close the PR again 😅 |
What This PR Does
Use memchr_iter to find and remove underscores when parsing number literals.
I'm seeing some performance improvements when running benchmarks on my machine, but I want confirmation from the CI benchmark job.