Optimize MoonBit primitive stream buffering#1664
Merged
alexcrichton merged 1 commit intoJul 24, 2026
Merged
Conversation
alexcrichton
approved these changes
Jul 24, 2026
peter-jerry-ye
marked this pull request as ready for review
July 24, 2026 05:33
Merged
via the queue into
bytecodealliance:main
with commit Jul 24, 2026
7c48901
28 of 29 checks passed
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.
Why
MoonBit async streams currently use a fixed 64-element window regardless of
the canonical element size. That leaves small primitive streams with tiny
transfers and causes avoidable canonical ABI callbacks and scheduler activity.
The async runtime also snapshots borrowed array views with explicit
element-by-element constructors instead of standard collection-copy APIs.
What changed
selecting the element count.
Sink.single-element staging rule for nested endpoint payloads.
FixedArray::from_arrayandBytesView::to_fixedarraywhen the runtimemust take an owned snapshot of a borrowed view.
Performance
The WASI HTTP benchmark used a 64 KiB body, 64 connections, and three
interleaved 6-second runs per variant. Fixed-rate results below are medians;
all requests succeeded.
For the bidirectional 64 KiB case at saturation, median throughput increased
from 351 to 13,625 req/s (38.8x), while p99 fell from 667 to 7.87 ms.
Holding the byte window at 4 KiB and comparing the old
makeisnapshot withthe standard-library byte conversion isolates the copy change:
makei→ byte blitmakei→ byte blitThe baseline component was generated from upstream main at
6b3ec405. It isbyte-identical to the previous v0.60.0 benchmark component because the MoonBit
generator did not change between those commits.
This workload exercises
stream<u8>. The other primitive widths are covered bythe generated-code policy tests, but these byte-stream speedups are not claimed
for them.
Why this is correct and minimal
Only fixed primitive streams receive larger windows. Non-primitive streams and
nested future/stream payload staging retain their existing behavior.
The runtime still copies borrowed views before a callback can suspend, so the
lifetime invariant is unchanged. The byte-specialized path delegates to the
standard library's blit-backed conversion. Generic copies use the standard
API boundary, leaving any future bulk-copy implementation to MoonBit core.
This does not introduce owner buffers, dynamic window adjustment, or generic
canonical element-lowering changes.