How do GPU execution and memory behavior shape AI kernel performance?
A tensor is a multidimensional array. Its shape specifies dimension sizes; its numerical type specifies how values are represented. A tensor operator describes a computation on these arrays. An operator need not correspond to one kernel: a compiler can combine several operators into one launch, keeping intermediate values inside that kernel.
Bias addition and ReLU are pointwise operations: each output uses its corresponding matrix entry. The chosen bias orientation matches the documented cuBLASLt epilogue convention. An epilogue is postprocessing applied to matrix results; a library option supporting it establishes available semantics, not the kernel count or speed of a particular invocation.
Training fits parameters; inference applies them. Both require array computation. Kernel optimization concerns that execution, while LLM Inference covers request-level behavior. Arithmetic, memory movement, and framework dispatch are distinct costs; improving one helps only when it matters to the required workload.
Follow the workers and the operands
The host is the CPU side; the device is the GPU side. A launch creates a grid of thread blocks, each containing threads. A block executes on one streaming multiprocessor, or SM. CUDA groups threads into 32-thread warps. Single-instruction, multiple-thread execution runs common kernel code, masking inactive lanes when threads take different branches. Ordinary blocks cannot assume scheduling order or simultaneous residency.
A scheduler can issue another ready warp while one waits. This hides latency when independent work exists; it does not shorten the waiting operation itself. Parallelism means simultaneous progress, whereas concurrency permits other work to progress during a wait. Creating more logical workers does not guarantee more useful execution.
Logical work and hardware placement
A launch describes more work than necessarily runs simultaneously.
Read the diagram as text
- Host.
- Launch grid.
- Thread block.
- Warp.
- Thread / lane.
- Streaming multiprocessor.
- Host → Launch grid: submits.
- Launch grid → Thread block: contains.
- Thread block → Warp: contains.
- Warp → Thread / lane: groups.
- Thread block → Streaming multiprocessor: placed when resources permit.
| Resource | Role |
|---|---|
| Global memory | Cross-launch inputs, outputs, and state; persists until freed. |
| Caches | Hardware-managed reuse of memory accesses; distinct from explicit shared-memory staging. |
| Shared memory | Block-accessible, programmer-managed on-chip scratchpad. |
| Registers and local memory | Private state exceeding registers spills to thread-private local memory in device memory, adding writes/rereads. |
Memory bandwidth measures bytes transferred per unit time; latency measures waiting time, and capacity measures storage available. On a discrete GPU, copying host inputs to device memory is separate from moving those operands toward arithmetic units. Shared-memory staging is optional. A model fitting in memory therefore says little about how quickly its operands can be supplied.
Coalescing groups lane addresses into transactions. With 32-byte segments, 32 aligned contiguous four-byte loads need four transactions; scattered loads can need 32. Cache reuse concerns later accesses.
| Layout issue | Consequence |
|---|---|
| Transpose view | Changes metadata without moving data, but changes subsequent access patterns. Making a non-contiguous view contiguous requires a copy. |
| Shared-memory banks | Successive 32-bit words occupy successive banks. Distinct same-bank addresses serialize; padding 32-by-32 float rows to 33 separates column accesses. |
| Portable execution groups | HIP wavefront width depends on the target. OpenCL workgroups contain implementation-controlled subgroups. Neither vocabulary guarantees CUDA's width or scheduling behavior. |
Establish correctness and meaningful timing
A test oracle determines whether output is acceptable; Evals explains that responsibility. For a kernel, establish an independently trusted reference and supported shapes, layouts, and types before optimizing. Include incomplete tiles and unusual values. A successful compilation or plausible output does not establish numerical correctness.
Submission ends before the work
Example timingsSubmission, kernel execution, and transfer-inclusive completion have different boundaries.
Read the diagram as text
- Transfer-inclusive operation. 0 to 12 microseconds; duration 12 microseconds.
- Host submission. 0 to 2 microseconds; duration 2 microseconds. Parent: Transfer-inclusive operation.
- Input copy. 1 to 4 microseconds; duration 3 microseconds. Parent: Transfer-inclusive operation.
- Kernel execution. 4 to 10 microseconds; duration 6 microseconds. Parent: Transfer-inclusive operation.
- Output copy. 10 to 12 microseconds; duration 2 microseconds. Parent: Transfer-inclusive operation.
Floating-point operations round, so addition is not associative. A reduction tree groups additions into partial sums; changing that grouping changes which intermediate results round and can change the final answer. Cancellation subtracts nearly equal quantities, potentially exposing earlier rounding error. Fused multiply-add computes a product plus an addend with one rounding instead of two. Algebraic equivalence does not imply bitwise equality.
| Requirement | Meaning |
|---|---|
| Accuracy | Error is acceptable against the reference. Include deliberate cases for long reductions, cancellation, and overflow, where results exceed the format's finite range. |
| Repeatability and bitwise equality | Repeated executions agreeing is distinct from agreeing with a reference. Different valid rounding paths may produce different bit patterns. |
| Exceptional values | NaN means not-a-number. Specify infinity and NaN behavior separately. In assert_close, infinities must match; NaNs match only when enabled. |
| Precision stages | FP16 is 16-bit half precision; FP32 is 32-bit single precision. BF16 (Brain Floating Point) uses 16 bits with greater range but fewer fraction bits than FP16. Storage type governs stored values; accumulator precision governs running sums. Multiplication behavior is separate. FP16 inputs can use FP32 accumulation. Quantization changes numerical representation; Quantization covers representation methods. |
A CUDA stream orders its commands; independent streams have no general relative order. Device events timestamp positions reached during execution. A stop event covers preceding work in its stream; other streams require explicit dependencies. Launches return before completion: wait for the stop event before reading elapsed time; CPU timing also needs completion. Extra synchronization can change overlap. Distinguish kernel-only and transfer-inclusive intervals.
A CPU API interval and a GPU execution interval describe different activities. Observability explains why parentage, overlap, and completion are separate facts; GPU traces additionally distinguish kernels from memory copies.
A benchmark record must preserve the conditions behind its result.
- Execution boundary — State whether setup, allocation, compilation, and transfers are included. Warmups remove some initialization effects; warmed timing does not describe cold starts.
- Repeated observations — Retain repeated timings and variability, not only the fastest run. Record hardware, software, workload, and measurement labels.
- Operating conditions — Disclose input reuse, cache policy, competing work, and clock conditions. Keep baseline and candidate conditions comparable.
Find the limiting resource
A workload timeline locates expensive kernels, transfers, and gaps. Kernel counters then narrow the explanation. High arithmetic capability cannot compensate for missing operands or dispatch delays. Diagnosis must connect an observed interval to a proposed change and the evidence that would support that change.
| Observation | Interpretation and next check |
|---|---|
| Many memory transactions | Inspect lane addresses and useful bytes before changing layout. |
| Short-scoreboard stalls | Shared-memory dependencies are one explanation; special math and branching can also contribute. Check memory evidence before diagnosing bank conflicts. |
| Many not-selected warps | These warps were eligible while another issued; the count can indicate sufficient latency-hiding work. |
Reuse and execution efficiency differ
ExampleReuse moves right; better execution at unchanged traffic moves upward.
Fixed precision and memory boundary
Both candidate changes start below the envelope.
Scroll sideways if the figure extends beyond the screen.
- 1. Performance envelope
- 2. Improve execution
- 3. Increase reuse
Read coordinates and regions as data
X: 0–12 operations/byte; Y: 0–10 tera-operations/second, increasing up. Axes scaled independently; screen angles and distances are not comparable.
(0, 0); (8, 8); (12, 8)
(4, 2); (4, 3.8)
(4, 2); (8, 5)
More reuse can increase intensity; better scheduling can improve throughput without changing it. A point below the envelope may reflect small launches, dependency chains, or insufficient parallelism. The model suggests hypotheses rather than forcing every workload into a compute-bound or bandwidth-bound category.
Profilers can replay kernels, serialize launches, alter clocks, and flush caches. Replaying device memory does not restore cache contents. Use counters diagnostically, then confirm performance in ordinary benchmark execution.
Divide work and coordinate safely
Output ownership assigns results to workers: an element per thread, a row or rectangular tile per group. Larger assignments offer reuse but fewer independently schedulable groups.
A reduction combines values; GEMM sums products along . Split-K divides this dimension among blocks, gaining parallelism but adding partial-output storage and a combining kernel. Queue the combiner after its producers in one stream; across streams, make its stream wait on an event recorded after each producer.
Cooperative computation needs explicit phase boundaries.
- Publish operands — Threads populate shared memory before other threads consume it. A block barrier coordinates the phase; participating threads must reach it consistently.
- Protect reuse — Finish all reads before overwriting shared storage. A later barrier cannot repair an earlier producer-consumer race, including within a warp.
- Check safety separately — Bounds, initialization, race, and synchronization checks target different defects. Passing shared-memory race checking does not establish absence of every global-memory race.
An atomic operation protects an update to its target location. Scope determines which participants it covers; memory ordering determines relationships to other accesses. CUDA's legacy atomics use relaxed ordering, so atomically updating an accumulator does not publish an unrelated operand buffer. Newer interfaces permit explicit ordering and scope. Atomicity is not a substitute for the required synchronization protocol.
Occupancy is resident warps divided by the SM's supported maximum. Registers, shared memory, and block size constrain residency. More occupancy need not mean more throughput: larger assignments may improve reuse while reducing residency. Optimize completed useful work, not occupancy alone.
Reuse operands through tiled matrix computation
Tiling computes an output region through successive chunks of , retaining partial sums while reusing operand chunks. Edge loads must be masked and missing reduction values replaced by zero; final stores must exclude nonexistent outputs. This preserves ownership even when dimensions do not divide evenly.
For and two-byte operands, the chunk performs 8,192 operations from 1,024 operand bytes: eight operations per byte. Each loaded A entry contributes to 16 columns; each B entry contributes to 16 rows. This is an idealized reuse count, not measured device traffic or a predicted speedup.
Larger tiles consume scratchpad and accumulator capacity. Edge waste and reduced parallelism can offset saved operand loads.
Matrix multiply-accumulate (MMA) adds a matrix product to an accumulator; specialized hardware requires a compatible execution contract.
- Collective fragments — WMMA fragments distribute operands and accumulators across a warp with unspecified element mapping. All threads participate with matching parameters.
- Layout and precision — CUDA 13.0 WMMA constrains shapes, types, layouts, alignment, and leading dimensions. Loads require 256-bit pointer alignment; BF16 fragments require float accumulators.
- Communication guarantees — Warp shuffles exchange register values without memory barriers; participation does not publish unrelated writes.
Padding, conversion, and rearrangement must earn back their cost. Hardware literacy helps identify a fast arithmetic path, but peak matrix throughput cannot establish that the complete workload benefits.
Keep intermediate results close to computation
Fusion executes multiple operators within one kernel. For GEMM, bias, and activation, an epilogue can process accumulated results before final storage. Internal values may travel through registers or shared memory rather than becoming full device-memory arrays. Fusion can save launches and intermediate traffic independently; fewer allocations are another possible benefit, not a prerequisite.
| Plan | Launches | Matrix writes | Matrix rereads |
|---|---|---|---|
| GEMM, then bias, then ReLU | 3 | 3 | 2 |
| GEMM with bias–ReLU epilogue | 1 | 1 | 0 |
A consumer can keep storage necessary
ExampleFusion removes storage only when no required use needs it.
Read the diagram as text
- Accumulated matrix.
- Bias and activation.
- Final output.
- Stored auxiliary matrix.
- Second consumer.
- Accumulated matrix → Bias and activation: data: internal result.
- Bias and activation → Final output: data: final store.
- Accumulated matrix → Stored auxiliary matrix: data: store if required.
- Stored auxiliary matrix → Second consumer: data: required read.
Fusion can change rounding when it omits or moves an intermediate conversion; explicit casts can preserve that rounding boundary. Recheck the numerical contract and retain required outputs: an auxiliary consumer can require materialization even when the main path is fused.
Fusion boundaries must respect dependencies and layouts. Extending fusion across a whole model can make coordination substantially harder. Larger fused computations also require resource checks. A reduced launch count alone is insufficient evidence of improvement.
- Lifetime-based reuse — Storage can serve successive intermediates once the earlier value has no remaining use. This reduces allocation demand without necessarily removing computation or traffic.
- Graph replay — CUDA graphs record operations and dependencies, prepare an executable graph, and replay it. Replay reduces repeated host setup and launch overhead while retaining device computation. Capture and update restrictions still apply; configuring a graph does not establish that execution uses it.
Extend tiling with overlapped data movement
Double buffering alternates operand buffers: fill only reusable storage; consume only completed data. This overlaps within-kernel movement, not host-device transfers.
Asynchronous submission enables overlap only when independent work and suitable resources exist. More buffers consume capacity, and short workloads offer little steady-state overlap. A timeline must show completed movement and legal reuse, not merely early issuance of copies.
Two-buffer pipeline
Example timingsOverlap retains startup and drain.
Read the diagram as text
- Two-tile pipeline. 0 to 8 time units; duration 8 time units.
- Load tile 0 → A. 0 to 2 time units; duration 2 time units. Parent: Two-tile pipeline.
- Compute tile 0 from A. 2 to 5 time units; duration 3 time units. Parent: Two-tile pipeline.
- Load tile 1 → B. 2 to 4 time units; duration 2 time units. Parent: Two-tile pipeline.
- Compute tile 1 from B. 5 to 8 time units; duration 3 time units. Parent: Two-tile pipeline.
Validate the optimization across real workload shapes
An established library and a compiler-generated implementation are meaningful baselines. Try framework compilation before custom CUDA or Triton code. CUDA exposes GPU programming constructs; Triton expresses blocked computations. A custom implementation must justify its complexity against the actual workload and software version, not an outdated baseline.
Equivalent high-level expressions can outperform custom kernels by reaching a better backend primitive. Conversely, mature matrix-multiplication libraries are difficult baselines to beat. Automated synthesis still needs separate compilation, execution, correctness, and hardware-performance checks; generated code is a candidate, not performance evidence.
| Candidate advantage | Required validation |
|---|---|
| Packed contiguous operands | Include conversion when fresh strided inputs arrive every invocation. A reusable packed-input benchmark excludes that recurring work. |
| Fused intermediate elimination | Retain every required auxiliary output. Disabling a second consumer changes the workload. |
| Graph replay | Confirm compatibility with input updates and dependencies, then measure through completion of all required consumers. |
| Tuned tile configuration | Sweep representative sizes, awkward boundaries, layouts, and types. Recheck correctness for each candidate; keep regression cases. |
Protect the measurement machinery from the candidate. Reported benchmark exploits distinguish correctness runs from timing runs, reuse answers, alter inputs, or tamper with timers. Verify fresh-input execution and inspect generated code. Apparent throughput exceeding a relevant physical ceiling is a reason to investigate the measurement and its assumptions.
Search can explore equivalent implementations and profile candidates rather than assume every rewrite helps. Its cost belongs in the decision. Preserve the supported workload, environment, correctness results, timing distributions, and whole-workload boundary. Stop when the remaining bottleneck lies elsewhere or expected repeated savings no longer justify tuning and maintenance.
Open questions
Workload-specific error budgets remain difficult to derive for long reductions and cancellation. Progress means connecting accepted kernel error to downstream requirements across challenging inputs, rather than inheriting a library tolerance.
Portable specialization must reconcile changing execution-group widths and collective guarantees. This matters because a correct lane mapping on one target may fail elsewhere. Progress requires target-aware implementations validated under each supported width and synchronization contract.
Graph replay needs stronger applicability evidence for changing workloads. Reduced submission overhead matters only if updates, capture restrictions, and required consumers remain compatible. Progress means demonstrating complete fresh-input execution with those costs included.
Optimization verifiers must resist candidates that recognize or alter evaluation phases. This remains hard because correctness and timing often expose different behavior. Progress means independently reproducing gains with fresh inputs, protected measurements, and checks against applicable resource limits.






