-
-
Notifications
You must be signed in to change notification settings - Fork 475
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(semantic): calculate number of nodes, scopes, symbols, references before visiting AST #4328
Conversation
CodSpeed Performance ReportMerging #4328 will improve performances by 30.11%Comparing Summary
Benchmarks breakdown
|
@Dunqing Is this related to oxc-project/backlog#31? If so, a couple of thoughts:
|
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. |
Yes, We'd better be able to do this in parser, and can expect this to be a sizeable performance gain |
Wow! This is banging! Much more than I expected. Only problem is I think the reason it's suffering is:
In my view we should not merge this as is because of the significant negative effect on that 1 benchmark. But what this experiment has done is show us there's a massive speed boost there for the taking, and that we should probably prioritize it above other perf work. |
I'm in favor of merging this and have a new issue on removing this ast pass, which is a clearer task. |
Does Rolldown's process involve running Semantic at all? If it does, merging this I'd imagine could hurt them, because A compromise would be to use a heuristic to enable/not enable the extra pass. e.g. only run on source files larger than 10 KB. That'd probably put us in the green for all benchmarks. What do you think of that option? |
I've opened a similar PR tackling this in a slightly different way: #4332. Sorry I didn't know what this one was doing, I was a little confused by the title! #4332 uses source text length as a heuristic for reserving memory instead of performing a traversal. It seems to perform worse overall than @Dunqing's approach, which I find quite interesting. |
Don's approach of estimating the required size of the
He's getting even better results on some benchmarks than this PR, but worse on others. If I can throw in my 2 cents as well... From my (fairly little) knowledge of OS-level memory stuff, I believe that allocating too much memory is not necessarily a problem. On architectures with virtual memory (which includes all the ones Oxc targets except WASM), allocating a huge slab of memory (e.g. 1 GB) doesn't actually consume 1 GB of physical memory. It only consumes 1 GB of virtual memory space. Pages of physical memory to "back" that virtual memory will only be allocated when that chunk of the memory is first written to. Like I said, I could be wrong about this - it's not an area I really know - but that's my rough understanding. Which is all a long way of saying: possibly the best strategy (except on WASM) is to estimate too high because that costs very little, whereas estimating too low will lead to the The big question though is where is this -6% perf penalty on the I don't really have much idea on that one. A good first step might be to figure out what the optimal size of all these |
Sure, I can try that out. Another possible option is to record symbols/AST nodes/etc that we find during the parse step. Thoughts? |
Yes, that is a good option. Please see my comment above. But:
Sorry, I think I've made everything too complicated! As Boshen said above, let's get this PR merged, and then iterate on it. So I propose:
|
Sounds good to me. Both of these approaches look good. Which one you would favor, I have no opinion on that. |
109.1 µs -> 116.6 µs Don't forget to look at the absolute numbers, -6% is huge but 7 µs is small. |
@@ -100,6 +100,39 @@ pub struct SemanticBuilderReturn<'a> { | |||
pub errors: Vec<OxcDiagnostic>, | |||
} | |||
|
|||
#[derive(Default)] | |||
pub struct Collector { |
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.
We should move this to another file and have some doc comments explaning the why before merge.
AST builder can do the counting :-) |
Yes, but currently
I thought % change was more important, on grounds that a large application might contain 10,000+ files this size (particularly if you include |
@Dunqing I see you're still working on this, so going to leave you alone to get on with it. Please shout when you're happy with it and would like a review. |
I corrected the issue with the |
Maybe we can do more, even count the number of each scope bindings? |
I assume you're only referring to nodes count being accurate here? Is symbol count for I don't think we can make symbol (aka binding) count completely accurate without building scope tree (which would defeat the point of As I said above, I don't think we necessarily need to make the counts 100% accurate. Over-estimating is fine. It may be that the cost of complicating
Yes, maybe that would be good - could size the bindings hash map for each scope correctly up front. But where do we store those "bindings per scope" counts? Would have to be in a |
I got you mean. You are right. The counting is not complicated as it stands, we are not dealing with |
Rolldown's codspeed shows 1% ~ 4% faster than before |
I checked counts on latest version (2nd
The most problematic one is |
I found nodes over-estimated caused by When #4366 is merged. Only symbols are very over-estimated. [crates/oxc_semantic/src/builder.rs:289:13] collector = Collector {
node: 314759,
scope: 10554,
symbol: 15834,
reference: 78443,
}
[crates/oxc_semantic/src/builder.rs:292:13] Collector {
node: self.nodes.len(),
scope: self.scope.len(),
symbol: self.symbols.len(),
reference: self.symbols.references.len(),
} = Collector {
node: 314759,
scope: 10554,
symbol: 15674,
reference: 78443,
}
[Finished running. Exit status: 0] |
I don’t why this PR is merged !!!! I didn't click the merge button. And I don't see a revert button |
Reverted, reopen in #4367 |
LOLs! Github loves your perf work, it couldn't resist merging. |
**Related issue:** - Inspiration: oxc-project/oxc#4328
Y'all are CRACKED |
Note by @overlookmotel 20/7/24: Even though this PR shows as merged, that was by some weird malfunction of Github. It was immediately reverted, and the merge scrubbed from history of
main
branch. #4367 continues the work.