Skip to content

gc-matrix: intermittent output mismatch on test_gap_repsel_gc_stress x safepoint_minor (1 in 11, 10/10 clean in isolation) #7678

Closed

Description

@proggeramlug

Summary

test_gap_repsel_gc_stress × safepoint_minor produced an output mismatch in a full 58-file scripts/gc_repsel_matrix.sh --arms pr run, and 10/10 clean when the identical binary is re-run in isolation with the identical env. It is intermittent, it is untriaged, and it is on the arm the matrix leans on hardest.

Evidence

Full run (58 files x 7 PR arms, --pressure 8, node 26.5.1, release compiler):

FAIL test_gap_repsel_gc_stress (output-mismatch cycles=52 evacuated=0 scavenged=38184 reclaimed=799294640)
summary: PASS=341 UNVER=64 XFAIL=0 FAIL=1

Isolated re-run, same binary (compiled with PERRY_GC_MOVING_LOOP_POLLS=1), same run env
(PERRY_GC_HEAP_LIMIT=8 PERRY_GC_MOVING_LOOP_POLLS=1 PERRY_GC_TRACE=1 PERRY_GC_DIAG=1), 10 runs:

10 ok, 0 bad, of 10

with copied_objects per run at 415,450 (x8), 415,453 and 303,205 (x2) — so the arm is live on every run and the collection schedule itself varies run to run.

Note the mismatching run also scavenged far less than the clean ones (38,184 vs ~415,450), i.e. it took a different collection schedule, not merely a different outcome under the same one.

Why it is worth its own issue

safepoint_minor is described in gc_repsel_matrix.sh as "THE SOUND RELOCATING ARM, and what keeps the #6993 defect class reachable per-PR while #7161's stopgap holds." It compiles and runs with PERRY_GC_MOVING_LOOP_POLLS=1 — the configuration #7161 turned off by default precisely because of #7154's use-after-free. An intermittent wrong-output on that arm is consistent with that open class still biting at a low rate, which is exactly the thing the arm exists to surface.

The last main gc-stress run (31240304595) reported FAIL=0 over 22 arms, so this is a low-rate sampling difference rather than a new deterministic break — which is what makes it easy to lose.

Deliberately NOT triaged

It is not in test-parity/gc_repsel_triage.txt and should not be added until it is root-caused. Triaging a red nobody has explained is how a real defect becomes permanent furniture — and test-parity/gc_repsel_triage.txt entries are supposed to name a cause, not a symptom.

Suggested first step

Capture the mismatching run's stdout and diff it against the oracle to find which line diverges (the harness discards the diff today; only output-mismatch survives into the cell evidence). A per-cell saved diff for FAIL cells would make this class self-documenting, and is cheap — the harness already writes both files.

Activity

  1. proggeramlug commented on Aug 10, 2026

    @proggeramlug
    ContributorAuthor

    Closing as not reproducible, on the arm's own harness rather than a hand-rolled approximation.

    scripts/gc_repsel_matrix.sh --arms safepoint_minor --filter test_gap_repsel_gc_stress, six consecutive rounds on current main (v0.5.1432): 6/6 PASS, 0 FAIL, 0 UNVER, with the arm reporting live 1/1 counter=44806 every time.

    live rather than UNVER is the part that makes this meaningful — the matrix distinguishes "output matched" from "output matched and the arm actually collected", and an inert arm would be a pass that exercised nothing. This issue reported 1-in-11; six clean rounds is not a proof of absence, but combined with the evidence below it is enough to stop tracking it.

    An earlier pass got much further and found the same thing at greater scale: 280+ runs with zero mismatches, across four configurations — 120 serial with PERRY_NO_AUTO_OPTIMIZE=1, 100 serial with a real auto-optimize build (matching how the harness actually links), 60 across six rounds of 10-way parallel invocation on a box at load 53 (a deliberate proxy for the matrix's own xargs -P fan-out, since a parallel-only race was the obvious hypothesis), and one direct harness invocation. Every run reported the identical schedule: copy_minor_runs=53 copied_objects_total=44804, with no variance at all — notably more deterministic than this issue's own isolated re-runs, which had copied_objects varying across 415450 / 415453 / 303205.

    That last detail is the strongest signal: the nondeterminism this issue was filed about is itself gone. The scheduling now reproduces exactly, run to run, serial or parallel.

    Reopen with the copied_objects value and the xargs -P width if it returns — those two are what distinguish a real schedule race from an inert arm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions