perf(codegen): reduce allocations in SourcemapBuilder#13677
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
CodSpeed Instrumentation Performance ReportMerging #13677 will not alter performanceComparing Summary
Footnotes |
There was a problem hiding this comment.
Pull Request Overview
This PR optimizes memory allocation patterns in the SourcemapBuilder by reverting from mem::take back to clone with adaptive capacity management.
Key changes:
- Replaces
mem::takewithcloneto avoid unnecessary reallocations - Removes fixed capacity reservation in favor of adaptive growth
- Adds detailed comments explaining the memory allocation optimization rationale
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Merge activity
|
Follow-on after #13670. That PR made 2 changes: 1. Pre-allocating capacity in `columns` `Vec`. 2. `mem::take`-ing `columns` for each line, rather than re-using it. In my opinion, the 1st change is good, but the 2nd is not. Revert the usage of `mem::take`, and add a comment explaining why the `.clone()` is not as bad as it looks! Before this PR: `columns` will likely have spare capacity, so `mem::take(&mut columns).into_boxed_slice()` will perform a reallocation to drop the excess capacity, and then `columns.reserve(256)` performs a 2nd allocation. Approach after this PR: 1. `columns.clone().into_boxed_slice()` performs 1 allocation, and copies the data from `columns` into this new allocation. `columns.clear()` does not perform any reallocation, and is a very cheap operation. 2. `columns` `Vec` is reused over and over, and will grow adaptively depending on how heavy the file's use of unicode chars is, rather than always going back to estimated max capacity of 256. Benchmarks show a very small positive difference.
3613afd to
4ded22b
Compare
#13670 optimized `SourcemapBuilder` to pre-reserve capacity in `columns` `Vec`. However, after #13677, `columns` will resize adaptively depending on how many unicode chars in source text. So now initial capacity of 256 (1 KiB) is probably excessive for most cases. Reduce it to 16 (64 bytes, which is 1 x CPU cache line). Codspeed shows little change in perf (max +0.1%, min -0.1%), and memory usage will definitely be reduced.

Follow-on after #13670.
That PR made 2 changes:
columnsVec.mem::take-ingcolumnsfor each line, rather than re-using it.In my opinion, the 1st change is good, but the 2nd is not.
Revert the usage of
mem::take, and add a comment explaining why the.clone()is not as bad as it looks!Before this PR:
columnswill likely have spare capacity, somem::take(&mut columns).into_boxed_slice()will perform a reallocation to drop the excess capacity, and thencolumns.reserve(256)performs a 2nd allocation.Approach after this PR:
columns.clone().into_boxed_slice()performs 1 allocation, and copies the data fromcolumnsinto this new allocation.columns.clear()does not perform any reallocation, and is a very cheap operation.columnsVecis reused over and over, and will grow adaptively depending on how heavy the file's use of unicode chars is, rather than always going back to estimated max capacity of 256.Benchmarks show a very small positive difference.