mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(semantic): pre-reserve unresolved_references using Stats::references (#22580)
## Summary The `unresolved_references` `Vec<(Ident, ReferenceId)>` inside `SemanticBuilder` grows from `cap = 0` via the default doubling policy — that's ~13 reallocations to reach the ~5k references of a moderately-sized TypeScript file (193 KB `binder.ts`), copying a cumulative ~16k entries (~250 KB of memory traffic) just to grow the buffer. `Stats` already knows the exact reference count up front (via `Stats::count` or passed in by the caller via `SemanticBuilder::with_stats`). Pre-reserving with `stats.references` eliminates all the growth reallocations. 8-line internal change. No public API impact. ## Benchmark ### `cargo bench --bench semantic` (local Criterion) | Bench | main | this PR | Δ | |---|---|---|---| | `RadixUI.jsx` (3 KB) | 3.155 µs | 3.046 µs | **−3.5%** | | `react.development.js` (72 KB) | 136.47 µs | 133.78 µs | **−2.0%** | | `cal.com.tsx` (1 MB TSX) | 2.7414 ms | 2.7064 ms | **−1.3%** | | `binder.ts` (193 KB TS) | 314.90 µs | 309.46 µs | **−1.7%** | All Criterion intervals non-overlapping. ### CodSpeed (precise, instruction-count based, from #22571 which tested the same commit) | Bench | Δ | |---|---| | `pipeline[binder.ts]` | **−4.34%** | | `semantic[binder.ts]` | **−9.75%** | | `semantic[react.development.js]` | **−5.06%** | CodSpeed's instruction-count measurement is more sensitive to allocator-call elimination than wall-clock Criterion, so the numbers are larger but consistent in direction. ## Why `reserve_exact` (not `reserve`) - `stats.references` is the exact total push count (asserted in debug builds via `Stats::assert_accurate`). No need for amortized growth headroom. - Matches the existing precedent in `Scoping::reserve` which uses `reserve_exact` on arena-allocated structures. - Sub-100% reserves (tested 50%) were empirically *worse* than no reserve — the single resulting realloc is a large-block alloc that misses the size-class fast paths the small doubling reallocs hit. So 100% is the optimum. ## Test Plan - [x] `cargo test -p oxc_semantic --lib --tests` — 71 tests pass - [x] `cargo bench --bench semantic` — wins above - [x] CodSpeed re-run on commit (positive results above) AI disclosure: drafted with Claude Code, reviewed manually.
This commit is contained in:
1 parent
652530a283
commit
7a4120ed92
4 files changed
+21
-12
No files matched your search
@@ -288,6 +288,7 @@ impl<'a> SemanticBuilder<'a> {
|
||||
stats.references as usize,
|
||||
stats.scopes as usize,
|
||||
);
|
||||
self.unresolved_references.reserve_exact(stats.references as usize);
|
||||
|
||||
// Visit AST to generate scopes tree etc
|
||||
self.visit_program(program);
|
||||
|
||||
@@ -16,6 +16,14 @@ impl<'a> UnresolvedReferences<'a> {
|
||||
Self { references: Vec::new() }
|
||||
}
|
||||
|
||||
/// Reserve exactly `additional` more slots in the underlying `Vec`.
|
||||
/// Avoids growth reallocations when the expected count is known up-front
|
||||
/// (typically from [`crate::Stats::count`]).
|
||||
#[inline]
|
||||
pub(crate) fn reserve_exact(&mut self, additional: usize) {
|
||||
self.references.reserve_exact(additional);
|
||||
}
|
||||
|
||||
/// Push an unresolved reference to the flat list.
|
||||
#[inline]
|
||||
pub(crate) fn push(&mut self, name: Ident<'a>, reference_id: ReferenceId) {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
File | File size || Sys allocs | Sys reallocs || Arena allocs | Arena reallocs
|
||||
---------------------------------------------------------------------------------------------------------------------------
|
||||
checker.ts | 2.92 MB || 226 | 37 || 152662 | 28244
|
||||
checker.ts | 2.92 MB || 226 | 7 || 152662 | 28244
|
||||
|
||||
cal.com.tsx | 1.06 MB || 16287 | 46 || 37156 | 4570
|
||||
cal.com.tsx | 1.06 MB || 16287 | 20 || 37156 | 4570
|
||||
|
||||
RadixUIAdoptionSection.jsx | 2.52 kB || 24 | 6 || 31 | 6
|
||||
RadixUIAdoptionSection.jsx | 2.52 kB || 24 | 0 || 31 | 6
|
||||
|
||||
pdf.mjs | 567.30 kB || 4016 | 417 || 47465 | 7740
|
||||
pdf.mjs | 567.30 kB || 4016 | 393 || 47465 | 7740
|
||||
|
||||
antd.js | 6.69 MB || 7624 | 1657 || 333609 | 69349
|
||||
antd.js | 6.69 MB || 7624 | 1627 || 333609 | 69349
|
||||
|
||||
binder.ts | 193.08 kB || 47 | 23 || 7076 | 824
|
||||
binder.ts | 193.08 kB || 47 | 1 || 7076 | 824
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
File | File size || Sys allocs | Sys reallocs || Arena allocs | Arena reallocs
|
||||
---------------------------------------------------------------------------------------------------------------------------
|
||||
checker.ts | 2.92 MB || 2309 | 18 || 0 | 0
|
||||
checker.ts | 2.92 MB || 2309 | 3 || 0 | 0
|
||||
|
||||
cal.com.tsx | 1.06 MB || 12064 | 22 || 0 | 0
|
||||
cal.com.tsx | 1.06 MB || 12064 | 10 || 0 | 0
|
||||
|
||||
RadixUIAdoptionSection.jsx | 2.52 kB || 10 | 3 || 0 | 0
|
||||
RadixUIAdoptionSection.jsx | 2.52 kB || 10 | 0 || 0 | 0
|
||||
|
||||
pdf.mjs | 567.30 kB || 1401 | 208 || 0 | 0
|
||||
pdf.mjs | 567.30 kB || 1401 | 196 || 0 | 0
|
||||
|
||||
antd.js | 6.69 MB || 2455 | 18 || 0 | 0
|
||||
antd.js | 6.69 MB || 2455 | 3 || 0 | 0
|
||||
|
||||
binder.ts | 193.08 kB || 196 | 11 || 0 | 0
|
||||
binder.ts | 193.08 kB || 196 | 0 || 0 | 0
|
||||
|
||||
Reference in new issue
Block a user