Skip to content

← Memory, Copies and Slow Code step 28 of 38

Medium Framework

Compare Best Timings and Put the Garbage Collector Back

Write two small helpers. The first compares two lists of timings by their best run. The second times a function with timeit, keeps the garbage collector on while it times, and leaves the collector exactly as it found it. The tests check the arithmetic and the collector setting, not how fast your code runs.

Compare best timings

reduce_ratio(timings_a, timings_b) returns min(timings_a) / min(timings_b).

  • Both sequences are non-empty and hold positive times per run, in the same unit.
  • A result above 1 means A's best run is slower than B's.
  • Don't change either sequence.
assert reduce_ratio([3.0, 2.0, 5.0], [1.0, 4.0]) == 2.0  # the means give 1.33

Time with the collector on

measure(*, repeat) gets a repeat count of 1 or more. Keep the provided probe. Each time it runs, it records in OBSERVED whether the collector is on. Then follow these steps:

  1. Save whether the collector is on, with gc.isenabled().
  2. Clear OBSERVED and create timeit.Timer(probe, setup=gc.enable). The setup turns the collector back on after timeit turns it off.
  3. Call timer.autorange() to get a loop count. Then call timer.repeat(repeat=repeat, number=number).
  4. In a finally block, put the collector back the way you found it, on if it was on and off if it was off. Do this even when timing raises, and let the error reach the caller.
  5. After the finally block, return:
Key Value
samples the number of totals that repeat returned
loops_ok whether the loop count is at least 1
gc_on_during OBSERVED.get("gc_during", False)
gc_enabled_after gc.isenabled(), read after you restore the setting

Step 4 needs both branches. timeit turns the collector back on only if it was on when timing started. If it was off and your setup turned it on, it stays on until you turn it off. The test starts with the collector on, but your code must handle a collector that starts off too.

What the driver reports

Keep solve as it is. It returns ratio, the result of reduce_ratio rounded to nine decimal places. It also returns measured, which is the report from measure when do_measure is true and None otherwise.

Your submission must pass mypy --strict.