Repository navigation
Conversation
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
One backend per PR: PR title tags & labels: |
READY FOR HUMAN REVIEWPR Self-ReviewRevision Author self-review accepted. Readiness report: Author answers
Show the author's self-review answersBehavior and intentValidation and unverified scopePR-specific questionChanged op testsPR state
Copilot findings
Code and op-test hygiene
Required CI
Shadow mode reports what would block but keeps the status successful. Set |
The power window launched each candidate from Python, so a kernel whose launch took longer than its GPU time left the GPU idle between launches and read low. The launch-gap correction recovered most of that, but split-K FlyDSL GEMMs still read 12-28% under graph replay. measure_kernel now captures the call into a CUDA graph holding about 1 ms of GPU work and replays it for the window. A call that cannot be captured is logged once and sampled eagerly with the existing correction; AITER_POWER_GRAPH=0 forces eager. Without a timed us, one warm call is timed to size the graph. The capture helper lives in aiter/utility/cuda_graph.py and the IQ2R timer uses it. IQ2R now hands its call list to the power sample like every other tuner. Co-authored-by: Cursor <cursoragent@cursor.com>
556907c to
f34fb38
Compare
Summary
--select power, from [HIP] [CK] [JIT] [Tuner] Rank accuracy-qualified kernels by package energy #6970) ranks candidates byus × package watts. The power sample launched each candidate from Python, so a kernel whose launch takes longer than its GPU time left the GPU idle between launches and read low. [HIP] [CK] [JIT] [Tuner] Rank accuracy-qualified kernels by package energy #6970's launch-gap correction recovers most of that fortorch.mm, but split-K FlyDSL GEMMs still read 12-28% under their true power, enough to pick the wrong winner on close shapes, and kernels under ~5 µs were left unmeasured.package_power.measure_kernelnow captures the candidate's call into a CUDA graph holding about 1 ms of GPU work and replays it for the sample window, so the sensor sees the kernel back to back with no host gaps. A call that cannot be captured (host sync, CPU-side work) is logged once per reason and sampled with the existing eager loop and correction.AITER_POWER_GRAPH=0forces the eager path. Without a timedus, one warm call is timed to size the graph.aiter/utility/cuda_graph.py; IQ2R's timer uses it, and IQ2R now hands its call list to the power sample like every other tuner. No tuner decides how power is measured.PR Self-Review
Reviewed revision
f34fb38
Behavior and intent
Power-mode tuning only.
measure_kernel(the single power-measurement function from #6970) replays a CUDA graph of the timed call instead of launching it eagerly from Python, because eager launches leave the GPU idle whenever the host launch path is longer than the kernel, which under-reads power for short and split-K kernels and can flip the energy ranking. Eager sampling with the #6970 launch-gap correction remains the fallback when capture fails, andAITER_POWER_GRAPH=0forces it. Latency tuning and runtime dispatch are unchanged.Validation and unverified scope
Hardware: 8× MI355X (gfx950), ROCm 7.2.4, power cap 1400 W, clocks auto (SCLK 500-2400 MHz), GPUs otherwise idle.
torch.mm64×7168×2048 779 vs 639. Graph readings match an independent CUDA-graph measurement (892 / 987 / 768 W).python -m unittest op_tests.tuning_tests.test_fast_tuning— 59 tests pass, including real-sensor tests: a launch-bound GEMM (~100 µs host work per 22 µs kernel) reads 881 W by graph replay vs 850 W back to back and 594 W eager; a failed capture leaves the device usable.test_mp_tuner_logic,test_compare_logic,test_config_shape_collision,test_csv_validation,test_fhmoe_tuner,test_a6w6_tuning,test_mixed_mxfp_tuning.test_tuner_infrahas 2 failures (a_preshuffleblank-cell) that also occur on main.--select powertunes on GPUs 0-7 with the shipped low/mid/high shapes: a16w16 (all backends, 4 shapes), gradlib hipBLASLt (4), a8w8 (3), a8w8 blockscale (3), CK MoE ASM FP8 (3), MXFP4 staged (3) and fast scan (2), IQ2R (3). All exit 0 with no capture fallback; every row is stamped with finite watts; every pick is the minimum-energy measured candidate. a16w16 16×128×128 now measures all 82 candidates (39 of 40 FlyDSL candidates were unmeasured with eager sampling). MXFP4 32 tokens reads 797-805 W vs ~540 W eager.mp_tunerworker, and with--shape_groupedthat drops every candidate of that shape (the shape comes out untuned). It did not happen on the eight tuner paths above (0 capture fallbacks, 0 crashes);AITER_POWER_GRAPH=0avoids it, and automatic eager retry is left for a follow-up if it shows up in practice.PR-specific question
No kernel dispatch path changes. Which kernel runs is still chosen by the tuned CSV for the arch/dtype/shape keys. This changes only how
--select powermeasures a candidate during tuning; runtime never captures or replays graphs. Graph replay applies only insidemeasure_kernel, which the latency policy never calls, and an uncapturable call falls back to the previous eager measurement.Changed op tests
op_tests/tuning_tests/test_fast_tuning.py— the only changed op test. New cases, none redundant with existing ones:test_power_sample_replays_a_graph_and_falls_back_to_eager: graph path used when capture succeeds (window replays the graph and frees it), eager path with the correction when capture fails, andAITER_POWER_GRAPH=0skips capture.test_power_sample_times_the_call_when_no_us_is_given: withoutus, one timed call sizes the graph and drives the fallback correction.test_graph_holds_about_a_millisecond_for_a_timed_call(GPU): the captured graph holds ~1 ms of work.test_failed_graph_capture_returns_none(GPU): a host-syncing call is rejected, logged, and the device stays usable.test_graph_replay_reads_a_launch_bound_kernel_at_full_power(real sensor): host work between launches does not dilute the graph sample.Test plan
python -m unittest op_tests.tuning_tests.test_fast_tuning(59 tests, MI355X)--select powertunes on 8 tuner paths, low/mid/high shapes, MI355X (see Validation above)