Skip to content

feat(hip,aiter): default silu_and_mul and rope auto backend to native#259

Merged
demandal25 merged 2 commits into
ROCm:amd-integrationfrom
demandal25:update-auto-backend-silu_rope
Jun 17, 2026
Merged

feat(hip,aiter): default silu_and_mul and rope auto backend to native#259
demandal25 merged 2 commits into
ROCm:amd-integrationfrom
demandal25:update-auto-backend-silu_rope

Conversation

@demandal25

Copy link
Copy Markdown
Collaborator

Summary

Make backend="auto" resolve to the in-tree HIP native kernel (instead of routing to AITER on gfx942/gfx950) for silu_and_mul and the cos/sin-cache rope ops. Experimentation found the native kernels to be the better default for these two ops; the C++ AITER path stays reachable via an explicit backend="aiter".

What changed

  • flashinfer/activation.py_auto_select_silu_and_mul_backend now always returns "native"; the silu_and_mul docstring describes the new auto behavior.
  • flashinfer/rope.py_auto_select_rope_backend now always returns "native"; both apply_rope_with_cos_sin_cache and its inplace variant document the new auto behavior. Also reconciled the inplace docstring, which incorrectly claimed AITER consumes the cos/sin tables in the query dtype — the C++ shim (rope_aiter.cu) passes them as float32.
  • tests/rocm_tests/test_activation_hip.py, test_rope_hip.py — added test_*_auto_backend_selection asserting auto resolves to "native".
  • tests/rocm_tests/test_activation_aiter_hip.py, test_rope_aiter_hip.py — removed the old auto-selection tests from the AITER modules. Those modules are gated behind requires_aiter (skipped when the aiter package is absent), but the auto-default contract is aiter-independent, so the tests now live in the native modules where they run on any HIP build.
  • README.md — Feature Support Matrix (RoPE, Activation rows) and the AITER Support prose updated to reflect auto→native for these two ops; the C++ AITER path remains opt-in.

Architecture / design notes

The four C++-level AITER ops now split on auto-routing:

Op backend="auto" resolves to
rmsnorm AITER (2-D fp16/bf16 on gfx942/gfx950), else native
fused_add_rmsnorm AITER on gfx942/gfx950, else native
silu_and_mul native (AITER opt-in via backend="aiter")
rope (cos/sin-cache) native (AITER opt-in via backend="aiter")

The _auto_select_*_backend helpers are kept (rather than inlining "native") as the uniform extension point and test seam, matching the pattern in norm.py.

Test plan

  • pytest tests/rocm_tests/test_activation_hip.py tests/rocm_tests/test_activation_aiter_hip.py tests/rocm_tests/test_rope_hip.py tests/rocm_tests/test_rope_aiter_hip.py -n auto --reruns 2 — all pass on gfx942 with aiter installed
  • pre-commit run -a

Experimentation found the in-tree HIP native kernels to be the better
default for silu_and_mul and the cos/sin-cache rope, so backend="auto"
now resolves to native for both ops instead of routing to AITER on
gfx942/gfx950. The C++ AITER path stays reachable via an explicit
backend="aiter".

Move the auto-selection tests to the native test modules so the
native-default contract is exercised on any HIP build, independent of
whether the aiter package is installed. Also reconcile the inplace rope
docstring, which incorrectly claimed AITER consumes cos/sin in the query
dtype (the C++ shim passes them as float32).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 17, 2026 02:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes the HIP backend="auto" routing for silu_and_mul and cos/sin-cache RoPE ops to always select the in-tree native implementation (leaving AITER reachable only via backend="aiter"), and updates docs/tests/README to match that contract.

Changes:

  • Make _auto_select_silu_and_mul_backend and _auto_select_rope_backend always return "native".
  • Update public docstrings and README AITER/auto-routing documentation to reflect auto→native for these ops.
  • Move/add tests so auto-backend-selection assertions run independent of the aiter Python package.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
flashinfer/activation.py Forces auto backend selection for silu_and_mul to native and updates docstring.
flashinfer/rope.py Forces auto backend selection for cached RoPE to native and updates docstrings.
tests/rocm_tests/test_activation_hip.py Adds an auto-backend-selection test asserting auto→native.
tests/rocm_tests/test_activation_aiter_hip.py Removes the old auto-selection test from the AITER-gated suite.
tests/rocm_tests/test_rope_hip.py Adds an auto-backend-selection test asserting auto→native (including mixed dtype case).
tests/rocm_tests/test_rope_aiter_hip.py Removes the old auto-selection test from the AITER-gated suite.
README.md Updates the support matrix and AITER support section to document auto→native for these two ops.
Comments suppressed due to low confidence (1)

flashinfer/rope.py:1220

  • The docs now state that backend supports only 'auto', 'native', and 'aiter', and that 'aiter' is ROCm-only. However, on non-HIP platforms the function currently performs no backend validation (because the checks are under if IS_HIP:), so backend='aiter' or any unknown string silently falls back to the native implementation. This is inconsistent with the documented/expected API behavior and with activation.silu_and_mul, which raises on unsupported backends.
    backend : str
        Kernel backend to use. ``"auto"`` (default) resolves to the native
        FlashInfer JIT kernel on all platforms.
        ``"native"`` uses the FlashInfer JIT kernel on all platforms.
        ``"aiter"`` uses AMD AITER's C++ ``rope_cached_positions_2c_fwd_impl``
        kernel — ROCm (gfx942/gfx950) only; requires the ``aiter`` package and
        query/key to share a dtype.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread flashinfer/rope.py
Move the backend-string check and explicit-aiter validation to the top of
apply_rope_with_cos_sin_cache and its inplace variant, matching
silu_and_mul. Previously these checks lived inside `if IS_HIP:`, so on
non-HIP platforms backend="aiter" or an unknown backend string silently
fell through to the native kernel instead of raising — inconsistent with
the documented contract. Addresses Copilot review feedback on PR ROCm#259.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@demandal25 demandal25 merged commit 884712b into ROCm:amd-integration Jun 17, 2026
1 check passed
@demandal25 demandal25 deleted the update-auto-backend-silu_rope branch June 18, 2026 20:52
demandal25 added a commit that referenced this pull request Jun 24, 2026
)

## Summary

Adds a committable, reproducible cos/sin-cache RoPE benchmark for ROCm,
mirroring `bench_silu_and_mul.py`. Until now the `backend="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) — drives
`apply_rope_with_cos_sin_cache` / `_inplace` through the existing
`RocmProfiler` harness. 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). `--accuracy` prints
AITER-vs-native max-abs-error; `--op inplace|outplace` restricts the op
mode; falls back to native-only when AITER is unavailable. No vLLM
dependency (unlike the upstream `benchmarks/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 `_impl` entry 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:

| nnz | native f16 | aiter f16 | native bf16 | aiter bf16 |
|---:|---:|---:|---:|---:|
| 8 | 7 | 33 | 6 | 33 |
| 512 | 10 | 36 | 12 | 35 |
| 2048 | 24 | 46 | 28 | 46 |
| 8192 | 71 | 88 | 72 | 89 |
| 32768 | 218 | 237 | 218 | 237 |

**Out-of-place** (`apply_rope_with_cos_sin_cache`), median µs:

| nnz | native f16 | aiter f16 | native bf16 | aiter bf16 |
|---:|---:|---:|---:|---:|
| 8 | 6 | 34 | 6 | 34 |
| 512 | 9 | 36 | 10 | 36 |
| 2048 | 20 | 45 | 26 | 45 |
| 8192 | 69 | 85 | 70 | 85 |
| 32768 | 225 | 207 | 226 | 209 |

**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

- [x] `python benchmarks/rocm_benchmarks/bench_rope.py --timing-only` —
both op modes, 80 configs, ran clean on gfx942 with AITER installed
(numbers above)
- [x] `python benchmarks/rocm_benchmarks/bench_rope.py --accuracy` —
native-vs-AITER error table, ran clean
- [x] `--op` argument guards (missing value / bad value) exit with a
clear message
- [x] `pre-commit run -a`

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants