4

Software

Choose runtimes and kernels with evidence from benchmarks and profiles.

11 min read

Printed pages: 93–116

Star on GitHub

In one breath

Inference software is a ladder of control. Compute Unified Device Architecture (CUDA) kernels determine how work touches NVIDIA hardware; frameworks express tensor programs and serialization; inference engines package optimized kernels, scheduling, batching, caching, and distributed settings; orchestration coordinates many workers. Start at the highest layer that meets the requirement, descend only when measurement shows a missing capability or expensive bottleneck, and verify every change with production-shaped load.

Why it matters

  • Higher abstractions shorten delivery and encode broad optimization experience, but they hide kernel and scheduling choices. Lower layers offer control at the cost of architecture-specific code, compatibility work, and a much larger test surface. A team must know which control it traded away so it does not solve a problem at the wrong layer.
  • A mathematically identical operation can have radically different memory traffic and hardware utilization because of tiling, read-write order, and hardware mapping. Kernel selection and fusion therefore preserve the algorithm while turning its abstract model into a hardware-specific implementation problem.
  • An inference engine saves teams from rebuilding continuous batching, cache management, quantization paths, speculation, and parallel execution. Its fit still depends on model architecture, graphics processing unit (GPU) generation, traffic shape, and the control the team needs; no engine is universally fastest.
  • A benchmark says whether the service improved; a profile says where the time and memory went. Without a profile when causal detail is needed, optimization becomes a sequence of plausible stories. Without an end-to-end benchmark, a local speedup may never become a user-visible improvement.

Mental model

Treat each layer as a contract. Hardware exposes instructions and memory; CUDA launches concrete kernels; PyTorch or another framework describes graphs and tensors; files preserve weights or graphs; an engine chooses implementations and schedules requests; an orchestrator routes work among replicas. Performance work asks which contract prevents the next improvement, then changes the narrowest layer that can solve it without taking ownership of everything below.

Inference software stack - January 2026 edition snapshot

Hardware supports CUDA kernels, PyTorch and model formats build on CUDA, inference engines assemble optimized serving, and Dynamo coordinates engines across a distributed deployment.

  1. Accelerator hardwareCompute, memory, and interconnect
  2. CUDA and kernelsExplicit GPU execution and memory control
  3. PyTorch and model formatsGraphs, tensors, compilation, and serialization
  4. Inference enginesScheduling, batching, kernels, and optimization flags
  5. Distributed orchestratorRouting, cache reuse, and worker coordination
  • Accelerator hardwareCUDA and kernels: Exposes device
  • CUDA and kernelsPyTorch and model formats: Powers operations
  • PyTorch and model formatsInference engines: Supplies models and graphs
  • Inference enginesDistributed orchestrator: Serves as backend

A newly released model exposes the stack's dependencies. A reference library may download its configuration and weights and produce correct output before a production engine understands a new attention form. A nightly engine may support the graph while the critical optimized kernel still targets an older GPU; the driver or CUDA version may also conflict with other container packages. Loading is not full support. Trace the chain from file format and model definition through framework operations, kernels, engine, driver, and hardware. Pin the first combination that is correct, stable under load, and reproducible, then optimize from it. If day-zero support requires prerelease packages, keep a rollback path and make compatibility plus quality tests release gates.

Engine choice begins by rejecting candidates that miss hard constraints: model architecture, modality, accelerator and precision kernels, license, or required paths for continuous batching, quantization, caching, speculation, parallelism, and disaggregation. Next compare official containers, configuration surface, logging and monitoring, upgrade cadence, debugging tools, and team capacity to own the complexity. Only viable candidates deserve a head-to-head benchmark with the same model revision, traffic distribution, and quality suite. A broad engine may win time-to-service; a deeply specialized engine may trade more engineering for capacity. Convert throughput at the latency objective, GPU count, maintenance, and failure risk into service cost instead of declaring a winner from an isolated peak chart.

A useful experiment forms a closed loop. Freeze the environment, controllable randomness, and baseline; replay production-like sequence lengths, arrival jitter, concurrency, temperature, and prefix repetition. Inspect end-to-end percentile latency, throughput, errors, and quality. Profile only when the result needs explanation, attributing time to the central processing unit (CPU), GPU, memory copies, kernels, or interconnect. Change one kernel or setting, repeat enough runs to exceed ordinary variance, and reject quality or memory-safety regressions. Then combine intended optimizations because individually useful settings may compete for resources. Finally shadow production to verify that the synthetic conclusion survives real traffic. This evidence supports retuning, retaining the old version, or rolling back after dependencies change.

Fusion illustrates why abstraction boundaries matter. Two individually fast kernels can be slow together when they materialize a large tensor, write it to video random-access memory (VRAM), and immediately read it back. A compiler can fuse a regular graph automatically; an engine may choose a fused plugin by shape and GPU; a rare architecture may require a framework contributor to handwrite a path from profiler evidence. The lower the change, the broader its compatibility matrix: shape, precision, alignment, GPU generation, invalid input, and future versions all need tests. Keep a correct unfused fallback for unsupported combinations, then verify realistic scheduling, batch, and concurrent requests. The fused path earns maintenance only when less local traffic becomes lower user latency or greater service capacity.

Distributed orchestration should answer a measured need, not complete an architecture diagram. Reusable prefixes across replicas can justify cache-aware routing; different prefill and decode load curves can justify independent scaling; genuinely multi-node model work needs shared topology and state coordination. Otherwise a direct engine removes a queue, network hop, version boundary, and failure mode. Evaluate an orchestrator with uneven traffic, cold cache, worker loss, scaling transitions, and a slow downstream, not only steady-state peak throughput. Observe whether routing holds the latency objective, state survives, and queues remain bounded. The extra layer is justified only when these dynamic gains exceed its operational cost.

Preserve each decision as auditable evidence: hypothesis, complete dependency and hardware versions, model revision, traffic-generator settings, raw distributions rather than averages, quality result, profile trace, chosen setting, rejected alternatives, and rollback trigger. Engine defaults, compiler ability, and kernel support can change quickly. Without the record, a team cannot distinguish an obsolete plugin workaround from a constraint that still protects the service, and an old benchmark becomes folklore. Rerun the same evidence package before an upgrade to expose performance and quality regressions; during an incident, use it to return to the last known-safe setting.

Core ideas

CUDA components

A kernel executes parallel work; a CUDA graph records kernels and other device operations for efficient replay; the driver is the low-level hardware interface; and the runtime is the developer application programming interface (API) for launches and memory. CUDA programs are commonly written in C++ and compiled into host and device code.

Kernel libraries before custom code

Basic Linear Algebra Subprograms (BLAS) underpins cuBLAS matrix primitives, while cuDNN covers neural-network operations. CUTLASS and CuTe offer composable templates, and FlashInfer provides inference kernels. Most teams should let an engine select these or plug in a proven kernel before handwriting one; custom code belongs on a stable critical path whose measured gain pays for maintenance.

Selection is hardware-specific

A kernel tuned for one GPU generation or matrix shape may underuse another or fail to run. Automatic compilers and engines cover common paths, while a manual plugin belongs only where compatibility and measured gain are clear.

Framework and format

January 2026 edition snapshot: PyTorch was the dominant programmable framework. Safetensors separated non-executable weights from architecture, while Open Neural Network Exchange (ONNX) could package weights with an execution graph for portable runtimes, subject to export support.

Reference libraries are not production servers

January 2026 edition snapshot: Hugging Face transformers and diffusers were useful for model definitions, configuration, downloads, notebooks, and understanding input-output behavior; production traffic generally required compiled PyTorch or a serving engine.

Engine selection

January 2026 edition snapshot: vLLM emphasized broad adoption and model coverage, SGLang emphasized configurable components and strong mixture of experts (MoE) or diffusion paths, and TensorRT-LLM emphasized deep NVIDIA optimization with more setup effort. Validate the current matrix rather than preserving the ranking as doctrine.

Orchestration has a scale threshold

January 2026 edition snapshot: Dynamo coordinated engines for cache-aware routing, disaggregated serving, and multi-node work. Those capabilities can matter for large models and heavy traffic, while smaller services may gain little from the extra distributed layer.

Load and benchmark tools

January 2026 edition snapshot: SGLang GenAI-Bench and NVIDIA GenAI-Perf targeted generative-model traffic, while Locust supplied general concurrent load. Evaluation datasets could provide realistic inputs and a quality spot check, but the request distribution still had to match production.

Profiling tools

January 2026 edition snapshot: PyTorch Profiler covered framework steps, NVIDIA Nsight Systems traced CPU, GPU, and interconnect activity, and Nsight Compute analyzed individual kernels. Choose the narrowest scope that can explain the benchmark result.

How it works

  1. Choose a supported engine and establish a stable baseline with the target model, precision, hardware, dependency image, request shape, and concurrency distribution. Confirm output quality before tuning speed.
  2. Prefer shadowed production requests. If simulation is necessary, reproduce input and output lengths, request contents, arrival jitter, concurrency, sampling settings, and cache-relevant repetition rather than sending uniform synthetic prompts.
  3. Change one variable at a time, repeat enough runs to reduce outlier influence, and then test promising changes together. Techniques can interfere, so individual gains do not guarantee a combined gain.
  4. When the system-level result is insufficient or surprising, profile CPU time, GPU time, memory, kernel duration, and interconnect activity. Attribute the largest avoidable cost before editing a lower layer.
  5. For a bandwidth-heavy sequence, inspect whether adjacent operations write an intermediate to memory and immediately read it back. Use compiler fusion where it applies; reserve handwritten fusion for important stable paths that justify maintenance.
  6. Insert the selected kernel or configuration, then return to the original end-to-end benchmark. A faster isolated kernel is useful only if user-visible latency, throughput, cost, or capacity improves without quality loss.
Unfused versus fused memory traffic

Unfused read and First kernel lead to an Intermediate round trip through video random-access memory (VRAM), while Fused read passes through one Fused kernel directly to Final write.

Unfused read
Load input from VRAM
First kernel
Compute intermediate
Intermediate round trip
Write to and read from VRAM
Second kernel
Compute final value
Fused read
Load input once
Fused kernel
Perform both operations together
Final write
Store output once
  • Unfused readFirst kernel: Input
  • First kernelIntermediate round trip: Extra traffic
  • Intermediate round tripSecond kernel: Reload
  • Fused readFused kernel: Input
  • Fused kernelFinal write: Output

Metrics that matter

P50, P90, and P99 time to first token

TTFT

Segment by input length and load so queueing and prefill changes remain visible.

Per-request tokens per second

TPS

Measure output speed alongside batch and concurrency, not as an isolated maximum.

System throughput

tokens/s and requests/s

Report the latency constraint under which the throughput was achieved.

Operator and kernel time

ms and share of trace

Use a profile to find expensive compute, memory movement, launch gaps, or host work.

Peak and allocated memory

GB

Track model, cache, workspace, and transient allocations when changing compilation or kernels.

Output-quality delta

eval score

Use realistic evaluation inputs as benchmark traffic and as a guardrail against optimization regressions.

Trade-offs

Convenience versus peak control

Broad engines reduce implementation time and support many models; narrower or lower-level paths can win when the model, hardware, and traffic are stable enough to reward specialization.

Compilation versus plugins

Compilation can automatically select and fuse ordinary operations, while custom kernels cover unusual or highly tuned paths. Plugins may interrupt compiler visibility and increase compatibility work.

Weights only versus portable graph

Safetensors keeps serialization simple and safe while code defines execution; ONNX carries a graph across runtimes but export constraints can reject complex model features.

Direct engine versus orchestrator

A direct engine is simpler for modest deployments. Distributed orchestration earns its overhead when cache routing, independent worker pools, or multi-node coordination materially improve a large service.

Fast benchmark versus faithful benchmark

A small uniform test gives quick feedback but can reward the wrong configuration. Production-shaped distributions take longer yet protect the decision from sequence, load, cache, and parameter mismatch.

Engineering checklist

  • Recheck every January 2026 edition support and version statement against current official release notes before selecting a stack.
  • Pin driver, CUDA, framework, engine, kernel plugin, model revision, and container image for reproducible comparisons.
  • Record a quality-checked baseline before the first optimization and preserve its complete traffic configuration.
  • Match sequence lengths, concurrency, arrival pattern, request contents, sampling parameters, and expected cache behavior.
  • Test one change at a time, repeat runs, examine percentiles, and retest combinations for interference.
  • Profile only when the decision requires causal detail, then choose a tool at the right scope: framework, system, or individual kernel.
  • For a manual kernel, verify GPU generation, shape, precision, correctness, fallback behavior, and end-to-end benefit.
  • Shadow or canary the final configuration and watch latency, throughput, memory, errors, and output quality under real traffic.

Vocabulary

CUDA kernel
A function compiled to execute parallel work on an NVIDIA GPU.
CUDA graph
A reusable directed graph of GPU operations that reduces repeated scheduling overhead.
General matrix-matrix multiplication
The recurring linear-algebra operation behind model linear layers and a major kernel-selection target.
Kernel fusion
Combining adjacent operations so an intermediate can remain near compute instead of making an avoidable memory round trip.
Safetensors
A weight serialization format that stores tensor data without executable Python objects and supports memory mapping.
Inference engine
A serving runtime that packages model execution, scheduling, batching, memory management, and optimization controls.
Traffic shadowing
Copying production requests to a test deployment without changing the response seen by the original caller.
Profiler
A tool that attributes elapsed time and resource use to operations, kernels, host work, or communication.

Source map

  • Pages 93-101

    Abstraction stack, CUDA, kernel libraries, selection, and fusion.

  • Pages 101-105

    Frameworks, compilation, serialization formats, portable runtimes, and reference libraries.

  • Pages 105-111

    Serving-engine capabilities and positioning in the January 2026 edition.

  • Pages 111-112

    Distributed orchestration and its scale threshold in the January 2026 edition.

  • Pages 112-114

    Representative load, benchmarking tools, and experimental discipline.

  • Pages 114-116

    Profiling scopes, tools, and the measurement-to-implementation loop.

Software abstraction stack, CUDA components, kernel selection, and fusion
Printed pages: 93–101; PDF pages: 95–103
PyTorch, compilation, model formats, runtimes, transformers, and diffusers
Printed pages: 101–105; PDF pages: 103–107
vLLM, SGLang, and TensorRT-LLM capabilities and selection
Printed pages: 105–111; PDF pages: 107–113
NVIDIA Dynamo orchestration, scale threshold, cache routing, and disaggregation
Printed pages: 111–112; PDF pages: 113–114
Production-shaped benchmarking, load generation, and controlled experiments
Printed pages: 112–114; PDF pages: 114–116
Profiling purpose, tools, and benchmark-profile optimization loop
Printed pages: 114–116; PDF pages: 116–118