Two teams serve the same model on the same GPU. One pays roughly twice as much per request as the other, and neither has touched the weights. The difference is whether the serving path was compiled. That gap is where most cost-per-request conversations quietly go wrong. Teams tracking cloud spend see the invoice line item — instance-hours on an A100 or H100 — and treat throughput as a fixed property of the model. It isn’t. Between the trained model graph and the hardware that runs it sits a compilation stage, and that stage decides how many requests you get out of an hour of GPU time. A machine learning compiler takes the trained model graph and lowers it to hardware-specific kernels: fusing operators, selecting memory layouts, and pruning dead compute before a single request is served. The same weights, producing the same outputs, run at lower latency and higher batch density on exactly the same silicon. What a machine learning compiler actually does to a trained model When you train a model in PyTorch or TensorFlow, you get an eager graph — a sequence of framework operations dispatched one at a time. Each operation reads its inputs from GPU memory, computes, and writes results back. That dispatch model is convenient for research and debugging, but it leaves performance on the table in three specific ways, and a compiler addresses all three. Operator fusion. A transformer layer isn’t one operation; it’s dozens — matrix multiplies, additions, activations, normalizations. In the eager graph each of these is a separate kernel launch, and each launch round-trips intermediate tensors through high-bandwidth memory (HBM). Fusion collapses adjacent operations into a single kernel, so an intermediate result stays in registers or shared memory instead of being written out and read back. Attention is the canonical case: FlashAttention exists precisely because a fused attention kernel avoids materializing the full attention matrix in HBM. Compilers apply the same principle across the whole graph. Layout and precision selection. The physical arrangement of a tensor in memory changes how efficiently a kernel can read it. A compiler picks layouts that match what the target hardware’s tensor cores want, and it can lower operations to lower-precision formats (FP16, BF16, INT8) where the numerics allow. This is a lever, not a free win — precision choices interact with accuracy, which is a decision you make deliberately. Dead-compute pruning and graph capture. The compiler removes operations whose outputs never reach the model’s result, and it captures the full computation as a static graph so the runtime stops paying per-operation Python dispatch overhead on every request. For latency-bound decode steps in an autoregressive model, that overhead is not marginal. The result is a serving artifact that produces the same outputs as the eager model — token for token, within the precision envelope you chose — while consuming fewer GPU-seconds per request. That last property is the whole point, and it’s why compilation is worth understanding before you reach for more expensive levers like adding hardware. Which machine learning compilers matter for production inference? There is no single compiler; there is a stack of tools that overlap and interoperate, each with a different entry point. Choosing among them is less about which is “fastest” and more about where your model already lives and how much control you need. Compiler / runtime Entry point Best fit Trade-off torch.compile PyTorch eager code You want gains with minimal code change Lowest ceiling of the group; captures graph breaks imperfectly on dynamic models TensorRT ONNX or framework export NVIDIA GPUs, aggressive latency targets NVIDIA-only; build step and version pinning add operational weight XLA JAX / TensorFlow (and PyTorch via torch-xla) TPU targets, large static graphs Shines on static shapes; dynamic sequence lengths need care TVM Model from many frameworks Portability across CPU, GPU, edge, custom accelerators Highest engineering effort; autotuning is time-consuming ONNX Runtime ONNX graph Framework-agnostic serving with pluggable execution providers Peak performance often trails a hand-tuned TensorRT engine The practical reading of this table: torch.compile is where most teams should start, because the cost of trying it is a one-line wrapper and a warm-up compile. TensorRT is where NVIDIA-bound production serving usually ends up when latency budgets are tight. TVM and XLA earn their keep when portability or non-standard hardware is a hard requirement. In our experience these are not mutually exclusive — a common production pattern is exporting to ONNX and running it under TensorRT as an execution provider, so the framework and the compiler are decoupled. How compilation lowers cost-per-request without changing outputs Cost-per-request is arithmetic: it’s the hourly price of the hardware divided by the number of requests that hardware completes in an hour. The vendor sets the numerator. Compilation moves the denominator. Fused kernels and better layouts reduce the GPU-time each request consumes, which raises the achievable batch size at a fixed latency target and lifts tokens-per-second on the serving path. More requests per hour, same invoice — cost-per-request falls. Crucially, this happens without a model change, so the outputs your product depends on stay identical (within the precision envelope you explicitly chose). That property is what makes compilation a low-risk optimization to reach for first: it changes the economics without changing the product. Here is a worked example with explicit assumptions, framed illustratively rather than as a benchmark you should expect to reproduce: Illustrative, not benchmarked. Suppose a serving path runs at a p95 latency budget of 200 ms and, in eager mode, saturates a single GPU at batch size 8, completing on the order of 40 requests per second. If compilation fuses the hot kernels and cuts per-request GPU-time enough to sustain batch size 16 within the same 200 ms budget, throughput roughly doubles to ~80 requests per second. The GPU costs the same per hour, so cost-per-request roughly halves. The actual uplift depends entirely on the model, the sequence lengths, and how memory-bound the workload already is — treat this shape as the mechanism, not a promised number. The evidence class here matters. Any real uplift figure is a benchmark-class claim tied to a specific model on specific hardware; the range varies widely because a compute-bound workload has less fusion headroom than a memory-bound one. That is exactly why you measure the deployed path rather than trusting a headline. Compilation is one stage in a broader effort — our machine learning model optimization work treats it alongside quantization, batching strategy, and serving-runtime choices, because the gains compound and sometimes conflict. When is compilation worth the engineering effort? Not always, and not first in every case. A compiler adds a build step, a warm-up cost, version pinning against a CUDA and driver stack, and a class of debugging problem — graph breaks, unsupported operators, shape-specialization surprises — that the eager graph never had. Use this rubric to decide whether the effort earns its keep. Reach for compilation when: The serving path is under sustained load and cost-per-request is a metric someone actually tracks. Compilation pays off on volume; a prototype serving ten requests a day should not bother. Your latency budget is tight enough that batch density matters. Fusion buys headroom you can spend on larger batches. The model graph is reasonably static — fixed architecture, bounded sequence lengths — so the compiler’s shape specialization holds. Leave the eager graph in place when: Traffic is low or bursty and GPU-hours are already a rounding error. The model changes frequently, so every change forces a recompile and re-validation cycle that eats the savings. You have not yet profiled the serving path and don’t know where the time actually goes. Compiling blind can even regress performance if the graph is full of dynamic control flow the compiler handles poorly. That last point deserves weight. Compilation gains are measured against a baseline, and if you don’t have one you can’t tell whether the compiler helped, did nothing, or hurt. Establishing that baseline is a profiling exercise — the same GPU profiling discipline that tells you whether a workload is compute-bound or memory-bound in the first place. A memory-bound decode loop has enormous fusion headroom; a compute-bound prefill on tensor cores that are already near peak has almost none. Where the compiler stage fits in a cost-per-request workflow Think of the inference stack as a sequence of levers, each with a different cost and blast radius. Profiling comes first — it tells you where GPU-time goes and whether the workload is memory- or compute-bound. Compilation comes next, because it’s low-risk and doesn’t touch model behaviour. Only after those do the heavier levers make sense: quantization (which does touch numerics), speculative decoding, prefill/decode disaggregation, and finally hardware changes. This ordering is deliberate. Each lever gets riskier and more invasive as you descend it, so you exhaust the cheap, output-preserving options before you spend engineering time on the ones that change the model or the cluster. Reasoning about the full compute footprint of a feature — the arithmetic behind cost-per-request for a production AI feature — is what makes the ordering concrete for a specific workload. And when you want a structured pass over the deployed serving path, our [inference cost-cut engagement](Inference Cost-Cut Pack) profiles exactly this chain and identifies where compilation, batching, and precision choices are leaving money on the table. For teams running AI as a product surface, the same reasoning underpins how we think about AI infrastructure economics for SaaS. FAQ How does machine learning compiler actually work? A machine learning compiler takes the trained model graph and lowers it to hardware-specific kernels — fusing operators, choosing memory layouts, and pruning dead compute — before any request is served. In practice this means the same weights run faster on the same GPU, so you complete more requests per hour without changing the model or the vendor invoice. What does a machine learning compiler actually do to a trained model before serving? It fuses adjacent operations into single kernels so intermediate tensors stay in fast on-chip memory instead of round-tripping through HBM, selects layouts and precisions that match the target hardware’s tensor cores, and captures the computation as a static graph to remove per-operation dispatch overhead. The outputs remain the same, token for token, within the precision envelope you deliberately chose. Which machine learning compilers matter for production inference (XLA, TensorRT, TVM, ONNX Runtime, torch.compile)? Each has a different entry point: torch.compile for minimal-change PyTorch gains, TensorRT for aggressive latency on NVIDIA GPUs, XLA for TPU and large static graphs, TVM for portability across diverse hardware, and ONNX Runtime for framework-agnostic serving. They interoperate — a common pattern is exporting to ONNX and running under TensorRT — so the choice depends on where your model lives and how much control you need. How does model compilation lower cost-per-request without changing the model’s outputs? Cost-per-request is hardware cost divided by requests completed. Compilation cuts the GPU-time each request consumes, raising achievable batch size and tokens-per-second on the same hardware, so more requests fit into an hour at the same hourly price. Because the weights and outputs are unchanged, the economics improve while the product stays identical. What throughput and latency gains can we realistically expect from compiling a serving path? There is no universal number — it’s a benchmark-class result tied to a specific model and GPU. Memory-bound workloads have large fusion headroom and can see substantial uplift, while a compute-bound path already near tensor-core peak may see little. The only reliable answer comes from measuring cost-per-request and p95 latency on your own deployed path before and after. When is compilation worth the engineering effort versus leaving the eager graph in place? Compile when the serving path is under sustained load, cost-per-request is tracked, the latency budget rewards higher batch density, and the model graph is reasonably static. Leave the eager graph in place when traffic is low or bursty, the model changes frequently enough to force constant recompiles, or you haven’t yet profiled the path to know where time goes. How does the compiler stage fit into an inference-cost optimisation workflow? It sits after profiling and before the heavier levers. Profiling establishes the baseline, compilation is the low-risk output-preserving win, and only then do quantization, speculative decoding, disaggregation, and hardware changes make sense. Each step down the sequence is riskier and more invasive, so you exhaust the cheap options first. Compilation is the rare optimisation that changes what a request costs while leaving what a request returns untouched. The open question on any given serving path isn’t whether a compiler helps in principle — it’s whether your graph is memory-bound enough to have headroom, and the only honest way to answer that is to profile the baseline, compile, and measure the same cost-per-request number on both sides. That before/after delta, not a headline uplift figure, is what SVC-COSTCUT’s inference-cost analysis is built to surface.