{"slug": "safe-kernels-are-fast-kernels-tile-rs-next-to-mojo-1-0", "title": "Safe kernels are fast kernels: tile-rs next to Mojo 1.0", "summary": "On 18 August 2026, Modular open-sourced the Mojo compiler and toolchain under Apache 2, enabling a head-to-head comparison with tile-rs, a Rust dialect for accelerator kernels that enforces type, concurrency, and resource safety. On an Apple M1 Ultra across 16 kernels, tile-rs-generated Metal kernels were faster than Mojo on 15 of 16 kernels, with a median gap of 4.7%, and tied on the last, showing that safety does not cost speed.", "body_md": "# Safe kernels are fast kernels: tile-rs next to Mojo 1.0\n\nTL;DR— Mojo's compiler and toolchain went open source on 18 August 2026, which for the first time lets anyone put it side by side with something else on the same silicon. We did that with tile-rs, a Rust project for writing accelerator kernels that are type-, concurrency- and resource-safe by construction. On an Apple M1 Ultra, across sixteen kernels — five primitives and eleven from the decode path of DeepSeek-R1-Distill-Qwen-1.5B — the tile-rs-generated Metal kernel is faster than the Mojo one on15 of 16and ties on the last. Not by a lot on most of them: the median gap is 4.7%. The interesting claim isn't the margin, it's the direction —you do not have to spend safety to get speed.\n\n## Why this comparison is possible now\n\nChris Lattner has shipped the compiler infrastructure most of us build on: LLVM, Clang, Swift, MLIR. In June 2026 Qualcomm [agreed to acquire Modular](https://www.cnbc.com/2026/06/24/qualcomm-ai-chip-modular-software.html) — the company behind Mojo — for about **$3.9 billion in stock**; the deal [closed on 29 July](https://www.qualcomm.com/news/releases/2026/07/qualcomm-completes-acquisition-of-modular), with Lattner becoming EVP of Advanced AI Software and Platforms. On **11 August** Modular [shipped Mojo 1.0](https://www.modular.com/blog/modular-26-5-mojo-1-0-is-here) with stability guarantees, and on **18 August** they [open-sourced the compiler and toolchain](https://www.phoronix.com/news/Modular-Mojo-Open-Source) under Apache 2.\n\nThat last step is what makes this post possible. Before it, Mojo's numbers were Modular's to publish. Now anyone can build it, run it, and check.\n\ntile-rs is a much smaller thing, open-sourced in late June 2026. It is a Rust dialect for accelerator kernels whose defining property is that the compiler refuses to emit a kernel that could race, overflow a buffer, or read a tile it does not own.\n\nBoth projects target Apple GPUs. That overlap is the whole experiment.\n\n## The head-to-head\n\nSixteen kernels, Apple M1 Ultra, timed on the GPU's own clock — `MTLCommandBuffer.gpuStartTime`\n\n/`gpuEndTime`\n\n, so the host's submit-and-wait sits outside the measurement. Median of 5 blocks of 40 launches, minimum within each block. Mojo built with optimisation on.\n\n| kernel | tile-rs → Metal (µs) | Mojo (µs) | tile-rs is |\n|---|---|---|---|\n`vec_add` | 44.1 | 45.4 | 1.03× faster |\n`vec_mul` | 44.1 | 45.4 | 1.03× faster |\n`vec_sub` | 44.1 | 45.3 | 1.03× faster |\n`vec_exp` | 34.2 | 35.5 | 1.04× faster |\n`residual_add` | 44.1 | 45.4 | 1.03× faster |\n`rms_norm` | 49.3 | 64.6 | 1.31× faster |\n`rope` | 29.9 | 33.1 | 1.10× faster |\n`argmax` | 274.7 | 281.5 | 1.02× faster |\n`matmul` | 244.6 | 272.0 | 1.11× faster |\n`q_proj` | 30.5 | 34.2 | 1.12× faster |\n`k_proj` | 30.2 | 32.2 | 1.07× faster |\n`v_proj` | 30.5 | 32.2 | 1.05× faster |\n`o_proj` | 30.6 | 33.6 | 1.10× faster |\n`down_proj` | 45.4 | 45.9 | tie (1.01×) |\n`gate_up_silu` | 147.6 | 152.5 | 1.03× faster |\n`attn_gqa` | 8616.9 | 9801.1 | 1.14× faster |\n\n**Read this honestly.** The corpus total is 9.74 ms against 11.00 ms — 1.13× — but `attn_gqa`\n\nis 88% of that total, so the corpus number is very nearly a single kernel's result wearing a suit. The per-kernel view is the fair one, and there the story is *consistent small wins*: 15 of 16, median 4.7%, one tie, nothing lost.\n\nA 4.7% median is not a rout. What it rules out is the thing people assume must be true — that memory safety has to be paid for in throughput.\n\n## How? Three claims\n\n**One: the kernels are safe, in three specific senses.**\n\n*Type safety.*No raw pointers, and nothing that needs a runtime check to stay true.*Concurrency safety.*No data races, with no synchronisation the programmer has to remember to add.*Resource safety.*A kernel cannot allocate more than the buffer it was given. This one is not theoretical — see the section on the four Ascend backends below, where three of four got a hardware capacity limit wrong, each in a different way.\n\n**Two: hardware affinity is not optional, and not uniform.**\n\nGPUs, TPUs and NPUs have genuinely different architectures, and no single emitted implementation suits all of them. What they *do* share is enough structure to be captured by one type system and one set of invariants. tile-rs generates a different implementation per target, keeping the operator's meaning while satisfying that target's memory, concurrency, synchronisation and capacity constraints.\n\n**Three: the two directions compose.**\n\n*Lowering* goes from types and invariants to a hardware-affine implementation; it must preserve the safety properties while introducing hardware detail. *Lifting* goes the other way — from an optimised, target-specific kernel back to types and invariants — and it must re-establish safety. The payoff is what happens when you lift and then lower again to a *different* target: an optimisation discovered on one backend transfers to the others.\n\nIf you know *Journey to the West*: tile-rs is the Monkey King. Safety is the golden headband, hardware affinity is the staff that grows to any length, and the lift/lower cycle is his seventy-two transformations. The headband is usually read as a punishment, but it is the thing that makes the rest of him safe to let loose — and wearing it he still goes everywhere, heaven and the dragon king's palace included.\n\nIn practice this has been a magpie exercise. tile-rs borrows from NVIDIA's cuTile, Huawei's PTO and Ascend C, and Mojo, then lifts and lowers repeatedly. Adding safety to those ideas has, repeatedly, also made them faster.\n\n## Two objections worth answering\n\n### \"Rust only draws level with C++, and it cheats with `unsafe`\n\n\"\n\nThe old complaint: Rust and C++ share an LLVM backend, so Rust merely ties, and C++ has decades of high-performance template libraries. And Rust has `unsafe`\n\n, so the optimisations sneak in through a back door anyway — which lets a C++ advocate say *\"I'm unsafe, but so are you, and I'm better at poking the hardware.\"*\n\nLook at the tile-rs kernels. The body a person writes contains no `unsafe`\n\nat all. What remains is confined to a macro-generated prelude that does two things no safe API can do for you: read the hardware block index, and construct the global-memory views from the raw device context. Everything above that line — every operator in both tables below — is safe Rust, and on this hardware it is faster than the alternatives.\n\n### \"Python is AI-native; Rust isn't\"\n\nWhere did that idea come from? When Python became popular, AI in the statistical sense barely existed. And look at what the \"AI-native\" stack is actually made of once you get below the API surface. OpenAI's `tiktoken`\n\n, Hugging Face's `tokenizers`\n\n, `safetensors`\n\nand `candle`\n\n, NVIDIA's cuTile-rs, and `uv`\n\n— the package manager for Python itself — are all Rust. Python serving stacks like vLLM and SGLang are Python and CUDA where the scheduling lives, but the tokenizer they load is somebody's Rust crate.\n\nThat is the actual division of labour: Python is where the *interface* is AI-native, and a systems language is where the throughput is. The question is only which systems language, and whether it hands you a compiler that objects before the chip does.\n\nAt minimum: if a large model is going to generate the code, I would rather have a Rust compiler checking it for hazards before it ships.\n\n## The wider table: five backends, one source\n\nThe Ascend numbers below deserve a precise reading, because it is easy to misread them as \"tile-rs versus Triton\". They are not. **Every column is generated from tile-rs.** The question they answer is *which backend should tile-rs lower to for this kernel*, not *whose language is faster*.\n\n### Lines of code\n\n| kernel | tile-rs | Ascend C | PTO | TileLang | Triton | Metal | Mojo |\n|---|---|---|---|---|---|---|---|\n| all 16, total | 223 | 1276 | 1605 | 498 | 283 | 635 | 606 |\n\ntile-rs is the most concise of the seven, and it is the only one a human writes — the rest are emitted. (PTO's 1605 is inflated by two kernels, `attn_gqa`\n\nat 621 lines and `argmax`\n\nat 365, both of which are fully unrolled.)\n\nSeven of the sixteen kernels, when an AI first generated the equivalent tile-rs operator, **did not compile**. Those compiler errors were real defects, not pedantry; fixing them is what produced the operators measured here.\n\n### Relative performance, Ascend 910B2, DeepSeek-R1-Distill-Qwen-1.5B\n\n| tile-rs (best-of) | Ascend C | PTO | TileLang | Triton | |\n|---|---|---|---|---|---|\n| total-time ratio | 51.08× | 1.62× | 2.28× | 1.42× | 22.33× |\n\n**Every one of these numbers needs its caveats stated, not buried.**\n\n*It is a total-time ratio, not a geometric mean or a median of speedups.* So the expensive kernels dominate. Triton reads 22.33× while being fastest on only 5 of the 16 — two kernels carry the whole figure. TileLang makes the same point from the other side: it is fastest on **8 of 16**, more than any other backend, and has the *largest* total, because its launch path is the leanest on the part while its scans are single-core.\n\n*The tile-rs column is a best-of, and therefore theoretical.* It takes the fastest generated kernel per row against the slowest. It is achievable in principle — each kernel is compiled independently, so a compiler may pick a different backend for each — but if a deployment requires one backend throughout, or fuses only within a backend, that headroom does not materialise.\n\n*Triton and TileLang reach the NPU through their own Ascend C generation.* So those two columns measure Ascend C that was generated from tile-rs-generated Triton or TileLang — a longer path, and worth remembering when comparing them to the direct Ascend C column.\n\n### What the safety argument looks like in practice\n\nThe most concrete evidence for the \"resource safety\" claim came from the four Ascend backends. Each has a 192 KB vector unified buffer to respect. Three of the four got it wrong, each differently, and — this is the part that matters — **each was caught at a different distance from the hardware**:\n\n| backend | how the limit was missed | who caught it |\n|---|---|---|\n| PTO | budget constant set above the hardware's | the assembler |\n| Triton | gated on Triton's representational limit, not the buffer | the compiler |\n| TileLang | no check at all | the device, mid-run |\n| Ascend C | — | it asks the hardware |\n\nA budget that is merely *wrong* gets caught by the next tool down. A budget that is *absent* does not get caught until the chip faults. That ordering is the argument for pushing the constraint into the type system, where it is checked before anything is emitted.\n\n## Credit where it is due\n\nMojo's abstraction level holds up well on safety, and here is the evidence for that from outside the timing tables. Every kernel in this corpus exists in two readings: the shapes as they were first captured, some of them degenerate and ill-formed, and the same kernels after those shapes were fixed. Ascend C, TileLang, Triton and PTO all emit *different code* for the two readings — they were sensitive to a malformation they had no business being sensitive to. The Mojo operator is byte-identical across both. It never had to care.\n\nThat is a real design win, and hats off to the Modular team for it.\n\n## An invitation\n\nMeasuring nine days after a 1.0 open-sourcing is not especially fair to Chris Lattner and his team. Nine days is not long.\n\nSo: consider this a challenge, warmly meant. The kernel corpus and the benchmark entries are published at [pu-rs.org](https://pu-rs.org), and the measurement method is described above in enough detail to be argued with — which is the part that matters. If the next Mojo release takes these numbers back, everyone who runs a model on any of this hardware wins, and that is rather the point of doing it in the open.\n\n*All Ascend figures: Ascend 910B2, DeepSeek-R1-Distill-Qwen-1.5B, CANN 8.5.2. All Apple figures: M1 Ultra, 128 GB. Every kernel in both tables is verified against a host reference before it is timed.*", "url": "https://wpnews.pro/news/safe-kernels-are-fast-kernels-tile-rs-next-to-mojo-1-0", "canonical_source": "https://yijunyu.github.io/tile-rs-vs-mojo.html", "published_at": "2026-08-27 03:58:17+00:00", "updated_at": "2026-08-27 04:19:29.582851+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "developer-tools"], "entities": ["Modular", "Mojo", "tile-rs", "Apple M1 Ultra", "Chris Lattner", "Qualcomm", "DeepSeek-R1-Distill-Qwen-1.5B"], "alternates": {"html": "https://wpnews.pro/news/safe-kernels-are-fast-kernels-tile-rs-next-to-mojo-1-0", "markdown": "https://wpnews.pro/news/safe-kernels-are-fast-kernels-tile-rs-next-to-mojo-1-0.md", "text": "https://wpnews.pro/news/safe-kernels-are-fast-kernels-tile-rs-next-to-mojo-1-0.txt", "jsonld": "https://wpnews.pro/news/safe-kernels-are-fast-kernels-tile-rs-next-to-mojo-1-0.jsonld"}}