1. The SM is the Resource You Actually Manage

A block size that achieves 100% occupancy on a Pascal P100 might throttle on an Ampere A100 due to register allocation rules. A shared memory tile size that saturates Turing's cache might leave Ampere's expanded 164 KB capacity half-empty. An algorithm that was hopelessly memory-bandwidth-bound on Pascal might suddenly become compute-bound on Ampere simply because HBM2e bandwidth tripled while Tensor Core throughput jumped by an order of magnitude.

None of that is an accident. It is the direct result of how NVIDIA has systematically redesigned the Streaming Multiprocessor (SM) — the fundamental execution engine of the GPU — across the Pascal, Turing, and Ampere architectures.

Pascal • 2016
GP100 / GP102
Tesla P100, GTX 1080
FP32 Cores / SM 64 (GP100) / 128
Tensor Cores None (DP4A / FP16)
Shared Mem / SM 64 KB - 96 KB
Max Bandwidth ~720 GB/s (HBM2)
Turing • 2018
TU10x Architecture
Tesla T4, RTX 2080
FP32 + INT32 / SM 64 FP32 + 64 INT32
Tensor Cores 2nd Gen (8 / SM)
Shared Mem / SM 96 KB (Unified L1)
Concurrent INT/FP Yes (Independent)
Ampere • 2020
GA100 Architecture
NVIDIA A100, RTX 3090
FP32 Cores / SM 64 (GA100) / 128
Tensor Cores 3rd Gen (+TF32, Sparsity)
Shared Mem / SM 164 KB (+ cp.async)
Max Bandwidth ~2.0 TB/s (HBM2e)
Streaming Multiprocessor (SM) Microarchitecture Anatomy
Thread blocks decompose into warps scheduled across 4 execution sub-partitions per SM.
NVIDIA STREAMING MULTIPROCESSOR (SM) SUB-PARTITION 0 Warp Scheduler & Dispatch 16K Register File (32-bit) FP32 ALU 16 Cores INT32 / TC Datapath SUB-PARTITION 1 Warp Scheduler & Dispatch 16K Register File (32-bit) FP32 ALU 16 Cores INT32 / TC Datapath SUB-PARTITION 2 Warp Scheduler & Dispatch 16K Register File (32-bit) FP32 ALU 16 Cores INT32 / TC Datapath SHARED MEM / L1 High-Bandwidth On-Chip SRAM Pascal: 64-96 KB Config Turing: 96 KB Unified Ampere: 164 KB + cp.async

2. Pascal (GP100): The Baseline Architecture

Pascal is the cleanest reference architecture for classical CUDA programming. It represents the peak of the "pure SIMT" era before dedicated matrix-multiply hardware became the defining feature of high-end GPUs.

  • SM Structure: A Pascal SM (GP100 in the P100) is partitioned into two 32-core processing blocks, each with its own warp scheduler, dispatch unit, and register file — 64 CUDA cores per SM total for GP100. Consumer GP102 parts use 128 CUDA cores per SM split into four 32-core partitions.
  • CUDA Cores: Pascal cores execute one FP32 fused-multiply-add (FMA) per clock per core. GP100 additionally supports full-rate FP16 ($2\times$ FP32 throughput via packed half2 operations) and 1/2-rate FP64.
  • Warp Scheduling: Each 32-core partition has its own warp scheduler issuing instructions to the core array. Latency hiding depends entirely on having enough resident warps per scheduler to cover arithmetic or memory latency pipelines.
  • Registers & Shared Memory: 64K 32-bit registers per SM, up to 255 registers per thread, and 64KB-96KB of configurable shared memory/L1.
  • Memory Bandwidth: GP100 pairs with HBM2, delivering $\approx 720\text{ GB/s}$ on the P100 — the first architecture where memory bandwidth stopped being the universal bottleneck for well-tiled GEMMs.
  • Tensor Cores: None. Pascal has no Tensor Cores. Mixed precision on Pascal means manually packing FP16 storage with FP32 accumulation via intrinsics, not dedicated matrix hardware.

3. Turing (TU104 / Tesla T4): The Inference Shift

Turing is the pivotal transitional architecture. It introduced dedicated hardware matrix units to mainstream and datacenter inference tiers, fundamentally shifting what kind of compute dominates.

  • SM Structure & Concurrent INT32: Turing splits the SM into four partitions (16 FP32 + 16 INT32 cores per partition = 64 FP32 + 64 INT32 per SM). The headline architectural leap is the addition of a dedicated INT32 datapath alongside FP32 — integer and floating-point instructions execute concurrently. Address generation, loop counters, and pointer arithmetic no longer steal cycles from your FP32 math.
  • Tensor Cores (2nd Gen): Turing introduces 2nd-gen Tensor Cores (8 per SM), adding INT8 and INT4 support on top of FP16 matrix-multiply-accumulate (MMA). A single Tensor Core instruction executes an entire matrix MAC tile across a warp.
  • Registers & Shared Memory: 64K registers per SM, with shared memory unified with L1 in a flexible split — up to 96KB combined per SM (e.g. 64KB shared / 32KB L1).
  • L1 & L2 Cache: Doubled L2 cache size relative to Pascal at comparable tiers (up to 6MB L2), significantly accelerating irregular access patterns like embedding lookups and attention gathers.
  • Memory Bandwidth: The T4 uses GDDR6 ($\approx 320\text{ GB/s}$), intentionally trading bandwidth for power efficiency (70W TDP) because Tensor Core compute throughput is the targeted bottleneck.

4. Ampere (GA100 / NVIDIA A100): The Memory & Sparsity Leap

Ampere is the modern standard for large-scale training and high-throughput inference. It restructures the SM around memory hierarchy acceleration and multi-precision versatility.

  • SM Structure: GA100 divides the SM into four sub-partitions, each containing dedicated warp schedulers, register files, FP32/FP64 pipelines, and 3rd-gen Tensor Cores.
  • Tensor Cores (3rd Gen): Adds native support for TF32 (19-bit format providing FP32 dynamic range at near-FP16 Tensor Core speed without code changes), BF16, full FP64 Tensor Cores, and 2:4 structured sparsity (~2× throughput for pruned weight matrices).
  • Shared Memory & Asynchronous Copy (cp.async): Ampere nearly doubles the shared memory ceiling to 164KB per SM and introduces cp.async — an asynchronous copy instruction that transfers global memory directly into shared memory via hardware DMA without routing through registers.
  • Massive 40MB L2 Cache: L2 cache balloons to 40MB on the A100 with residency controls (cudaFuncAttributePreferredSharedMemoryCarveout), enabling developers to pin frequently-reused structures (like attention KV caches) directly in L2.
  • Memory Bandwidth: A100 delivers up to ~2.0 TB/s (HBM2e) — roughly $6\times$ Turing's T4 bandwidth, supercharging bandwidth-bound operations (Softmax, RMSNorm, GELU).

5. Memory Staging: Pre-Ampere vs. Ampere

The difference between how Pascal/Turing stage memory tiles versus Ampere's hardware DMA pipeline represents one of the most critical paradigm shifts in modern CUDA programming:

Pre-Ampere vs Ampere Memory Staging Pipeline
Before Ampere, staging tiles required intermediate registers. Ampere's cp.async copies directly via hardware DMA.
PRE-AMPERE (PASCAL & TURING): 2 LOAD/STORE ROUNDTRIPS Global Memory LD.GLOBAL Register File ST.SHARED Shared Memory × High Register Pressure & Stall AMPERE (A100): HARDWARE ASYNCHRONOUS DMA (cp.async) Global Memory cp.async (Direct DMA Bypass) Shared Memory ✓ Zero Register File Overhead

6. Side-by-Side Architectural Specifications

The definitive hardware parameters across the three architectures:

Hardware Feature / Parameter Pascal (GP100) Turing (TU104 / T4) Ampere (GA100 / A100)
Launch Year & Process 2016 (16nm FinFET) 2018 (12nm FFN) 2020 (7nm TSMC)
FP32 Cores / SM 64 (GP100) / 128 64 64 (Higher Effective Throughput)
Dedicated INT32 Datapath No (Shared ALU) Yes (64 Cores/SM) Yes (64 Cores/SM)
Tensor Core Generation None (Manual FP16 packing) 2nd Gen (FP16/INT8/INT4) 3rd Gen (+TF32, BF16, FP64, Sparsity)
Max Shared Memory / SM 64 KB (up to 96 KB) 96 KB (Unified L1) 164 KB (+ Configurable Carveouts)
L2 Cache Capacity 4 MB (GP100) 6 MB (TU104) 40 MB (with Residency Control)
Memory Type & Bandwidth HBM2, ~720 GB/s GDDR6, ~320 GB/s HBM2e, ~2.0 TB/s
Async Global → Shared Copy No (via Registers) No (via Registers) Yes (cp.async DMA)
Structured Sparsity Support No No Yes (2:4, ~2× TC Throughput)

7. Six Rules of Thumb for CUDA Developers

1 Occupancy tuning is architecture-specific, not portable.

A block/thread configuration tuned for Pascal's 64K-register, ~96KB-shared-memory budget will not utilize an Ampere SM's 164KB ceiling efficiently. Never assume occupancy parameters transfer between generations; re-profile on your target device.

2 Separate INT32 datapath rewards isolating address math from data math.

From Turing onward, address calculation, loop counters, and pointer arithmetic run in parallel with FP32 FMAs. Structuring kernels so integer address generation happens alongside floating-point math hides indexing latency completely for free.

3 Tensor Cores are opt-in, not automatic.

Writing a naive CUDA-core GEMM on a T4 or A100 leaves the dominant compute silicon idle. Hand-rolled kernels (fused RNN gates, custom attention) require wmma / mma PTX instructions, CUTLASS, or cuBLAS/cuDNN to achieve peak arithmetic intensity.

4 Memory-bandwidth-bound operations benefit most from generational leaps.

Elementwise activations, softmax, LayerNorm, and RMSNorm are memory-bound. While Pascal → Turing reduced memory bandwidth on inference SKUs (T4), Ampere's jump to 2.0 TB/s provides massive generational speedups on normalization layers.

5 cp.async on Ampere revolutionizes tiled kernels.

Ampere's asynchronous copy pipeline transfers data directly from global memory to shared memory via DMA, eliminating register file roundtrips and instruction stalls:

Ampere Asynchronous Global-to-Shared Copy (CUDA C++)
// Ampere Asynchronous Tile Copy via cp.async
#if __CUDA_ARCH__ >= 800
__device__ inline void cp_async_16B(void* smem_ptr, const void* gmem_ptr) {
    unsigned int smem_addr = __cvta_generic_to_shared(smem_ptr);
    asm volatile("cp.async.ca.shared.global [%0], [%1], 16;\n" 
                 : : "r"(smem_addr), "l"(gmem_ptr));
}

__device__ inline void cp_async_commit_and_wait() {
    asm volatile("cp.async.commit_group;\n");
    asm volatile("cp.async.wait_group 0;\n");
}
#endif
6 Precision choice is now an architecture-aware decision.

On Pascal, mixed precision required manual FP16 packing. On Turing, INT8/FP16 Tensor Cores made quantization fast. On Ampere, TF32 provides instant speedups for FP32 training with zero numerical modification, and BF16 eliminates FP16 underflow/overflow concerns.

8. Key Engineering Takeaways

Across all three generations, the trajectory is clear: NVIDIA grows on-chip resources per SM (shared memory, register flexibility, unified caches) faster than raw core counts, while shifting matrix-multiply arithmetic onto specialized Tensor Core units.

Architectural Takeaway

Benchmarking against a vendor library on any of these three architectures is fundamentally a benchmark against how well that library exploits that generation's Tensor Cores, cache persistence, and DMA copy paths. Writing high-performance CUDA demands co-designing your kernel around the target SM's physical hardware constraints.

Read More Systems Research & Engineering

Link copied to clipboard!