Conversation
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.
Profiling the jobqueue campaign found 38.6% of a seed's wall time inside the
gc.collect()inrun_until_complete(_loop.py:558) — 2.4 ms a call, twiceper seed. The collection is load-bearing: it is what finalizes a dropped
failing task's reference cycle so its exception reaches the loop instead of
vanishing. What it should not be doing is re-walking the imported heap.
Measured in a warmed worker: 20,091 of 22,791 tracked objects are modules,
classes and functions a run cannot make garbage, and a full collection walks
all of them every time.
gc.freeze()moves them to the permanent generation,which collections never traverse. A run's own cycles are all allocated after
the freeze, so the collection still sees everything it saw before — the
collect drops from 1.65 ms to under a microsecond.
Worker throughput on the green campaign roughly doubles: 32.5 to 67.8
seeds per CPU-second, +108% (median of 5 interleaved 2,500-seed runs, 10
jobs, every tree's own spread under 1.5%; reproduced in two separate
sessions at +109.7% and +108.3%). Wall clock went 225 to 439 seeds/s on a
laptop that was not idle, which is why the CPU-second figure is the one to
read.
The freeze happens in simloop's own spawned workers, on the first batch —
after the workload's module is imported, once, so a later call cannot make a
run's garbage permanent. It never touches the calling process:
jobs=1never reaches this path, and neither does the parent of a parallel run.
Verified:
-m "slow or not slow"(565 before, +1 new test), mypystrict clean.
scheduling event, and the digest guards are green.
field except elapsed time: same failing seeds, same labels, same densities.
worker to report it. It fails if the collection is removed, so it guards
the guarantee rather than restating it.
Two things deliberately left out:
unretrieved exception. It skips 100% of collections on the green campaign
and is 1.5x faster, but it is not sound — a
loop.create_future()set withan exception and dropped is a cyclic orphan that is reported today and is
not in the loop's task registry. Confirmed by direct test, not by argument.
sequential sweep from 77.6 to 111.8 seeds/s (+44%). It works, but it
freezes the caller's heap, and a library making that global a change to
someone's pytest process is your call, not mine.
Note
benchmarks/README.mdstill records the green campaign at 263.1seeds/s. That number is now low, but this laptop is not idle and PR #33 is
exactly about not publishing absolute throughput measured in that state —
worth re-running on an idle machine alongside the version stamp before
tagging. Merging #33 first avoids touching the same section twice.