Repository navigation
Conversation
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.
Required human contributor answers
The author's recorded answers in #160 describe the reusable CUDA-operator work that this PR continues:
1. What outcome are you trying to achieve?
Reuse the outcome in #160, question 1: a complete path for developing and integrating further native CUDA operators. This change applies that path to Ouro RMSNorm and its following residual addition.
2. What is the highest-leverage variable for that outcome?
Reuse #160, question 2: activation memory movement, kernel launches, and parallel computation while preserving the numerical contract.
3. How will this work move that variable rather than create busywork?
Reuse the fusion, aligned vector body, safe scalar boundaries, paired arithmetic, and matched numerical/performance checks described in #160, question 3. Here those techniques combine RMSNorm and its existing subsequent residual add. The Ouro integration uses a separately validated PyTorch-order reduction and falls back where that reduction has not been validated.
4. Who is the customer or user, and what do they actually need?
Reuse #160, question 4: the author developing CUDA operators for vllm-rlt needs an implementation, build, model-integration, and validation path for subsequent operators.
PR necessity and bugfix evidence
The author explicitly requested this RMSNorm PR. The existing implementation is a sequence of PyTorch operations; using a native kernel and fusing the subsequent add requires repository changes. This is an optimization, not a claimed pre-existing correctness bug.
Purpose
Add a native inference RMSNorm operator with optional residual addition and use it in Ouro. The operation preserves Ouro's order:
Test Plan
vllm-rlt Version / Commit: base
989921ac1d3897c5c43e27ec8cddbc91fa953194; runtime implementation4f3ce8e1921af2224a98378a4dadb2be373b4bbb; final head59f964cc741d38643fa22edaafb931da67291f8eadds documentation and the timeline only. Measurements and execution tests ran on the identical runtime source at4f3ce8e.pre-commit run --all-files: Ruff lint, format and the complete CPU regression suite passed. A separate Python-only import/fallback and CPU autograd check also passed.pytest tests/test_normalization.py tests/test_ouro.py tests/test_activation.py tests/test_native_build.py --run-gpu -q: 348 passed after rebuilding the extension for SM80 and SM103. Coverage includes independent input/weight/residual offsets, outer strides and singleton strides, odd/empty widths, special values, staged rounding, current streams, Graph replay, fallback and existing Ouro/SiLU behavior.Test Result
Unprofiled, same-checkout three-way A/B after shape-specific warmup, three interleaved repetitions. Each backend has its own model worker resident on the same GPU, with only one submitting work at a time. Ouro-1.4B, BF16, Triton attention, fixed four loops, greedy, ignore EOS, KV 1536 × 16, max sequences 8, max batched tokens 1024, prefill chunk 256. Prompt IDs are constructed by repeating/truncating the first GSM8K questions to the indicated input lengths. Output throughput is successful output tokens divided by the local request window including prefill, scheduling and IPC; it excludes network time. All token IDs, exit depths, finish states and request/KV cleanup matched.
The columns are medians. The full replacement is +36.6% and +30.5%, respectively; the final residual fusion relative to the middle column is +3.1% and +2.4%. Per-run ranges were 68.69–69.11 / 90.79–91.89 / 94.15–94.92 token/s for concurrency 1, and 368.40–369.51 / 442.46–471.17 / 480.73–482.18 for concurrency 8. The latter separate-add run shows scheduling variation. For concurrency 1 the medians of per-run TPOT p50 were 14.151 / 10.650 / 10.331 ms; TTFT p50 was 35.334 / 26.932 / 24.732 ms. For concurrency 8 TPOT p50 was 19.837 / 15.398 / 15.006 ms and TTFT p50 was 96.387 / 87.039 / 88.473 ms. These are short closed-loop bursts, not saturation, tail-SLO, or task-quality measurements.
All three single-request workers captured one recurrent graph, replayed it 4032 times and had zero recurrent graph fallbacks; the concurrency-8 workers captured six, replayed 6060 times and also had zero fallbacks. Only the compatibility path is included in model speed claims; generic kernel timings are not substituted for it.
Source attribution and matched profiles
One fixed-depth decode batch invokes
(24 layers × 4 RMSNorms + 1 final norm) × 4 loops = 388norms. In this environment, the prior Torch expressions use 8 GPU kernels for a plain norm and 9 with residual, versus one each in the compatible implementation. For a warmed 128-input/2-output Graph request, matching separate ops-only and full CPU+CUDA profiles observed 11004 → 5188 total GPU kernels, a difference of 5816 across prefill plus one decode. Four recurrent graph launches were present in each decode; the first replay contained 1386 → 659 GPU kernels. The candidate trace contains 776rms_norm_torch_order_kernellaunches across the two forwards. Both profile variants completed with the same two output IDs and depths.The full and zoomed panels use matching time scales; the first replay's profiled GPU span is 3.390 → 2.319 ms. Profiler timings are diagnostic, not the performance source. A separate unprofiled A/B with the same 128-input/2-output shape measured 41.61 → 57.03 output token/s, with 14.278 → 10.406 ms TPOT p50 medians; the four-request, two-output-token window is especially short. Raw ops-only/full archives, their shape/memory/stack artifacts, source hashes, request IDs and per-run results are retained locally under ignored
artifacts/rmsnorm-submission/; they are not yet uploaded for external review. Peak memory and other GPU architectures have not been qualified. The PR remains draft while externally accessible raw traces are pending.Reproduction
Use an allocated GPU and a prepared CUDA-enabled PyTorch/toolkit environment:
The serving guide contains engine startup, a single request and batch client examples; those HTTP timing boundaries differ from the local worker results above. The exact same-checkout A/B, natural/adaptive, and profile drivers and results are retained in the local artifact directory above.
AI assistance was used for implementation, measurements and author self-review.