Engineering

Write Once, Run Anywhere GPU Kernels: MI300X vs H100 (2026)

Back to BlogWritten by Published Sep 18, 2026
write once run anywhere gpu kernelstriton rocm vs cuda benchmarktriton mi300x vs h100triton amd backend portabilityAMD MI300XH100GPU Kernel DevelopmentAITERGPU Cloud
Write Once, Run Anywhere GPU Kernels: MI300X vs H100 (2026)

Triton's whole pitch is write once, run anywhere GPU kernels: write a kernel once in Python and let the compiler target whatever GPU you point it at, NVIDIA or AMD, without a rewrite. That pitch is testable, because it's now been tested: vLLM's Triton attention backend runs the identical kernel source against both CUDA on H100 and ROCm on MI300-class hardware, and the research behind it publishes exactly what changed and what didn't. We pulled that data apart, added Spheron's own live rates for both GPUs, and turned the gap into an answer to the question that actually matters for renting hardware: does the portability survive contact with a real autotuning pass, and does it change which GPU you should book.

TL;DR: Do Write Once, Run Anywhere GPU Kernels Work for Triton on MI300X vs H100?

  • Tuning does not transfer: AMD's fastest config uses a smaller BLOCK_M (16) than NVIDIA, and AMD tunes waves_per_eu where NVIDIA tunes warp specialization.
  • Launch overhead hits AMD harder: HIP graphs cut MI300-family latency roughly 2x on short sequences; CUDA graphs cut H100 latency only about 6%.
  • Assembly still wins on AMD: TileLang's hand-tuned attention kernel beat Triton's AMD backend 0.36ms to 0.55ms, a 1.53x gap, on MI300X.
  • Price, 19 Sep 2026: Spheron H100 SXM5 runs $2.98/hr on-demand versus MI300X at $3.59/hr, with no MI300X spot tier listed. Rent MI300X on Spheron.

The Setup: Same Triton Kernel Source, Two Backends

The cleanest test of "write once, run anywhere" isn't a synthetic microbenchmark, it's a kernel already carrying production traffic. vLLM's Triton attention backend is that kernel: the team behind it is explicit that "the same Triton kernel source code was used on both platforms," meaning one .py file compiled by Triton's own backend selection, CUDA on NVIDIA, ROCm on AMD, with no forked implementation maintained per vendor.

The research underneath that backend, IBM Research's "Anatomy of a Triton Attention Kernel", traces what happens to that single kernel source as it gets progressively tuned on H100: from roughly 19.7% of FlashAttention-3's performance at an untuned baseline, to 49% after a single Q-block optimization, to 98.6-105.9% after the full tuning pass. That range on one vendor, before AMD even enters the picture, is the first useful data point: Triton's portability was never a claim that a kernel runs at peak speed unmodified. It's a claim that the same source compiles and executes correctly everywhere, and that the tuning knobs needed to get from correct to fast exist on both backends, even if they aren't the same knobs.

The paper's authors put the actual thesis in one sentence: "Portable, efficient cross-platform LLM inference is indeed possible." The rest of this post is about what "possible" costs in practice, not whether it's true.

If you haven't written a Triton kernel before, our OpenAI Triton kernel development guide covers the block-pointer API and autotuner mechanics this post assumes; this piece picks up from a working kernel and asks what changes when you point the same source at a different vendor's backend.

What Actually Ported Cleanly Without Touching a Line

The parts of the kernel that moved with zero edits are the parts Triton was built to abstract: tl.load, tl.dot, tl.store, block pointer arithmetic via tl.make_block_ptr, and the Python-level kernel signature itself. None of that changed between the CUDA compile and the ROCm compile. Two tuning parameters also carried over as shared vocabulary between vendors, num_warps and num_stages, meaning the concept of pipeline depth and warp count exists on both platforms even though their optimal values differ per hardware.

That's a genuinely large surface staying untouched. A team maintaining a custom attention variant, a fused activation, or a memory-bound elementwise kernel in Triton does not maintain two codebases to support both an NVIDIA and an AMD fleet. That's the actual value of the abstraction, and it's the reason the attention backend reached that 100.7% FlashAttention-3 figure on H100 using code that was never written with H100 as its exclusive target.

What Needed AMD-Specific Tuning (Block Sizes, waves_per_eu, Launch Overhead)

Everything downstream of "does it run" needed a separate pass. Three specific gaps showed up in the research, and each one is a place the identical source produces different optimal configurations per vendor rather than one configuration that works everywhere.

Block sizes diverge by vendor. The IBM Research paper found AMD consistently performs best with a smaller BLOCK_M (16) than NVIDIA, and that NVIDIA benefits from a larger BLOCK_N (64) at long sequence lengths where AMD does better at 32. Autotuning across both vendors with one shared search grid would have missed each platform's actual optimum; the tuning had to run its own sweep per backend.

The occupancy knobs aren't the same knob. num_warps and num_stages are shared vocabulary, but each vendor also exposes something the other doesn't. NVIDIA has warp specialization on Hopper and Blackwell, letting different warps within a thread block run different roles in the pipeline. AMD has waves_per_eu, which controls how many wavefronts can be resident on an execution unit at once by trading off against VGPR (vector general-purpose register) usage per thread. Getting AMD to its best configuration meant tuning a parameter that has no direct NVIDIA analog, which is exactly the kind of vendor-specific knowledge "write once" doesn't make disappear, it just moves it from kernel-source work to autotuning-config work. For the general mechanics of why occupancy and register pressure trade off against each other in the first place, see our CUDA occupancy calculator explainer; the underlying tradeoff is architecture-agnostic even though the specific knob AMD exposes for it isn't.

Launch overhead lands harder on AMD at short sequences. Per-kernel launch overhead of 100-300 microseconds is small relative to a long, compute-heavy kernel, but proportionally large next to a short attention call, and the research found that overhead hits MI300 harder than H100 for short sequences. The fix on each side wasn't symmetric either: enabling full HIP graphs cut MI300 latency by roughly 2x, while CUDA graphs delivered only about a 6% improvement for the same kernel on H100. NVIDIA's launch path was already closer to its floor; AMD's had more overhead sitting on the table.

None of this required touching the kernel's math. It required a second autotuning campaign, run with AMD-specific search parameters, and a graph-capture strategy that mattered far more on one vendor than the other. If you're profiling that gap yourself, Nsight Compute on the CUDA side and its ROCm equivalent is how you'd actually measure where the launch overhead and occupancy numbers land on your own kernel and shapes, rather than trusting a paper's configuration to match yours exactly.

The Performance Gap, Measured: Tokens/Sec on MI300X vs H100

On H100, the portable Triton attention backend reached 100.7% of FlashAttention-3's performance for long decode requests (Llama 3.1 8B, batch size 1, 500-token input), per vLLM's own benchmark. That's Triton essentially matching a hand-optimized, vendor-specific kernel on NVIDIA's own turf, using code that also runs on AMD.

The AMD side of the story doesn't stop at the portable Triton kernel, and that's worth being direct about, because it changes what "the Triton number" actually measures on AMD. vLLM's production ROCm attention path layers AMD-specific work on top of the portable backend rather than shipping the Triton kernel alone: a preshuffled KV-cache layout designed by AMD's AITER team gives a 15-20% decode throughput improvement, and the decode path itself uses assembly-level kernels hand-tuned specifically for CDNA, not the Triton-compiled path. The vLLM/AMD team frames the shift plainly: "For a long time, enabling AMD support meant 'porting', i.e. just making code run. That era is over." On MHA models like Qwen3-235B, that tuned ROCm attention path delivers 1.2-4.4x higher throughput than the legacy, less-tuned ROCm backend, consistent across the MI300X, MI325X, and MI355X generations.

Put those two numbers next to each other and the honest read is this: the portable Triton kernel is what gets you from zero to a working, reasonably fast AMD backend with no separate codebase. Getting from there to production-grade AMD throughput, the 1.2-4.4x jump, required AITER's preshuffled KV-cache layout and hand-assembled decode kernels sitting on top of the portable path, not the Triton source alone.

There's a third data point that completes the honest picture, and it comes from outside vLLM entirely. AMD's own TileLang DSL, a newer tile-level language built natively for CDNA, measured its own fused attention kernel on MI300X at 0.36ms against Triton's 0.55ms for the identical test configuration, a 1.53x gap. The HipKittens paper from Stanford's Hazy Research lab explains part of why: Triton's compiler "struggles with register lifetime tracking and lowering memory accesses to AMD CDNA's most performant intrinsics," and its authors put the underlying constraint bluntly: "peak performance AMD kernels are written in raw assembly." Our HipKittens kernel performance coverage goes deeper on what a tile-based, assembly-competitive framework looks like when it's built for AMD from the ground up instead of ported to it. Triton's AMD backend is the most portable path on that hardware. It is demonstrably not the fastest one available, and a team chasing the absolute ceiling on MI300X has reasons to look past it.

MetricH100 (Triton, CUDA backend)MI300X (Triton, ROCm backend)
Vs. vendor-specific reference kernel100.7% of FlashAttention-3 (long decode)Triton alone trails TileLang by 1.53x (0.55ms vs 0.36ms, fused attention)
What closes the gapFull autotuning pass, 98.6-105.9% of FA3 after tuningAITER's hand-assembled decode kernels + preshuffled KV-cache layout (1.2-4.4x over legacy ROCm backend on Qwen3-235B)
Launch overhead fixCUDA graphs, ~6% latency improvementHIP graphs, ~2x latency improvement

Our earlier kernel-level MI355X vs H200 attention benchmark ran the same exercise, holding a single attention op constant across vendors, on the newer MI355X/H200 pair; the pattern there matches what shows up here for MI300X/H100: system-level percentages and single-kernel comparisons tell different stories, and only one of them tells you what your own workload will actually see.

Cost Per Token: MI300X vs H100 at Live Spheron Rates

The performance story only matters once it's converted into a rental decision, and this is the part where the usual assumption about AMD breaks. As of 19 Sep 2026, Spheron rents H100 SXM5 at $2.98/hr on-demand ($2.10/hr spot) and MI300X at $3.59/hr on-demand, with no spot tier currently listed for MI300X. MI300X is the more expensive hourly rate on this marketplace right now, not the cheaper one, so a Triton-kernel workload has to earn that premium through something other than price.

The place MI300X can still earn it is memory, not raw kernel throughput. MI300X ships 192GB of HBM3 per GPU against H100 SXM5's 80GB, which is a separate axis from anything this post measured: it's the difference between fitting a 70B-parameter model's full FP16 weights on one card versus needing two H100s in tensor parallel. Our AMD MI300X vs NVIDIA H100 memory and cost breakdown works through that tradeoff in detail, including where H100 wins back the low-batch and training cases despite the memory gap. If your Triton kernel work is decode-heavy on a large model that would otherwise need multi-GPU sharding on H100, the memory case can outweigh a per-hour premium that a pure kernel benchmark doesn't capture. If your workload is a custom attention or GEMM kernel running on a model that already fits comfortably on one H100, this post's numbers say the tuning tax and the assembly-level ceiling both currently favor staying on NVIDIA.

Pricing fluctuates based on GPU availability. Spheron rates above are live as of 19 Sep 2026; other providers reflect their most recent published rates and may have changed. Check current GPU pricing → for live rates.

Verdict: Do Write Once, Run Anywhere GPU Kernels Justify Renting AMD for Custom-Kernel Work?

Triton's write-once promise holds up exactly as far as vLLM's own framing suggests: the same kernel source genuinely compiles and runs correctly on both CUDA and ROCm, with no forked codebase, and on H100 it reaches near-parity with a hand-tuned vendor kernel after autotuning. That's not a marginal result. It means a team building custom attention or fusion kernels in Triton is not choosing between NVIDIA-only and AMD-only from the start.

What it doesn't mean is that renting MI300X gets you NVIDIA-equivalent throughput for free. The same source needs its own autotuning campaign on AMD (different block sizes, a different occupancy knob in waves_per_eu, a bigger payoff from HIP graphs), and even after that pass, the hardest kernels still cede ground to hand-tuned assembly and to newer AMD-native DSLs like TileLang. vLLM's own production ROCm path proves the point by not stopping at Triton: it adds AITER's preshuffled KV-cache layout and assembly-level decode kernels on top, because the portable backend alone wasn't the fastest option available.

For a team deciding where to develop and test that tuning pass, the practical case for testing on Spheron isn't that MI300X is cheap right now, it currently isn't against H100 on this marketplace, it's that both GPUs sit in the same catalog, billed per minute with no long-term contract. You can rent an H100 instance to establish your CUDA-backend baseline and an MI300X instance to run the identical Triton source against ROCm, for a few hours each, without committing to either platform before you've measured your own kernel on your own shapes. Provisioning steps for either GPU are in Spheron's docs. What Spheron's catalog doesn't cover is MI355X, where several of the newest AMD kernel gains (AITER's HipKittens integration, CDNA4-specific tuning) are concentrated, or a spot tier for MI300X for teams wanting cheap interruptible AMD capacity, so a workload specifically targeting those needs a different provider for that piece.

Testing whether "write once, run anywhere" holds for your own Triton kernel means running it on both backends, not trusting a published benchmark to match your shapes. Both GPUs in this comparison are in Spheron's catalog, billed per minute.

Rent MI300X or H100 on Spheron →

FAQ / 04

Frequently Asked Questions

Yes, at the compile level. vLLM's Triton attention backend team states plainly that the same Triton kernel source code was used on both platforms in their March 2026 benchmark: one Python file, compiled by Triton's own backend for CUDA on H100 and for ROCm on MI300-class GPUs. What differs is not the source, it's the tuning pass each backend needs to actually reach peak throughput, covered in the block-size and waves_per_eu sections below.

The kernel source stays the same, but the autotuning grid does not transfer. Research on Triton's attention kernel found AMD consistently performs best with a smaller BLOCK_M (16) than NVIDIA, and NVIDIA benefits from a larger BLOCK_N (64) at long sequence lengths versus AMD's 32. NVIDIA also exposes warp specialization on Hopper and Blackwell, while AMD exposes waves_per_eu, a knob that trades VGPR usage for how many wavefronts fit per execution unit. Neither knob has a direct equivalent on the other vendor, so the same autotune sweep has to be rerun with vendor-specific search spaces.

Not on the hardest kernels. The HipKittens paper from Stanford's Hazy Research lab states that peak performance AMD kernels are written in raw assembly, and identifies register lifetime tracking and lowering to CDNA's fastest intrinsics as specific weak points in Triton's AMD compiler path. AMD's own TileLang DSL measured a fused attention kernel on MI300X at 0.36ms against Triton's 0.55ms for the same test, a 1.53x gap, which shows Triton's AMD backend is the most portable option on that hardware, not necessarily the fastest one available.

Not on Spheron today. MI300X rents at $3.59/hr on-demand as of 19 Sep 2026, against $2.98/hr on-demand for H100 SXM5, and Spheron does not currently list a spot tier for MI300X the way it does for H100 at $2.10/hr. The usual assumption that AMD is the cheap option does not hold on this marketplace right now, so the case for MI300X has to come from memory capacity or a specific kernel win, not a lower hourly rate.

Try It Yourself

Try It on Real GPUs

The GPUs behind these guides are the ones you can rent here: H100s, H200s, B200s, and more, billed per minute after a 20-minute minimum runtime, with no contracts. Pick one and you are live in under two minutes.

Deploy Time
< 2 min
Uptime SLA
99.9%
GPU Models
10+
Billing
Per-Min