Skip to content

perf(iterator): Optimize Iter eager consumers#3642

Open
mizchi wants to merge 2 commits into
moonbitlang:mainfrom
mizchi:codex/optimize-iter-eager-consumers
Open

perf(iterator): Optimize Iter eager consumers#3642
mizchi wants to merge 2 commits into
moonbitlang:mainfrom
mizchi:codex/optimize-iter-eager-consumers

Conversation

@mizchi

@mizchi mizchi commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR optimizes eager Iter consumers by avoiding the extra self.next() call inside hot loops.

Consumers such as each, fold, to_array, find_first, contains, nth, maximum, and minimum now call the iterator's internal self.f directly and use the same #inline size-hint bookkeeping helpers as next. This keeps the observable size_hint behavior while reducing call overhead, especially for iter().fold on wasm-gc.

Changes

  • Optimize eager Iter consumers to call self.f directly in hot loops
  • Centralize size_hint bookkeeping in private #inline helpers shared with next
  • Mark under-reported size_hint values as None after underflow until exhaustion
  • Preserve maximum / minimum NaN behavior by keeping the old x > res / x < res update conditions
  • Keep count delegated to fold
  • Add tests for size_hint behavior during eager consumers
  • Add FixedArray / ArrayView iterator benchmarks for fold, each, and to_array

Benchmark

wasm-gc --release, n=100000

benchmark before after
FixedArray::iter fold 232.38 us 106.13 us
FixedArray::iter each 117.92 us 114.23 us
FixedArray::iter to_array 337.51 us 283.56 us
ArrayView::iter fold 222.62 us 109.31 us
ArrayView::iter each 119.45 us 115.16 us
ArrayView::iter to_array 364.15 us 284.41 us
Vector::iter fold 363.82 us 336.28 us
Vector::iter each 375.15 us 336.11 us
Vector::iter to_array 463.91 us 433.70 us

I also checked RSS with hyperfine + /usr/bin/time -l. The measurement covers the whole moon bench process rather than an individual MoonBit function; median RSS was about 1.2-1.6 MiB higher than baseline, with no large regression observed.

Validation

moon fmt
moon info
moon check
moon test
moon test builtin --target wasm-gc
moon test builtin --target wasm
git diff --check

moon test: 6510 passed.

Review notes

The eager consumers intentionally bypass next to avoid the extra method call in hot loops. To keep the code paths aligned, next and the eager consumers now share the same private #inline helpers for size_hint updates.

@mizchi mizchi marked this pull request as ready for review May 31, 2026 11:15
Copilot AI review requested due to automatic review settings May 31, 2026 11:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR updates several eager Iter consumers (each, any, all, eachi, fold, count, find_first, to_array, last, contains, nth, maximum, minimum) to drive the underlying iterator function (self.f) directly and decrement self.size_hint per element, so callers observing size_hint from inside a callback (or after a partial/full consumption) see an accurate remaining count.

Changes:

  • Replaced while self.next() is Some(x) { ... } patterns with explicit for next = next_fn() loops that decrement size_hint on each element and zero it on exhaustion.
  • Rewrote maximum/minimum/last/count/nth to fit the new tracking pattern (no longer reusing fold).
  • Added size-hint tracking tests for eager consumers, plus benchmarks for Iter over FixedArray and ArrayView.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
builtin/iterator.mbt Inlines iteration loops to update size_hint per element across all eager consumers.
builtin/iter_test.mbt Adds a test verifying size_hint decreases during/after eager consumption.
builtin/array_locals_bench_test.mbt Adds Iter fold/each/to_array benchmarks for FixedArray and ArrayView.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread builtin/iterator.mbt Outdated
Comment on lines +130 to +132
if self.size_hint is Some(n) {
self.size_hint = if n > 0 { Some(n - 1) } else { Some(0) }
}
Comment thread builtin/iterator.mbt Outdated
Comment on lines +286 to +303
let mut count = 0
let next_fn = self.f
for next = next_fn() {
match next {
Some(_) => {
if self.size_hint is Some(n) {
self.size_hint = if n > 0 { Some(n - 1) } else { Some(0) }
}
count += 1
continue next_fn()
}
None => {
self.size_hint = Some(0)
break
}
}
}
count
Comment thread builtin/iterator.mbt
Comment on lines +126 to +127
let next_fn = self.f
for next = next_fn() {
Comment thread builtin/iterator.mbt Outdated
Comment on lines +1147 to +1158
let mut res = None
let next_fn = self.f
for next = next_fn() {
match next {
Some(x) => {
if self.size_hint is Some(n) {
self.size_hint = if n > 0 { Some(n - 1) } else { Some(0) }
}
match res {
Some(current) if x <= current => ()
_ => res = Some(x)
}
Comment thread builtin/iterator.mbt Outdated
match next {
Some(x) => {
if self.size_hint is Some(n) {
self.size_hint = if n > 0 { Some(n - 1) } else { Some(0) }
@mizchi mizchi changed the title Optimize Iter eager consumers perf(iterator): Optimize Iter eager consumers May 31, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 87b1e0bb95

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread builtin/iterator.mbt Outdated
Comment on lines +1156 to +1157
Some(current) if x <= current => ()
_ => res = Some(x)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep maximum updates based on greater-than

For Double/Float iterators containing NaN, this is not equivalent to the previous if x > res logic because both NaN <= current and NaN > current are false. For example, [1.0, NaN].iter().maximum() used to keep 1.0, but this branch now falls through to res = Some(x) and returns NaN; [NaN, 1.0] changes in the opposite direction. Please preserve the old x > current update condition for partial orders.

Useful? React with 👍 / 👎.

Comment thread builtin/iterator.mbt Outdated
Comment on lines +1182 to +1183
Some(current) if x >= current => ()
_ => res = Some(x)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep minimum updates based on less-than

For Double/Float iterators containing NaN, this is not equivalent to the previous if x < res logic because both NaN >= current and NaN < current are false. For example, [1.0, NaN].iter().minimum() used to keep 1.0, but this branch now falls through to res = Some(x) and returns NaN; [NaN, 1.0] changes in the opposite direction. Please preserve the old x < current update condition for partial orders.

Useful? React with 👍 / 👎.

@mizchi mizchi force-pushed the codex/optimize-iter-eager-consumers branch from 87b1e0b to ab09ccc Compare May 31, 2026 11:23
@mizchi mizchi force-pushed the codex/optimize-iter-eager-consumers branch from ab09ccc to 3e91847 Compare May 31, 2026 11:24
@Yu-zh

Yu-zh commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks for revealing this optimization opportunity. We are working on improving the inlining so I think it's the compiler's duty for handle the situation here.

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.

3 participants