Skip to content

[turbopack] Optimize compaction cpu usage#91468

Merged
lukesandberg merged 10 commits intocanaryfrom
compaction_sorting_and_iteration
Mar 20, 2026
Merged

[turbopack] Optimize compaction cpu usage#91468
lukesandberg merged 10 commits intocanaryfrom
compaction_sorting_and_iteration

Conversation

@lukesandberg
Copy link
Copy Markdown
Contributor

@lukesandberg lukesandberg commented Mar 16, 2026

Summary

Optimizes the turbo-persistence compaction and iteration paths with several targeted improvements:

Iterator optimizations

  • Flatten index block iteration — The iterator previously used a Vec<CurrentIndexBlock> stack, but SST files have exactly one index level. Inline the index block fields (index_entries, index_block_count, index_pos) directly into StaticSortedFileIter, eliminating the stack allocation and Option overhead.

  • Non-optional CurrentKeyBlock — Parse the first key block during try_into_iter() construction so current_key_block is always populated, removing the Option<CurrentKeyBlock> wrapper and its take()/Some() ceremony in the hot loop.

  • Replace ReadBytesExt with direct byte indexing — In handle_key_match, parse_key_block, and next_internal, replace val.read_u16::<BE>() etc. with u16::from_be_bytes(val[0..2].try_into().unwrap()). This eliminates th mutable slice pointer advancement.

  • Extract read_offset_entry helper — Read type + offset from the key block offset table in a single u32 load + shift, replacing two separate ReadBytesExt calls.

Refcounting optimization

  • Introduce RcBytes — Thread-local byte slice type using Rc instead of Arc, eliminating atomic refcount overhead during single-threaded SST iteration. The iteration path (StaticSortedFileIter) now produces RcBytes slices backed by an Rc<Mmap>, so per-entry clone/drop operations are plain integer increments rather than atomic operations.

Merge iterator simplification

  • Optimize MergeIter::next — Replaced the straightforwards pop/push pattern with PeekMut-based replace-top pattern, which means we only need to adjust the heap once per iteration instead of twice.

Benchmark results

Compaction (key_8/value_4/entries_16.00Mi/commits_128)

Benchmark Canary Optimized Change
partial compaction 1.949 s 1.515 s -22%
full compaction 2.051 s 1.542 s -25%

Read path (static_sorted_file_lookup/entries_1000.00Ki)

No read regression — the branch is neutral to slightly faster:

Benchmark Canary Optimized Change
hit/uncached 6.73 µs 6.59 µs -2%
hit/cached 140.8 ns 130.7 ns -7%
miss/uncached 5.10 µs 5.02 µs -2%
miss/cached 230.1 ns 233.1 ns ~+1% (noise)

Test plan

  • cargo test -p turbo-persistence — 60/60 tests passing
  • Compaction benchmarks run and compared against canary baseline
  • Read path (lookup) benchmarks verified no regression

@nextjs-bot nextjs-bot added created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js. labels Mar 16, 2026
Copy link
Copy Markdown
Contributor Author

lukesandberg commented Mar 16, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Mar 16, 2026

Tests Passed

@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Mar 16, 2026

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 456ms 456ms ▁▅▁▁▁
Cold (Ready in log) 443ms 444ms ▁▅▁▁▂
Cold (First Request) 835ms 839ms ▂▄▁▂▂
Warm (Listen) 456ms 455ms ▁▅▁▁▁
Warm (Ready in log) 444ms 443ms ▁▆▁▁▂
Warm (First Request) 347ms 344ms ▁▃▁▁▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 456ms ▁▁▁▁▁
Cold (Ready in log) 439ms 438ms ▁▁▁▁▁
Cold (First Request) 1.937s 1.940s ▁▃▂▂▂
Warm (Listen) 456ms 455ms ▁▁▁▁▁
Warm (Ready in log) 439ms 438ms ▁▁▁▁▁
Warm (First Request) 1.985s 1.962s ▁▂▂▂▂

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.909s 3.893s ▁▅▁▁▂
Cached Build 3.902s 3.903s ▁▅▁▁▂
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.458s 14.403s ▁▁▁▁▁
Cached Build 14.652s 14.616s ▁▁▁▁▁
node_modules Size 484 MB 484 MB ▁▁▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
0.9zdz7ux63kn.js gzip 48.7 kB N/A -
0~lwfcrlb4v_9.css gzip 115 B 115 B
00h0nz7r436~l.js gzip 13.3 kB N/A -
00ivb_iunbucu.js gzip 13 kB N/A -
01tk89nk.ffi8.js gzip 158 B N/A -
02j5b_sjm5buz.js gzip 155 B N/A -
02ku7edzc_wf7.js gzip 450 B N/A -
03~yq9q893hmn.js gzip 39.4 kB 39.4 kB
04mfts9t5w62g.js gzip 155 B N/A -
08wow2p6zxy.b.js gzip 7.61 kB N/A -
092lcb3fqrrf9.js gzip 8.52 kB N/A -
0aj~xs1l1g8tg.js gzip 8.53 kB N/A -
0h35gmp9u328z.js gzip 8.54 kB N/A -
0h6fkavebp.iz.js gzip 8.47 kB N/A -
0i3d7jh-x_at5.js gzip 155 B N/A -
0ino_yf1k3h6k.js gzip 10.4 kB N/A -
0jjd.m22v.i-k.js gzip 156 B N/A -
0kdikcbiixwmk.js gzip 160 B N/A -
0kjkxzk698p9u.js gzip 70.8 kB N/A -
0ksw2n1gx8yd7.js gzip 65.7 kB N/A -
0mc16gv2x1bet.js gzip 13.7 kB N/A -
0moy~uao4dl.m.js gzip 9.19 kB N/A -
0q50rtpusjy90.js gzip 2.28 kB N/A -
0smgy2grrrlka.js gzip 8.58 kB N/A -
0t1dzhdfh0txh.js gzip 215 B 215 B
0tfl8rayb0-sl.js gzip 153 B N/A -
0tv_d-a_r-xf~.js gzip 156 B N/A -
0v6b~03xbk0ty.js gzip 168 B N/A -
0vt7pofxnk8in.js gzip 10.1 kB N/A -
0w9h4-_.9uabj.js gzip 160 B N/A -
0yqlkd5xff7.b.js gzip 153 B N/A -
0zid7o0-vupvp.js gzip 225 B N/A -
11j5tjy629bgg.js gzip 154 B N/A -
11yo3xfd6b147.js gzip 12.9 kB N/A -
13.84hqxl_1p7.js gzip 9.76 kB N/A -
137644g4qzo_7.js gzip 156 B N/A -
1554wr-t7p6z-.js gzip 8.55 kB N/A -
15tjst79~qy3_.js gzip 1.46 kB N/A -
15z_v00ne4ud0.js gzip 8.47 kB N/A -
17d_m3p4j9w6r.js gzip 5.62 kB N/A -
17yu~3yiu7d2m.js gzip 8.52 kB N/A -
turbopack-0...x10g.js gzip 4.16 kB N/A -
turbopack-00..wv2..js gzip 4.16 kB N/A -
turbopack-05..yugx.js gzip 4.16 kB N/A -
turbopack-08..j__l.js gzip 4.16 kB N/A -
turbopack-09..9pa1.js gzip 4.14 kB N/A -
turbopack-0c..7zg9.js gzip 4.16 kB N/A -
turbopack-0c..squ..js gzip 4.16 kB N/A -
turbopack-0d..trg8.js gzip 4.17 kB N/A -
turbopack-0i..xoa9.js gzip 4.15 kB N/A -
turbopack-0m..n7zi.js gzip 4.16 kB N/A -
turbopack-0q.._3~2.js gzip 4.16 kB N/A -
turbopack-0t..tm2i.js gzip 4.16 kB N/A -
turbopack-0v..8q6q.js gzip 4.16 kB N/A -
turbopack-11..~~sa.js gzip 4.16 kB N/A -
0-~kc4ap47t-y.js gzip N/A 161 B -
018c5y8lg9p79.js gzip N/A 155 B -
02p4h_hie86eo.js gzip N/A 155 B -
03t__~.5lvgeu.js gzip N/A 5.62 kB -
04d6ll75jqx3r.js gzip N/A 9.19 kB -
0583exyh-yhc7.js gzip N/A 9.76 kB -
072lv63r8dcz~.js gzip N/A 8.58 kB -
075t9dxgbf0m8.js gzip N/A 13.7 kB -
07sepdovlyvl0.js gzip N/A 155 B -
0ar1~bwpezfgw.js gzip N/A 13.3 kB -
0c99mq1ez2bke.js gzip N/A 450 B -
0cq-cmde_ws6u.js gzip N/A 8.47 kB -
0e7fprzho_rur.js gzip N/A 168 B -
0fwf102w10o9~.js gzip N/A 8.52 kB -
0g0r-8gqop3r4.js gzip N/A 152 B -
0gtmn.q_j1v5r.js gzip N/A 10.4 kB -
0h5~v-tahitcf.js gzip N/A 10.1 kB -
0jo.-p0x_18u~.js gzip N/A 65.7 kB -
0nclq9z6yzzm5.js gzip N/A 1.46 kB -
0nzumcogektg7.js gzip N/A 8.55 kB -
0p5sjual.nuis.js gzip N/A 13 kB -
0p88ggrxiy7bp.js gzip N/A 7.6 kB -
0qy62drk_cphp.js gzip N/A 155 B -
0s.c-cn5eebrx.js gzip N/A 8.47 kB -
0tna7lg6q4zne.js gzip N/A 12.9 kB -
0votdfxr5fb5u.js gzip N/A 2.28 kB -
0wz-g5ya6or-8.js gzip N/A 48.7 kB -
0xxdafvjerw_a.js gzip N/A 70.8 kB -
0ykl9bs_qj.5..js gzip N/A 8.52 kB -
0yq~k621klwzw.js gzip N/A 153 B -
0zfen0tnxp4gh.js gzip N/A 8.55 kB -
10wkq1h9jzkg..js gzip N/A 225 B -
10x7re-lumild.js gzip N/A 155 B -
118ev3phr.7~f.js gzip N/A 155 B -
13_p9g3dsp0fp.js gzip N/A 160 B -
149ndfh8zfcaz.js gzip N/A 8.53 kB -
15jy71cuk5lja.js gzip N/A 153 B -
17mt927cfhlsi.js gzip N/A 155 B -
turbopack-05...agn.js gzip N/A 4.16 kB -
turbopack-08..95zq.js gzip N/A 4.17 kB -
turbopack-0e..1_aa.js gzip N/A 4.16 kB -
turbopack-0f..2zj0.js gzip N/A 4.16 kB -
turbopack-0o..ay2b.js gzip N/A 4.16 kB -
turbopack-0p..-7hy.js gzip N/A 4.16 kB -
turbopack-0t..ml6l.js gzip N/A 4.16 kB -
turbopack-0v..sq0k.js gzip N/A 4.16 kB -
turbopack-0w..n4fv.js gzip N/A 4.16 kB -
turbopack-0x..nj1d.js gzip N/A 4.16 kB -
turbopack-11..jdct.js gzip N/A 4.14 kB -
turbopack-12..gyok.js gzip N/A 4.16 kB -
turbopack-12.._vzb.js gzip N/A 4.16 kB -
turbopack-12..4wtb.js gzip N/A 4.16 kB -
Total 463 kB 463 kB ✅ -15 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 713 B 711 B
Total 713 B 711 B ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 427 B 432 B 🔴 +5 B (+1%)
Total 427 B 432 B ⚠️ +5 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.54 kB N/A -
6280-HASH.js gzip 60.4 kB N/A -
6335.HASH.js gzip 169 B N/A -
912-HASH.js gzip 4.59 kB N/A -
e8aec2e4-HASH.js gzip 62.7 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 256 B 252 B 🟢 4 B (-2%)
main-HASH.js gzip 39.3 kB 39.2 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
262-HASH.js gzip N/A 4.59 kB -
2889.HASH.js gzip N/A 169 B -
5602-HASH.js gzip N/A 5.55 kB -
6948ada0-HASH.js gzip N/A 62.7 kB -
9544-HASH.js gzip N/A 61.1 kB -
Total 234 kB 235 kB ⚠️ +670 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 194 B
_error-HASH.js gzip 183 B 180 B 🟢 3 B (-2%)
css-HASH.js gzip 331 B 330 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 351 B 352 B
hooks-HASH.js gzip 384 B 383 B
image-HASH.js gzip 580 B 581 B
index-HASH.js gzip 260 B 260 B
link-HASH.js gzip 2.51 kB 2.51 kB
routerDirect..HASH.js gzip 320 B 319 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 315 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.98 kB 7.98 kB ✅ -1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 125 kB 125 kB
page.js gzip 269 kB 269 kB
Total 394 kB 394 kB ✅ -320 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 615 B 613 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 43.9 kB 44 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 45.5 kB 45.6 kB ⚠️ +59 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 715 B 718 B
Total 715 B 718 B ⚠️ +3 B
Build Cache
Canary PR Change
0.pack gzip 4.29 MB 4.28 MB 🟢 8.12 kB (0%)
index.pack gzip 110 kB 109 kB
index.pack.old gzip 110 kB 110 kB
Total 4.51 MB 4.5 MB ✅ -8.37 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 334 kB 334 kB
app-page-exp..prod.js gzip 181 kB 181 kB
app-page-tur...dev.js gzip 333 kB 333 kB
app-page-tur..prod.js gzip 181 kB 181 kB
app-page-tur...dev.js gzip 330 kB 330 kB
app-page-tur..prod.js gzip 179 kB 179 kB
app-page.run...dev.js gzip 330 kB 330 kB
app-page.run..prod.js gzip 179 kB 179 kB
app-route-ex...dev.js gzip 76.2 kB 76.2 kB
app-route-ex..prod.js gzip 51.8 kB 51.8 kB
app-route-tu...dev.js gzip 76.2 kB 76.2 kB
app-route-tu..prod.js gzip 51.9 kB 51.9 kB
app-route-tu...dev.js gzip 75.8 kB 75.8 kB
app-route-tu..prod.js gzip 51.6 kB 51.6 kB
app-route.ru...dev.js gzip 75.8 kB 75.8 kB
app-route.ru..prod.js gzip 51.6 kB 51.6 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 43.4 kB 43.4 kB
pages-api-tu..prod.js gzip 33 kB 33 kB
pages-api.ru...dev.js gzip 43.4 kB 43.4 kB
pages-api.ru..prod.js gzip 33 kB 33 kB
pages-turbo....dev.js gzip 52.8 kB 52.8 kB
pages-turbo...prod.js gzip 38.6 kB 38.6 kB
pages.runtim...dev.js gzip 52.8 kB 52.8 kB
pages.runtim..prod.js gzip 38.6 kB 38.6 kB
server.runti..prod.js gzip 62.5 kB 62.5 kB
Total 2.96 MB 2.96 MB ⚠️ +1 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/ea88f2d0ffb6edfe953e491d58d9291b6d25c75a/next

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 16, 2026

Merging this PR will not alter performance

✅ 17 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing compaction_sorting_and_iteration (ea88f2d) with canary (af97e75)

Open in CodSpeed

Footnotes

  1. 3 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.

@lukesandberg lukesandberg changed the base branch from update_qfilter to graphite-base/91468 March 16, 2026 21:11
@lukesandberg lukesandberg force-pushed the compaction_sorting_and_iteration branch from a5f38eb to 3600f32 Compare March 16, 2026 21:12
@lukesandberg lukesandberg changed the base branch from graphite-base/91468 to canary March 16, 2026 21:12
@lukesandberg lukesandberg force-pushed the compaction_sorting_and_iteration branch from 3600f32 to 4a942b8 Compare March 16, 2026 21:12
@lukesandberg lukesandberg marked this pull request as ready for review March 16, 2026 23:00
@lukesandberg lukesandberg requested a review from a team March 16, 2026 23:01
@lukesandberg lukesandberg changed the title improve compaction cpu [turbopack] Optimize compaction cpu usage Mar 16, 2026
Copy link
Copy Markdown
Member

bgw commented Mar 17, 2026

Replace ReadBytesExt with direct byte indexing — In handle_key_match, parse_key_block, and next_internal, replace val.read_u16::() etc. with u16::from_be_bytes(val[0..2].try_into().unwrap()). This eliminates the trait dispatch overhead, dead error-handling code, and mutable slice pointer advancement.

  • Static dispatch, so there's no trait call overhead
  • A helper is still nice because it's shorter, I just didn't like that it was on Read and generated a no-op io error
  • We could do an unsafe conversion from val[0..2] to an array, because we know the length is correct, we could define helper functions for this.

Comment thread turbopack/crates/turbo-persistence/src/db.rs Outdated
Comment thread turbopack/crates/turbo-persistence/src/merge_iter.rs Outdated
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs Outdated
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs Outdated
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs Outdated
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs
@lukesandberg lukesandberg force-pushed the compaction_sorting_and_iteration branch from 9800c36 to 56100a3 Compare March 18, 2026 05:45
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs
@lukesandberg lukesandberg force-pushed the compaction_sorting_and_iteration branch from f25dedc to 58b70cb Compare March 18, 2026 17:31
Comment thread turbopack/crates/turbo-persistence/src/arc_bytes.rs Outdated
Comment thread turbopack/crates/turbo-persistence/src/compression.rs
Comment thread turbopack/crates/turbo-persistence/src/static_sorted_file.rs Outdated
@lukesandberg lukesandberg force-pushed the compaction_sorting_and_iteration branch from 58b70cb to c8f0fba Compare March 19, 2026 20:37
@lukesandberg lukesandberg merged commit 8e9f951 into canary Mar 20, 2026
289 of 292 checks passed
Copy link
Copy Markdown
Contributor Author

Merge activity

@lukesandberg lukesandberg deleted the compaction_sorting_and_iteration branch March 20, 2026 05:11
@github-actions github-actions Bot added the locked label Apr 3, 2026
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Apr 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

created-by: Turbopack team PRs by the Turbopack team. locked Turbopack Related to Turbopack with Next.js.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants