Repository navigation
The string budget's gate reads the measured mark share, whatever SPINEL_GC_OBJ_BUDGET pins - #8460
Conversation
…EL_GC_OBJ_BUDGET pins Two review findings on matz#8444, both real. The share of the object old generation was gated by sp_gc_obj_alpha1024, and that is not the measurement: it is what SPINEL_GC_OBJ_BUDGET made of it for the object budget. `obj` sets it to zero, so the default string budget turned into `str`; `walk` sets it to one, and under `fixed` it stayed at its initial one because sp_gc_retune_object returned before measuring anything, so the default string budget turned into `walk`. On test/gc_str_budget_objects.rb `obj` collected 224 times with no share, where the default collects 44 times; on test/gc_str_budget_still.rb `walk` collected 33 times where the default collects 106, and with the object budget held at a 64 MB floor the default and `walk` both collected 17 times. The measurement has its own variable now, written before those knobs are applied, and `fixed` leaves the object retune after it instead of at the top. Each knob pins its own budget. With neither set the two values are the same number, so nothing else moves: the default, `walk` and `str` arms of both programs report the same `[gc]` lines as before. The other one is the reading. A string sweep that reclaims under a quarter doubles the budget as it stands and puts no share in, but `old obj in str trigger` kept the figure the last productive sweep had left. It is zero after such a sweep now. test/gc_str_budget_kept.rb goes through that branch (records first, then Strings past the slab's size, all kept): 2.80 MB before, 0.00 after. gc-str-budget-test holds both: four runs under SPINEL_GC_OBJ_BUDGET (`obj` on the first program, `walk` and a held budget on the second, the last one against `walk` under the same held budget), and the new program read against `str` for the share and against zero for the reading. Put back as it was, lib/sp_alloc.c fails four of the new checks; 17 mutations of the final code, 16 red, and the green one is the share at 1/4, which the leg leaves free on purpose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Gate: green tree 74292b1 master ad681d6 (linux-x86_64 gcc-14.2.0) tests 6831/0
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to The string-budget gate now uses the measured mark share independently of the object-budget setting, and unproductive sweeps report zero share. Added regression cases cover the relevant budget modes and retained strings; no concrete blocker remains before normal checks. Pre-merge checks |
|
What this changes
A follow-up to #8444: the two review findings it was merged with, both real, and a correction to one sentence of its description.
The string budget's gate read what
SPINEL_GC_OBJ_BUDGETmade of the mark share, not the share.sp_str_retunegated the share of the object old generation onsp_gc_obj_alpha1024. That is the object budget's decision:objsets it to 0,walkto 1, and underfixedit stays at its initial 1, because the object retune returned before measuring anything. So pinning the object budget pinned the string budget too:test/gc_str_budget_objects.rb,SPINEL_GC_OBJ_BUDGET=objold obj in str trigger 0.00 MBtest/gc_str_budget_still.rb,SPINEL_GC_OBJ_BUDGET=walkSPINEL_GC_STR_BUDGET=walkSPINEL_GC_OBJ_BUDGET=fixed SPINEL_GC_THRESHOLD_OBJ_KB=65536SPINEL_GC_STR_BUDGET=walkbeside it)The measurement has its own variable now (
sp_gc_mark_share1024, static), written before those knobs are applied, andfixedleavessp_gc_retune_objectafter the measurement instead of at the top. Each knob pins its own budget. With neither set the two values are the same number, so nothing else moves: the default,walkandstrarms of both programs print the same[gc]lines as on master.old obj in str triggerkept a share the trigger no longer carried. A string sweep that reclaims under a quarter doubles the budget as it stands and puts no share in, but the reading stayed at what the last productive sweep had left. It is zero after such a sweep now.test/gc_str_budget_kept.rb(new) goes through that branch: 2.80 MB before, 0.00 after. Its kept Strings are 3 KB each because Strings the slab takes never reached the branch here: kept alive in ten different ways, every sweep of them read as 40% reclaimed. I have not chased why.gc-str-budget-testholds both: four more runs underSPINEL_GC_OBJ_BUDGETand the new program, read againststr(the share was carried) and against zero (the reading was cleared). Withlib/sp_alloc.cput back as #8444 left it, four of the new checks fail; of 17 mutations of the final code 16 are red, and the green one is the share at 1/4, which the leg leaves free on purpose. The other six collector legs pass.A correction to #8444's description. It said that a scheduled string major skipped when it has nothing to free "would also take away the
gc_str_budget_stillcost". Measured since, it does not: with those majors skipped the program still peaks at 56 MB. The peak is one wide cycle at the change of phase, when the first string sweep after the heap is built reads the mark share of the last collection of the building phase; it is not the cycles after the full marks. Wide cycles among the string retunes of that program: 13 of 86 with the schedule as master has it, 6 of 237 with the scheduled majors skipped, 2 of 323 with full collections kept out of the gate altogether, and 56 MB each time against 26 MB underSPINEL_GC_STR_BUDGET=str. So that cost stands as the description gave it, and nothing I have tried takes it away.Counts and megabytes above are from one laptop under Docker (gcc 14.2, linux-x86_64); none of them is a time.
make gate(on this branch merged with current master)The gate ran on this branch as it stands, on master
ad681d651(theGate:trailer). Master is at00802fd5eas this opens, 34 commits later; none of them toucheslib/sp_alloc.corlib/sp_gc.c, and the branch merges cleanly. On that merged tree I ran again the three string-budget tests and the seven collector legs (gc-str-budget-test,gc-obj-budget-test,gc-str-major-test,gc-threshold-test,gc-phases-test,gc-stress-test,gc-minor-test), all passing. I did not run the whole gate a second time..expectedfiles that match CRuby 4.0 run with--enable-frozen-string-literal# spinel: int64(none: the new program stays under 2^31)lib/)Written by Claude Code (AI assistant) on behalf of @namespaceMarcello, who directs this work.
Summary by CodeRabbit