perf: merge stream transforms in continueFizzStream (8 → 4)#91621
Open
benfavre wants to merge 1 commit intovercel:canaryfrom
Open
perf: merge stream transforms in continueFizzStream (8 → 4)#91621benfavre wants to merge 1 commit intovercel:canaryfrom
benfavre wants to merge 1 commit intovercel:canaryfrom
Conversation
Merge 4 separate TransformStreams in `continueFizzStream` into 2 combined transforms, reducing the pipeline from up to 8 transforms to 4: 1. `createBufferedUnifiedTransform()` — combines: - Buffer (chunk batching via scheduleImmediate) - DplId injection (data-dpl-id attribute on <html>) - Metadata transformation (icon mark replacement) - Root layout validator (<html>/<body> tag scanning) 2. `createMoveSuffixAndHeadInsertionStream()` — combines: - MoveSuffix (strips </body></html>, re-appends at stream end) - HeadInsertion (inserts server HTML before </head>) Each eliminated TransformStream saves ~33μs of writable+readable state machine overhead per request. Total savings: ~130μs per dynamic request. Key design decisions: - The unified buffer processes merged chunks through DplId/Metadata/Validator on each flush. Once all one-time operations complete (`allDone` flag), the fast path is fully synchronous with zero Promise allocation. - Metadata insertion is the only async path (calls getServerInsertedMetadata). This is split into a separate `processMetadataInsertion` function to keep the hot path free of async overhead. - The merged MoveSuffix+HeadInsertion handles both operations in a single transform pass per chunk. - Original standalone transforms are preserved for use by other callers (debug-channel.ts, prerender functions). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collaborator
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
1 similar comment
Collaborator
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
Contributor
Author
Performance ImpactStream pipeline cost: ~200μs/req for dynamic routes (9% of CPU). Each TransformStream creates internal ReadableStream + WritableStream + queues + backpressure management costing ~33μs. Before (PR #91575): 6 transforms in
After (this PR): 4 transforms:
Savings: 4 fewer TransformStream constructions = ~132μs saved per request. From original 8 transforms to 4 total. Regression Safety
Test Verification
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Merge 4 separate
TransformStreaminstances incontinueFizzStreaminto 2 combined transforms, reducing the pipeline from up to 8 transforms to 4.The stream pipeline in
continueFizzStreamaccounts for ~200μs per dynamic request (~9% CPU in profiling). EachTransformStreamcarries ~33μs of writable+readable state machine overhead. This PR eliminates 4 of those by combining transforms that operate on the same chunks:Transform 1:
createBufferedUnifiedTransform()(replaces 4 separate transforms)scheduleImmediatedata-dpl-idattribute on<html>tag<html>/<body>tag scanningTransform 2:
createMoveSuffixAndHeadInsertionStream()(replaces 2 separate transforms)</body></html>, re-appends at stream end</head>Performance characteristics
allDoneflag),processChunkreturnsvoid(no Promise allocation, no microtask)processMetadataInsertion()to keep the hot path cleandebug-channel.ts, prerender functions)Before (up to 8 transforms)
After (up to 4 transforms)
(
DeferredSuffixandFlightDataare conditional and may not be present)Test plan
test/development/app-dir/missing-required-html-tagspasses (root layout validator)data-dpl-id) is correctly injected on<html>tag</head></body></html>is correctly moved to stream end</head>in chunk)continue*functions unchanged)🤖 Generated with Claude Code