Skip to content

perf: binary-search lookup_token by dst_col only#385

Merged
Boshen merged 2 commits into
oxc-project:mainfrom
linyiru:perf/lookup-token-dst-col
Jul 2, 2026
Merged

perf: binary-search lookup_token by dst_col only#385
Boshen merged 2 commits into
oxc-project:mainfrom
linyiru:perf/lookup-token-dst-col

Conversation

@linyiru

@linyiru linyiru commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

What

SourceMap::lookup_token binary-searches a line's token slice for the
greatest token <= (line, col). Every token in lookup_table[line] is built
to have dst_line == line (see generate_lookup_table), so searching the full
(dst_line, dst_col) tuple compares a component that is constant across the
slice on every probe. Searching dst_col alone is equivalent and avoids
building/comparing a tuple per step.

This is the per-token remapping hot path: bundlers call it once per token, per
chain link, when collapsing a sourcemap chain.

This PR:

  • searches dst_col only in lookup_token;
  • marks lookup_token #[inline] so it inlines into cross-crate callers;
  • adds a lookup_token benchmark group — the existing lookup_table group only
    measured generate_lookup_table (table construction), not the lookups.

Results

Microbench (benches/simple.rs, criterion, before → after):

fixture before after change
lookup_token/real_small 21.67 ns 14.00 ns −35%
lookup_token/real_medium 70.25 ns 36.47 ns −48%
lookup_token/real_large 1.555 µs 0.723 µs −54%
lookup_token/real_xlarge 54.06 µs 25.68 µs −52%

End-to-end in rolldown (via a local [patch.crates-io]), cargo bench -p bench:

bench before after change
sourcemap/collapse_codegen_chain 4.267 ms 2.263 ms −47% (p < 0.05)
sourcemap/join_with_sourcemap (control) 571 µs 582 µs no change (p = 0.52)
sourcemap/join_no_sourcemap (control) 43.5 µs 43.4 µs no change (p = 0.76)

The two controls are untouched by this change, confirming the delta is isolated
to the lookup path.

Correctness

dst_line is invariant within lookup_table[line], so the tuple and
dst_col-only searches are equivalent (including the equal-key run handled by
greatest_lower_bound). All existing tests pass (cargo test), including
lookup_token, lookup_with_duplicate_columns, and lookup_before_first_token;
cargo clippy --all-targets --all-features is clean.


Disclosure: this change was developed with AI assistance (Claude), and reviewed,
benchmarked, and verified by the author before submission.

linyiru added 2 commits June 26, 2026 18:40
The `lookup_table` group only measured `generate_lookup_table` (table
construction). Add a `lookup_token` group that, with the table already
built, probes every token's generated position — the per-token remapping
pattern bundlers use when collapsing a sourcemap chain.
Every token in `lookup_table[line]` has `dst_line == line` (see
`generate_lookup_table`), so binary-searching the `(dst_line, dst_col)`
tuple compares a constant first component on every probe. Searching
`dst_col` alone is equivalent and measurably faster on this remapping
hot path, which dominates sourcemap-chain collapse in bundlers. Also
marks `lookup_token` `#[inline]` so it inlines into cross-crate callers.

Microbench (criterion, in-crate, before -> after):
  lookup_token/real_small    21.67ns -> 14.00ns  (-35%)
  lookup_token/real_medium   70.25ns -> 36.47ns  (-48%)
  lookup_token/real_large    1.555us -> 0.723us  (-54%)
  lookup_token/real_xlarge   54.06us -> 25.68us  (-52%)
@Boshen Boshen self-assigned this Jun 27, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 13 untouched benchmarks
🆕 4 new benchmarks
⏩ 7 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
serialize[real_medium] 5.1 µs 5.1 µs -1.7%
parse[real_small] 11.7 µs 11.6 µs +1.51%
parse[real_medium] 14.5 µs 14.4 µs +1.22%
🆕 lookup_token[real_large] N/A 9.5 µs N/A
🆕 lookup_token[real_medium] N/A 924.2 ns N/A
🆕 lookup_token[real_small] N/A 669.7 ns N/A
🆕 lookup_token[real_xlarge] N/A 364 µs N/A

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing linyiru:perf/lookup-token-dst-col (1b9ac44) with main (90c12c8)

Open in CodSpeed

Footnotes

  1. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Boshen
Boshen merged commit 6a54fed into oxc-project:main Jul 2, 2026
8 checks passed
@oxc-guard oxc-guard Bot mentioned this pull request Jul 2, 2026
Boshen added a commit to hyfdev/oxc-sourcemap that referenced this pull request Jul 2, 2026
…sition test

Model the full rolldown/rolldown#10070 pipeline in one integration test:
codegen indents a line so its first anchor sits at column 1, the bundler
samples the moved line at column 0, and collapsing the chain resolves the
bundle token through the codegen map. The strict lookup drops the mapping
(asserted); the approximating lookup keeps it. The composed map then
round-trips through JSON and resolves the bundle position back to the
original source via OwnedSourceMap, covering the delegation as well.

Also align the new method's binary search with lookup_token (dst_col-only
key, oxc-project#385).
Boshen added a commit that referenced this pull request Jul 3, 2026
* feat: add lookup_token_approx for lossless sourcemap composition

lookup_token returns None when the queried column is before the first
token on a line. That's correct for a plain position lookup but drops
mappings when composing sourcemaps: an indented line's first token sits
after the indent, so a column-0 query misses and the line loses its
mapping.

Add lookup_token_approx / lookup_source_view_token_approx, which clamp to
the line's first token in that case, matching Rollup's collapseSourcemaps
traceSegment. lookup_token is unchanged.

* test: replace lookup_token_approx unit tests with an end-to-end composition test

Model the full rolldown/rolldown#10070 pipeline in one integration test:
codegen indents a line so its first anchor sits at column 1, the bundler
samples the moved line at column 0, and collapsing the chain resolves the
bundle token through the codegen map. The strict lookup drops the mapping
(asserted); the approximating lookup keeps it. The composed map then
round-trips through JSON and resolves the bundle position back to the
original source via OwnedSourceMap, covering the delegation as well.

Also align the new method's binary search with lookup_token (dst_col-only
key, #385).

---------

Co-authored-by: Boshen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants