Repository navigation
perf(runtime): born-old children for a producer's fresh old-born container (split) - #12613
Merged
Merged
Conversation
When a runtime producer fills a fresh container it owns and that container was born old, the children it allocates for it are now born old too, and its stores into the container skip the old->young remembering (old->old owes the remembered set nothing). The decision is made once per producer call from the container's own birth generation (`ProducerChildBirth::for_fresh_container`): no cache, no side table, no per-element test. Old children take the same birth a large object takes (`arena_alloc_gc_old_born_tenured`), so they inherit allocate-black during a mark cycle, the sweep-window rules, and non-movement by the minor collector. The store keeps the incremental mark shade. Only stores into the producer's own fresh container use the reduced barrier; every other store is unchanged. First producer: String.prototype.split on a non-empty delimiter. A 5M-part split built a 40 MB result born old and stored 5M young parts into it, all old->young; every minor then re-scanned, copied and promoted them. Tests: an old-born split result gets old, TENURED parts and adds no remembered slot; a small split keeps young parts; a split during an active budgeted mark (MarkPropagation) births every part marked, and all parts survive that cycle and a later full collection.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 6
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
What
When a runtime producer fills a fresh container it owns and that container was born old, the children it allocates for it are now born old too, and its stores into that container skip the old→young remembering. Old→old needs no remembered slot.
gc/producer_birth.rs:ProducerChildBirth::for_fresh_container(addr)decides once per producer call from the container's own birth generation (classify_heap_generation == Old). There's no cache, no side table and no per-element test.fresh_old_container_store_barrierkeeps only the incremental mark shade.string_storage_alloc_for(birth, cap):Oldtakes the same birth a large object takes (arena_alloc_gc_old_born_tenured: old pages +GC_FLAG_TENURED).String.prototype.spliton a non-empty delimiter (split_by_delimiter). The empty-delimiter path builds its parts through the shared constructors, which stay young, so it keeps the full barrier.Correctness
gc_birth_extra_flags+gc_note_black_birth), so a part born during a budgeted cycle is born MARKED (allocate-black). During a sweep, birth flags are clear and the old free list is withheld (Random heap corruption with the incremental old-gen collector on: package-manager installs fail ~10–40%; PERRY_GC_INCREMENTAL=0 passes 48/48 #11842), which is the same rule promotions and large objects already follow. The store also keeps the mark shade.Young, so it keeps the full barrier.Tests (
gc/tests/born_old_producer.rs)MarkPropagation; the test asserts the cycle is still active after the split) births every part MARKED. All parts read back after the cycle completes and after a later full collection.Results (qb6, base = a86b06b)
Node 26.8.1 on the same words program: split 358 ms, map 378 ms.
Gates run locally
scripts/gc_call_effects/regen.sh linux-x86_64 --check: identical to the archives.gc_repsel_matrix.sh --arms pr(129 files × 7 arms): 696 PASS / 200 UNVER / 7 FAIL. All 7 FAILs arerepsel_element_group_numeric, which fails the same way on base (TypeError ... reading 'y').cargo test -p perry-runtime --lib gc:: string:: array:: --test-threads=1: 2460 pass / 4 fail. All 4 fail the same way on base.root-survival, which differs on base too.