bench(rocm,rope): add native-vs-AITER cos/sin-cache RoPE benchmark#267
Merged
Conversation
Adds a committable, reproducible RoPE benchmark mirroring bench_silu_and_mul.py: sweeps nnz x dtype across both op modes (inplace + out-of-place) comparing the native HIP JIT kernel against AITER through the RocmProfiler harness, plus an --accuracy mode for the native-vs-AITER numerical-error axis the backend="auto" policy depends on. No vLLM dependency (unlike the upstream benchmarks/bench_rope.py). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a ROCm-focused benchmark script to compare FlashInfer’s native HIP JIT RoPE (cos/sin-cache) implementation vs the optional AITER backend, including an accuracy reporting mode to support/justify backend routing decisions.
Changes:
- Introduces
benchmarks/rocm_benchmarks/bench_rope.pyto benchmarkapply_rope_with_cos_sin_cache{,_inplace}across nnz × dtype × backend × op mode. - Adds an
--accuracymode to print native-vs-AITER max-abs error, and an--opflag to restrict to inplace/outplace.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address Copilot review on PR #267: - Share a single read-only fp32 cos/sin cache (~32 MiB) across all configs instead of reallocating per config, avoiding GPU OOM before profiling starts. - Cast to float32 before the max-abs-error reduction so the accuracy metric does not lose precision in the input dtype and under-report. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment on lines
+83
to
+85
| _COS_SIN_CACHE = torch.randn( | ||
| _MAX_SEQ_LEN, _ROTARY_DIM, device="cuda", dtype=torch.float32 | ||
| ) |
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.
Summary
Adds a committable, reproducible cos/sin-cache RoPE benchmark for ROCm, mirroring
bench_silu_and_mul.py. Until now thebackend="auto"routing decisions for RoPE (PR #252, then the auto→native default in #259) rested on ad-hoc experimentation with no committed script or recorded methodology — the numbers couldn't be reproduced from the tree. This script makes that comparison a first-class, re-runnable artifact: native (in-tree HIP JIT) vs AITER, swept across nnz × dtype × op mode, plus an accuracy axis for the numerical-error half of the policy.What changed
benchmarks/rocm_benchmarks/bench_rope.py(new) — drivesapply_rope_with_cos_sin_cache/_inplacethrough the existingRocmProfilerharness. Sweeps nnz[8 … 32768]× {f16, bf16} × {native, aiter} × {inplace, out-of-place} on the Llama-3 8B attention shape (q32 / k8, head_size 128, full rotary).--accuracyprints AITER-vs-native max-abs-error;--op inplace|outplacerestricts the op mode; falls back to native-only when AITER is unavailable. No vLLM dependency (unlike the upstreambenchmarks/bench_rope.py).Design notes
Two op modes are benchmarked because they diverge for AITER: the inplace path rotates q/k in place, while the out-of-place path uses AITER's zero-copy
_implentry point (no q/k copy) — which is where AITER's largest wins land. The accuracy axis exists because the auto policy turns partly on bf16 numerical error sitting near the test tolerance edge, so latency alone doesn't capture the trade-off. The kernel is memory-bandwidth bound (reads + writes q and k per token), so tokens/sec against the HBM ceiling is the headline metric.Benchmark results
MI300X (gfx942), median kernel time via
bench_rope.py --timing-only. Native leads at every nnz on the inplace path; AITER crosses ahead only at large nnz out-of-place (its zero-copy entry point), consistent with PR #252's finding that the out-of-place path is where AITER wins.Inplace (
apply_rope_with_cos_sin_cache_inplace), median µs:Out-of-place (
apply_rope_with_cos_sin_cache), median µs:Accuracy (AITER vs native, max abs error): fp16 tops out ~7.8e-3; bf16 reaches ~3.1e-2 at nnz=32768 — near the test tolerance edge, matching the auto policy's bf16→native rationale.
Test plan
python benchmarks/rocm_benchmarks/bench_rope.py --timing-only— both op modes, 80 configs, ran clean on gfx942 with AITER installed (numbers above)python benchmarks/rocm_benchmarks/bench_rope.py --accuracy— native-vs-AITER error table, ran clean--opargument guards (missing value / bad value) exit with a clear messagepre-commit run -a