Build1 distinct publisher3 min readPublished
Identical code and identical weights diverge 3.7x on decode between a T4G and an L4, because Turing has no bf16 datapath and XLA emulates one in fp32 while the instance keeps returning 200s and green health checks.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The first hypothesis was the obvious one: a bf16 checkpoint meeting a chip with no bf16 datapath, so rewrite the checkpoint. It was converted host-side, the parameter dtypes came back as 541 float16 arrays plus one uint8 and one int8, and conversion still accounted for 54.0% of decode [9]. The 87% figure covers conversion plus an fp32 `gemvx` path [5] while the 54.0% is quoted for conversion alone, so subtracting one from the other only bounds what the rewrite bought: 33 points at most, with 54 still sitting in the compute path [2]. According to the dev.to write-up, the `gemvx` line is the diagnosis. XLA round-trips through fp32 whatever the file on disk says, and the round trip disappears only on a card whose compute dtype matches its storage dtype, which is what the g6 demonstrates [10]. That puts the fix in the process rather than the artifact: the port reads the live compute capability and sets `COMPUTE_DTYPE = float16 if IS_PRE_AMPERE else bfloat16` [11].
How much is recoverable is a separate question. The g5g runs at 26% of its own memory-bandwidth roofline and the g6 at roughly all of its own [6]. Take the reciprocal and the T4G carries about 3.85x of headroom against itself [1]. That is close to the measured 3.7x decode gap between the two chips [4], but the two numbers are different quantities. One compares a card to its own bandwidth ceiling; the other compares two cards. For a dtype-corrected T4G to land where the L4 sits, the two cards' absolute memory bandwidths would have to be comparable, and percentages of each card's own roofline cannot tell you that.
The 3.7x is a claim about one workload: `google/gemma-4-E2B-it` through a hand-written pure-JAX port with no PyTorch, no vLLM and no `torch_xla` [3], at 64 output tokens, concurrency 1, three repeats per cell, median reported [14]. Two conditions have to hold before it transfers. Decode has to be weight-bound rather than context-bound, which is what the sweep shows: decode moves 0.8% across a 50x context range on the g5g and 0.4% on the g6 [16], so the KV cache is not what sets decode speed on either box. And the engine has to be warm, because `max_new_tokens` is a `static_argnames` entry and `(bucket, max_tokens)` is the compiled shape; the first request on the g5g took 18.06 s against 4.50 s warm [18]. Read the end-to-end column instead of the decode gauge and the gap narrows with context, from 3.72x to 3.35x [3], which is prefill scaling linearly in the padded bucket rather than decode degrading [15].
Adoption cost on the older host is not the toolchain. `jax[cuda13]` ships CUDA as wheels including aarch64 builds, there is no build step, no CUDA toolkit and no Rust toolchain are required, and install took 117 s with the cache restore included [21]. The author reports the profile reproducing across a different instance, a different AMI and a restored cache at 1466.0 ms against 1467.1 ms [20], and flags that a 56x figure from an earlier first-serve baseline is TTFT specifically, not the whole-request ratio [19]. Both families ran on spot [1], so the dollar comparison stays an exercise for whoever has the billing console open.
Ranked by verification strength, evidence, and original report placement.
g5g.2xlarge pairs a Graviton2 (aarch64) host with an NVIDIA T4G, Turing, SM 7.5; g6.2xlarge is x86_64 with an NVIDIA L4, Ada, SM 8.9. Both were run on spot.
The serving payload was byte-identical on both instances: build id 51bc52c9e2e9, config ple4 + int8_lm_head, and tpu_jax_weight_bytes reading 6,155,450,950 on each. Only the chip and its host differ.
The workload is google/gemma-4-E2B-it, the dense reference checkpoint, served through a hand-written pure-JAX port with no PyTorch, no vLLM and no torch_xla.
Decode throughput differs by 3.7x between the two instances, for the same code and the same weights.
Profiling with xprof over 20 decode steps with the service stopped shows 87% of decode on the g5g is not math: it is dtype conversion plus an fp32 gemvx path.
The g5g runs at 26% of its own memory-bandwidth roofline; the g6 runs at roughly all of it.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 30, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Fitting 6.155 GB of Gemma 4 weights lands you on AWS's only Arm GPU family1 distinct publisher
build
A Pallas kernel tiled for TPU VMEM splits one Gemma 4 port into two checkpoints1 distinct publisher
build
Four concurrent MPS processes fill the L40S that one ASR request leaves 80% idle1 distinct publisher
invest
H100 rentals are back to $2.35 an hour, and your AI cost model is stale1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
One engineer, one zone, receipts attached
Everything traces to a single dev.to writeup by the person who wrote the JAX port, and for a one-author benchmark it is unusually instrumented: an xprof trace over 20 decode steps, a payload pinned by build id and weight-byte count, and a repeat on a different instance and AMI that landed within a millisecond. What is missing is anyone else's hardware — one g5g and one g6 in us-east-1d, each measured once — and the post's own loose end, Tensor Core utilisation reading 0.0% on both chips with no explanation offered, sits exactly where an outside check would land.
Two spot instances, both since terminated
Adoption here amounts to two spot rigs that were deliberately killed after collection. The trap generalises to every pre-Ampere card still doing cheap inference, but no one else in this reporting says they hit it — no second operator, no vendor note, no bug thread, no production fleet. The only usage on record is the author's own serving port, and the one operational detail with legs beyond it is that jax[cuda13] now ships aarch64 wheels, which is what made the Graviton2 run possible at all.
The headline is smaller than the mechanism
The title sells two AWS SKUs; the finding is that a wrong compute dtype emulates instead of failing anywhere XLA meets a pre-Ampere GPU, and that the wasted work is invisible to every signal you would normally watch. Meanwhile the post talks itself down where a hypier version would not: it separates the end-to-end fall (prefill, linear in the padded bucket) from decode, warns that a cold first request misreports the box fourfold, and refuses to recycle the older 56x number because that one was time-to-first-token. Restraint like that is why the gap tips slightly toward understatement.
Self-promotion, no vendor money in sight
No vendor stands behind this. The comparison flatters neither AWS family, and NVIDIA gets no product win from a post about its own older card silently emulating a format it lacks. What the author does get is a showcase for a hand-written pure-JAX serving port with no PyTorch and no vLLM in it, and the remedy on offer happens to be that port's device-detection line. Mild self-interest, visible on the page rather than hidden in it.
Reproducible in-house, unreplicated outside
Internally the story holds: mechanism, falsification test, profile and roofline all point the same direction, and the float16 checkpoint rewrite that failed to shift conversion is the kind of detail people who are guessing leave out. The ceiling is external. A 3.7x figure no second party has reproduced, drawn from two machines in one availability zone, supports a diagnosis on those boxes rather than a capacity-planning rule — and the arithmetic that turns it into instance counts or a clean split of the overhead is softer than the measurements it rests on.