Repository navigation
fix(cli): run mops bench cells with the incremental GC paused - #890
Merged
Merged
Conversation
An incremental GC cycle can span several messages. A cell that starts while one is in progress pays for the GC's write and allocation barriers, so identical cells cost up to 40% more instructions depending on what ran before them. --force-gc made this happen in about every other cell, since it starts a new cycle after every message. Compile the bench canister without --force-gc for the incremental GC, and before each cell call a new collectorInstructions() method until the collector's instruction count stops changing. The legacy GCs keep --force-gc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without `--force-gc`, the bench-gc-barrier fixture never started a GC cycle, so the wait loop always returned after two calls and the test never ran it. Its cells now alternate between identical writes and cells that leave garbage. Without the wait, the write cell after the first garbage cell costs 16,100,150 instructions instead of 12,500,150. `rts_collector_instructions` is the GC cost of the previous message, not a running total, so the comments now say that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Cursor AI review👍 APPROVE — looks safe to merge
VerdictDecision: APPROVE Generated for commit 55dfced |
automation-sa-sre
previously approved these changes
Oct 12, 2026
automation-sa-sre
left a comment
Collaborator
There was a problem hiding this comment.
Automated approval: the AI review verdict for c35ee91 is APPROVE. See the "Cursor AI review" comment for details.
Kamirus
enabled auto-merge (squash)
October 12, 2026 13:40
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
automation-sa-sre
approved these changes
Oct 12, 2026
automation-sa-sre
left a comment
Collaborator
There was a problem hiding this comment.
Automated approval: the AI review verdict for 55dfced is APPROVE. See the "Cursor AI review" comment for details.
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.
Supersedes #889 by @timohanke, whose branch on an organization-owned fork doesn't accept maintainer pushes. The first commit is #889 unchanged, so the squash keeps @timohanke as co-author. Fixes #888.
Problem
mops benchinstruction counts depended on the order of the cells. The bench canister was compiled with--force-gc, so the incremental GC started a new cycle at the end of every message, and on a large heap that cycle ran on into the next cell. While a cycle is in progress, the GC's write and allocation barriers are on, and the cell pays for them: identical cells differed by 20–40%. #888 has the compiler details.Dropping
--force-gcisn't enough on its own. A cell that leaves enough garbage still starts a cycle, and the next cell runs mid-cycle. In the fixture below, that cell costs 16,100,150 instructions instead of 12,500,150.Fix
--force-gc. The legacy GCs ofmoc1.x keep it, because they finish a collection within the message.mops benchcalls a newcollectorInstructions()method on the bench canister until two calls in a row return the same value.rts_collector_instructionsis the GC cost at the end of the previous message, not a running total: about 330 instructions while the GC is paused, and hundreds of millions per increment while a cycle runs. After 1000 messages without a pause,mops benchfails.Before / after
cli/tests/bench-gc-barrier,moc2.0.0: identicalfillcells, each after agarbagecell, on a 1M-object live heap.Before (3.5.0):
After:
On a real benchmark, research-ag/sort, 23 of 36 cells were inflated by 23–40% on 3.5.0. With this fix, it gives the same counts in both cell orders.
Migration
Baselines saved with 3.5.0 can show lower instruction counts for cells that used to start mid-cycle. To compare against fair numbers, re-save them with
mops bench --save. Saved and published results now recordforceGc: falsefor the incremental GC.What is unchanged
--gc copying|compacting|generationalonmoc1.x still compiles with--force-gcand skips the wait.Follow-up worth flagging
If two GC increments in a row cost exactly the same number of instructions, the wait would end mid-cycle. That's unlikely, and the Motoko runtime exposes no GC phase to check instead.
🤖 Generated with Claude Code