Add opt-in multi-GPU sweep parallelism; fix GPU pinning and run dir races
For shape-heavy ops the autotune sweep dominates wall time, not the measurement. _parallel_warmup_plugin shards the sweep across N GPUs and hands the merged configs to the normal single-GPU serial measurement, so timing stays comparable. Activated by PARALLEL_WARMUP_GPUS=N (silent no-op when unset, so it can stay in the plugin list); output layout, REPLAY_FROM usage and the latency table are unchanged. Measurement is deliberately not parallelized: N processes saturating one box couple through the power/thermal budget, so per-card latency gets dragged by its neighbours by an amount that does not reproduce. Config keys whose winner differs across shards are counted and reported as a WARNING -- that count is how much to trust the run. Fixes found while auditing: - Shards no longer overwrite CUDA_VISIBLE_DEVICES with a bare shard index, which a caller who had selected idle cards (e.g. 6,7) would see re-interpreted as absolute ids 0,1 -- silently benchmarking on the busy cards they were avoiding. - Interrupting the sweep no longer leaves N subprocesses holding GPUs; children are terminated and reaped before the exception propagates (BaseException, since KeyboardInterrupt is not an Exception). - run_pytest.sh claims its output dir with a bare mkdir and retreats to a -2/-3 suffix on collision. The second-resolution timestamp meant two concurrent runs shared one directory and overwrote each other. - Replay eviction failures now emit a distinct compile_*_no_evict marker. LibTuner.cache is a sqlite-backed ConfigCache with no __delitem__, so the bad config could not be dropped and the retry re-read it, while the log still claimed a clean fallback to live autotune. Also trims comment density in both shell scripts and reworks the README: promotes the parallel and cudagraph sections out from under the A/B flow, groups the env table by purpose, documents that two record-mode runs are not comparable, and marks ab_fold_test.sh as a caliber example whose switch upstream has already removed.
This commit is contained in:
@@ -180,12 +180,21 @@ def _replay_run(original):
|
||||
except Exception as exc:
|
||||
if injected_key is not None:
|
||||
# Recorded config failed under the current build: drop it and
|
||||
# let run() autotune.
|
||||
# let run() autotune. Only Autotuner.cache is a plain dict;
|
||||
# LibTuner.cache is a sqlite-backed ConfigCache with no
|
||||
# __delitem__, so eviction is impossible there -- say so in the
|
||||
# marker instead of retrying with the same bad config and
|
||||
# reporting a clean fallback.
|
||||
evicted = True
|
||||
try:
|
||||
del self.cache[injected_key]
|
||||
except Exception:
|
||||
pass
|
||||
_emit_marker(f"compile_{type(exc).__name__}")
|
||||
evicted = False
|
||||
# _no_evict means the retry below re-reads the same recorded
|
||||
# config, so it is not a clean "fell back to live autotune":
|
||||
# treat those measurement points as unverified.
|
||||
suffix = "" if evicted else "_no_evict"
|
||||
_emit_marker(f"compile_{type(exc).__name__}{suffix}")
|
||||
return original(self, *args, **kwargs)
|
||||
raise
|
||||
return runner
|
||||
|
||||
Reference in New Issue
Block a user