Add --duration flag to perf for time-budgeted benchmarking#1168
Add --duration flag to perf for time-budgeted benchmarking#1168xieofxie wants to merge 1 commit into
Conversation
Run the benchmark for a wall-clock budget (seconds) instead of a fixed --iterations count. After warmup, inference loops until the duration elapses (always at least one benchmark iteration). Ideal with --monitor, whose PDH counters need time to emit real utilization data. Rejected with --op-tracing, which runs its own fixed iteration count. Works across the single-model, monitored, and per-module paths. The live --monitor chart shows elapsed/total time progress in duration mode. The reported iteration count reflects the actual timed sample count instead of the unused --iterations default. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Needed for #1149 |
DingmaomaoBJTU
left a comment
There was a problem hiding this comment.
Took a pass through this — the overall approach looks good. The warmup→timed-loop split, the at-least-one-iteration guarantee, the --op-tracing conflict, and the genai ignored-flag warning are all correct, and the tests cover the important paths.
A few minor nits (none blocking):
perf.py L732-734 — logger.info("Running benchmark: %d iterations + %d warmup", ...) still logs the fixed iterations count in --duration mode, so it reads e.g. "Running benchmark: 100 iterations + 10 warmup" for a run that's actually time-bounded. Might be worth branching to log the time budget there.
Two more inline below.
| for i in _benchmark_indices(total_iterations, warmup, duration_sec): | ||
| session.run(inputs) | ||
|
|
||
| if (i + 1) % max(1, total_iterations // 10) == 0: |
There was a problem hiding this comment.
In --duration mode i keeps counting past total_iterations (the loop is time-bounded, not count-bounded), so this progress log can read e.g. Progress: 350/110. The total_iterations denominator here — and on the logger.debug line just below — is meaningless once the run is timed. Minor since it's debug-only, but might be worth switching to an elapsed/duration readout in duration mode.
| and self._bench_start is None | ||
| and iteration > self._warmup | ||
| ): | ||
| self._bench_start = time.perf_counter() |
There was a problem hiding this comment.
This stamps _bench_start on the first post-warmup update(), which runs after that iteration's session.run(). But _benchmark_indices starts its own budget clock before that run (perf.py L1771) and the loop terminates on the generator's clock. Net effect: this display clock lags by ~one inference, so Time: x/Ns tends to finish a bit under 100%. Purely cosmetic — if you want the bar to land on 100%, share the generator's start timestamp with the display instead of re-stamping here.
Summary
Adds a
--duration <seconds>flag towinml perf. When set, the benchmark runs for a wall-clock time budget instead of a fixed--iterationscount. After warmup, inference loops until the duration elapses (always running at least one benchmark iteration so stats are never empty).This is ideal with
--monitor, whose PDH hardware counters need time to emit real utilization data — a small fixed iteration count often finishes before the counters produce meaningful samples.Details
--duration FLOAToption (must be> 0), plumbed throughBenchmarkConfig.duration._benchmark_indices()helper centralizes the loop: warmup first, then either a fixed iteration count (default) or a timed loop. Used by the single-model, monitored, and per-module paths.--op-tracing(op-tracing runs its own fixed, small iteration count) — rejected with a clearUsageError.--monitorchart shows elapsed/total time progress (Time: 12.3/30s) in duration mode instead of an iteration counter.--iterationsdefault. For per-module runs (where each module runs a different count under a shared budget), the count is recorded per instance and the top-level value isnull; both single-model and module reports also recordduration_sec.--durationis added to the genai "ignored flags" warning (genai benchmarks by token generation).Tests
--durationhelp/forwarding/default,--op-tracingconflict, non-positive rejection._benchmark_indicesiteration mode, timed budget, and at-least-one-iteration guarantee (deterministic via a faked clock).LiveMonitorDisplaytime-based vs iteration-based progress.benchmark_info.iterationsreports configured count without duration and actual sample count with duration.All perf suites pass (
test_perf_cli,test_perf_module,test_perf_composite,test_ep_monitor): 200 passed, 2 NPU-only skips;ruffclean.