Runtime

TensorRT-LLM: compile everything

Eager PyTorch trades flexibility for speed. TensorRT-LLM takes your model, compiles it into a fused CUDA graph, and squeezes out every last microsecond. Here is what that compilation actually does and why it matters.

When I first tried TensorRT-LLM, the build step took longer than training a small LoRA. I sat there wondering: why does inference need a compiler at all? PyTorch runs models just fine. The answer became obvious once I profiled the difference: a compiled engine on an H100 was pulling 30 to 40 percent more tokens per second than the same model in eager mode, at half the latency. Compilation is not a nice-to-have. It is where the last layer of performance lives.

What TensorRT-LLM actually is

TensorRT-LLM is NVIDIA's inference runtime specifically designed for large language models. It sits on top of the TensorRT compiler, the same one used for years in computer vision and speech, but wraps it with LLM-specific features: in-flight batching, paged KV caches, tensor parallelism, and quantization-aware kernels.

The core idea: take a model expressed in Python, convert it into a TensorRT engine, and execute that engine with a C++ runtime. The engine is a binary blob of fused CUDA kernels, custom memory layouts, and pre-computed execution plans. No Python overhead. No dynamic dispatch. Just raw kernel launches.

The build pipeline

The workflow has three stages:

A typical build command looks like this:

# Convert a Llama checkpoint to TRT-LLM format
python convert_checkpoint.py \
  --model_dir ./llama-3-8b \
  --output_dir ./tllm_checkpoint \
  --dtype float16

# Build the engine
trtllm-build \
  --checkpoint_dir ./tllm_checkpoint \
  --output_dir ./engine_dir \
  --gemm_plugin float16 \
  --max_batch_size 64 \
  --max_input_len 2048 \
  --max_seq_len 4096 \
  --paged_kv_cache enable

The --gemm_plugin flag is critical: it enables custom GEMM kernels instead of cuBLAS defaults, often delivering meaningful speedups for specific shapes. The --max_* flags are not suggestions; they are hard limits baked into the engine. If a request exceeds them, it fails. This is the trade-off: you give up dynamic shapes for deterministic performance.

What the compiler does under the hood

TensorRT's compiler performs several optimizations that are impossible in eager execution:

Key insight

The reason compilation helps so much for LLM inference is that the workload is predictable. The same operations run in the same order for every token. There is no control flow divergence. This is the ideal case for ahead-of-time optimization.

The LLM-specific features

Raw TensorRT could compile a transformer, but it would not know how to serve one efficiently. TensorRT-LLM adds the serving layer:

Where it hurts

Compilation is not free. The downsides are real:

TensorRT-LLM vs. vLLM and SGLang

The mental model I use: vLLM and SGLang are serving frameworks that happen to optimize execution. TensorRT-LLM is a compiler that happens to include a serving runtime. They solve the problem from opposite ends.

In practice, TensorRT-LLM engines often deliver the highest single-stream throughput and lowest per-token latency, especially on NVIDIA hardware with FP8 quantization. But vLLM and SGLang offer faster iteration, broader model support, and easier deployment. Many production setups actually use TensorRT-LLM engines as a backend within a serving framework, getting the best of both worlds.

If you need the absolute fastest inference on NVIDIA GPUs and you can afford the build step, compile. If you need flexibility and fast iteration, stay eager. If you are at scale, you will probably end up doing both.

Tomorrow: NVIDIA Dynamo, the orchestration layer that takes disaggregated serving to the next level by splitting prefill and decode across separate GPU pools.