Skip to content

perf(formatter): accumulate JSX child-list builders on the heap#24585

Merged
graphite-app[bot] merged 1 commit into
mainfrom
07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap
Jul 22, 2026
Merged

perf(formatter): accumulate JSX child-list builders on the heap#24585
graphite-app[bot] merged 1 commit into
mainfrom
07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap

Conversation

@leaysgur

@leaysgur leaysgur commented Jul 16, 2026

Copy link
Copy Markdown
Member

The JSX child-list builders (MultilineBuilder / FlatBuilder in child_list.rs) were the last IR staging path still growing vectors in the arena.

They accumulate elements across the whole child-list loop while arbitrary child content is
formatted in between, so every growth stranded its old allocation (the same pattern #24582 removed from intern / BestFitting / grouped arguments).

They can't use HeapVecBuffer: the flat and multiline builders write alternately for each child, which would interleave their segments in the shared scratch vector and break its LIFO watermark discipline. The thread-local cache behind it has no such requirement though.

So each builder now checks out its own ScratchBuffer and writes into it through a small private Buffer adapter (ChildListBuffer); the finished result reaches the arena as one exactly-sized copy via the new Formatter::intern_elements, which clears the source so its capacity returns to the cache on drop.

Now arena reallocs for RadixUIAdoptionSection.jsx is 0.

leaysgur commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent changes, fast-track this PR to the front of 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-hq

codspeed-hq Bot commented Jul 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 57 untouched benchmarks
⏩ 19 skipped benchmarks1


Comparing 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap (679a9e8) with 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers (c3b460b)

Open in CodSpeed

Footnotes

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

@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch from 0c8e314 to 4a5c078 Compare July 16, 2026 06:53
@oxc-guard

oxc-guard Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Oxfmt Ecosystem CI

suite oxfmt@latest main refs/pull/24585/head branch
monkeytypegame/monkeytype
AmanVarshney01/create-better-t-stack
actualbudget/actual
fuma-nama/fumadocs
cnpm/cnpmcore
formatjs/formatjs
tale/headplane
eggjs/egg
Comfy-Org/ComfyUI_frontend ⚠️
fastify/fastify-vite
huggingface/huggingface.js
dyad-sh/dyad
lichess-org/lila
vercel/turborepo
vuejs/pinia
openclaw/openclaw
cloudflare/agents
getsentry/sentry-javascript
npmx-dev/npmx.dev
mantinedev/mantine
cloudflare/workers-sdk
mastodon/mastodon
vuejs/core
aidenybai/react-grab
rolldown/rolldown

💥 = panic, ⚠️ = error e.g. parse error (main/branch columns: only new errors), ❌ = diff or exit code mismatch, 🟨 = differs from oxfmt@latest (merged-but-unreleased changes)

@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers branch from 72ae10f to c835270 Compare July 17, 2026 06:03
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch from 4a5c078 to d9a6184 Compare July 17, 2026 06:03
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch from d9a6184 to 8510ba2 Compare July 21, 2026 06:11
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers branch from c835270 to 7aa30a3 Compare July 21, 2026 06:11
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers branch from 7aa30a3 to a9a2c78 Compare July 21, 2026 09:26
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch from 8510ba2 to 0433b79 Compare July 21, 2026 09:26
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers branch from a9a2c78 to c3b460b Compare July 22, 2026 05:04
@leaysgur
leaysgur force-pushed the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch from 0433b79 to 679a9e8 Compare July 22, 2026 05:04
@graphite-app graphite-app Bot added the 0-merge Merge with Graphite Merge Queue label Jul 22, 2026
@graphite-app

graphite-app Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Merge activity

The JSX child-list builders (`MultilineBuilder` / `FlatBuilder` in `child_list.rs`) were the last IR staging path still growing vectors in the arena.

They accumulate elements across the whole child-list loop while arbitrary child content is
formatted in between, so every growth stranded its old allocation (the same pattern #24582 removed from `intern` / `BestFitting` / grouped arguments).

They can't use `HeapVecBuffer`: the flat and multiline builders write *alternately* for each child, which would interleave their segments in the shared scratch vector and break its LIFO watermark discipline. The thread-local cache behind it has no such requirement though.

So each builder now checks out its own `ScratchBuffer` and writes into it through a small private `Buffer` adapter (`ChildListBuffer`); the finished result reaches the arena as one exactly-sized copy via the new `Formatter::intern_elements`, which clears the source so its capacity returns to the cache on drop.

Now arena reallocs for `RadixUIAdoptionSection.jsx` is 0.
@graphite-app
graphite-app Bot force-pushed the 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers branch from c3b460b to 7810e8a Compare July 22, 2026 06:32
@graphite-app
graphite-app Bot force-pushed the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch from 679a9e8 to 94de05f Compare July 22, 2026 06:33
@graphite-app graphite-app Bot removed the 0-merge Merge with Graphite Merge Queue label Jul 22, 2026
Base automatically changed from 07-16-perf_formatter_core_share_one_thread-cached_scratch_vector_across_staging_buffers to main July 22, 2026 06:37
@graphite-app
graphite-app Bot merged commit 94de05f into main Jul 22, 2026
32 checks passed
@graphite-app
graphite-app Bot deleted the 07-16-perf_formatter_accumulate_jsx_child-list_builders_on_the_heap branch July 22, 2026 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-formatter Area - Formatter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant