Skip to content

tests: the strand recycle case's per-round rendezvous spins too, same shape as #826 #833

Description

@Yaraslaut

tests/test_strand_race.cpp's third case, "StrandExecutor recycles a drained strand under the key that asked for it", has the same coarse per-round rendezvous shape that morph#826 fixed in the case above it, and was not touched by that fix.

At tests/test_strand_race.cpp:607 (current master, after #826 lands), each of 3 producer threads waits out its own round with:

while (completed.at(slot).load(std::memory_order_acquire) < (round + 1) * kBurst) {
    std::this_thread::yield();
}

across kRounds = 900 rounds, 6 iterations. This is the same mechanism #826 diagnosed for the "keeps one strand per key" case: nothing blocks a spinning thread from being scheduled, so under Valgrind -- which runs one thread at a time and lets a yielding thread take the lock straight back -- this loop burns real instrumented CPU time for the whole round instead of yielding it to the actual (slow, instrumented) work.

Verification status: inferred from reading, not independently measured. I have not reproduced a Valgrind stall on this specific case (this host is macOS/arm64, where Valgrind is not practically usable -- same limitation #826's own triage noted). The mechanism is structurally identical to #826's, which was measured on real CI (job 108010066205: ~45 of 54 minutes; PR #806's run 36127304451: >3h before cancellation) for the sibling case in the same file. Whether this case's 900-round loop stalls CI by a similar or smaller margin is unverified -- it has 3 threads instead of 4, yield() on every iteration rather than every 4096 spins, and no fine-grained stagger loop competing for the same core, so the magnitude could differ from #826's case even though the mechanism does not.

What would change the verdict: a Valgrind CI run showing this case's own wall-clock time (the "Valgrind memcheck" job logs a ── memcheck: tests/morph_tests ── header per suite; per-case timing is not broken out, so a large gap in job log timestamps around this case, the way #826 found for its case, would confirm it) either does or does not show a comparable stall. If a future Valgrind run shows this case completing quickly relative to the rest of morph_tests, this can close as not-a-problem-in-practice; if it shows a similar multi-minute-or-worse gap, the fix is the same shape as #826's (block on a condition variable instead of spinning) applied to this case's wait, not a new mechanism.

Found while implementing #826 (a fork of that PR's work flagged it during /simplify's altitude pass); out of scope for #826 itself, whose issue text and triage both named only the "keeps one strand per key" case.

Activity

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

    area: ciSubsystem: cibugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions