mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
2691 字
8 分钟
GPU 架构概览
2026-03-05

CPU 有 8 个核心,每个核心能跑 4GHz,单线程性能极强。GPU 有 5000 多个核心,每个核心只能跑 1.5GHz,单线程性能很弱——但 5000 个核心同时跑,吞吐量碾压 CPU。这不是”GPU 比 CPU 强”,而是两种完全不同的设计哲学:CPU 用延迟换吞吐量(尽快完成一个任务),GPU 用吞吐量换延迟(同时处理尽可能多的任务)。理解这个差异,才能知道什么时候该上 GPU,什么时候 CPU 反而更快。

一、GPU vs CPU:设计哲学#

1.1 核心架构对比#

graph TB subgraph "CPU:延迟优化" C_CORE["少量强大核心<br/>4-8 个"] C_CACHE["大缓存<br/>L1: 32KB/core<br/>L2: 256KB/core<br/>L3: 共享 8-32MB"] C_ALU["复杂 ALU<br/>分支预测<br/>乱序执行"] C_CTRL["复杂控制逻辑<br/>~30% 面积"] end subgraph "GPU:吞吐优化" G_CORE["大量简单核心<br/>数千个"] G_CACHE["小缓存<br/>Shared: 48-96KB/block<br/>L2: 共享 2-6MB"] G_ALU["简单 ALU<br/>无分支预测<br/>顺序执行"] G_CTRL["简单控制逻辑<br/>~10% 面积"] end style C_CTRL fill:#e3f2fd,stroke:#1565c0 style G_CORE fill:#c8e6c9,stroke:#2e7d32
维度CPUGPU
设计目标最小化单线程延迟最大化总吞吐量
核心数4-8(桌面)数千(NVIDIA H100: 16896)
时钟频率3-5 GHz1-2 GHz
缓存大(MB 级)小(KB 级)
分支预测复杂、高准确率
乱序执行支持不支持
内存带宽~50 GB/s~3000 GB/s
单线程延迟~1 ns~10 ns
总吞吐量极高

1.2 为什么 GPU 更适合并行计算#

CPU 处理 1000 个数据:
1 个核心 × 1 ns/操作 × 1000 = 1000 ns
8 个核心 × 1 ns/操作 × 125 = 125 ns(并行)
GPU 处理 1000 个数据:
1000 个核心 × 10 ns/操作 × 1 = 10 ns(全并行)
GPU 的优势:当任务可以分解为大量独立操作时
GPU 的劣势:当任务需要复杂分支或串行逻辑时

二、SIMT 编程模型#

2.1 SIMT vs SIMD#

模型含义分支处理
SIMDSingle Instruction Multiple Data所有数据必须执行相同操作
SIMTSingle Instruction Multiple Threads线程可以分支,但会串行化执行
graph TB subgraph "SIMD:所有数据相同操作" S1["指令: ADD"] --> S2["数据0: +1<br/>数据1: +2<br/>数据2: +3<br/>数据3: +4"] end subgraph "SIMT:线程可分支" T1["指令: IF"] --> T2["线程0: 路径A<br/>线程1: 路径B<br/>线程2: 路径A<br/>线程3: 路径B"] T2 --> T3["路径A: 线程0,2 执行<br/>线程1,3 等待"] T3 --> T4["路径B: 线程1,3 执行<br/>线程0,2 等待"] T_NOTE[" Warp 分歧:两条路径串行执行<br/>性能下降 2x"] end style T_NOTE fill:#ffcdd2,stroke:#c62828

2.2 CUDA 执行层次#

层次说明数量
Grid一个 kernel 启动的所有线程1
Block线程组,共享内存,可同步数百到数千
Thread单个执行线程数千到数百万
Warp32 个线程同时执行(SIMT 单元)Block 内多个
// CUDA kernel:指定 Grid 和 Block 大小
__global__ void vectorAdd(float* a, float* b, float* c, int n) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < n) {
c[i] = a[i] + b[i];
}
}
// 启动 kernel:256 个线程/Block,n/256 个 Block
int blockSize = 256;
int numBlocks = (n + blockSize - 1) / blockSize;
vectorAdd<<<numBlocks, blockSize>>>(a, b, c, n);

三、GPU 内存层次#

3.1 内存类型#

graph TB subgraph "GPU 内存层次" REG["寄存器<br/>~1 ns<br/>每线程私有<br/>最快"] SHARED["共享内存<br/>~5 ns<br/>每 Block 共享<br/>用户管理"] L2["L2 缓存<br/>~20 ns<br/>所有 SM 共享"] GLOBAL["全局内存<br/>~200-400 ns<br/>所有线程可访问<br/>最大容量"] CONST["常量内存<br/>~5 ns(缓存命中)<br/>只读"] TEXTURE["纹理内存<br/>~5 ns(缓存命中)<br/>空间局部性"] end REG --> SHARED --> L2 --> GLOBAL CONST --> L2 TEXTURE --> L2 style REG fill:#c8e6c9,stroke:#2e7d32 style GLOBAL fill:#ffcdd2,stroke:#c62828
内存类型延迟容量作用域管理
寄存器~1 ns256 KB/SM每线程编译器
共享内存~5 ns48-96 KB/SM每 Block程序员
L1 缓存~5 ns128 KB/SM每 SM硬件
L2 缓存~20 ns2-6 MB全局略件
全局内存~400 ns8-80 GB全局程序员
常量内存~5 ns(命中)64 KB全局程序员

3.2 内存合并#

// 非合并访问:线程访问分散的地址
__global__ void badAccess(float* data) {
int i = threadIdx.x * 256; // 步长 256
float val = data[i]; // 32 个线程访问 32 个分散地址
// 每个线程单独访问全局内存 → 32 次内存事务
}
// 合并访问:线程访问连续地址
__global__ void goodAccess(float* data) {
int i = threadIdx.x; // 步长 1
float val = data[i]; // 32 个线程访问连续 128 字节
// 一次 128 字节内存事务 → 1 次访问
}
Note

内存合并是 GPU 性能的关键。当 Warp 中的 32 个线程访问连续的 128 字节(32 × 4 字节 float),GPU 可以用一次内存事务完成所有读取。非合并访问需要 32 次独立事务,性能下降 10-30 倍。

四、Streaming Multiprocessor#

4.1 SM 内部结构#

一个 SM(Streaming Multiprocessor)包含:
├── 64-128 个 CUDA 核心(FP32)
├── 32-64 个 FP64 核心
├── 4-8 个 Tensor 核心(矩阵加速)
├── 1-2 个 Warp Scheduler
├── 2-4 个 Dispatch Unit
├── 64-128 KB 寄存器文件
├── 48-96 KB 共享内存
├── 128 KB L1 缓存
└── 加载/存储单元
└── 特殊功能单元(SFU)
NVIDIA H100 (Hopper):
132 个 SM × 128 核心/SM = 16896 个 FP32 核心
132 个 SM × 64 核心/SM = 8448 个 FP64 核心
132 个 SM × 4 Tensor 核心/SM = 528 个 Tensor 核心

4.2 GPU 架构演进#

架构年份SM 数核心/SM关键特性
Fermi20101632首个完整 GPU 计算架构
Kepler201215192动态并行、Hyper-Q
Maxwell201424128统一内存
Pascal20166064NVLink、FP16
Volta20178064Tensor Core、独立线程调度
Ampere2020108128第三代 Tensor Core、多实例 GPU
Hopper2022132128第四代 Tensor Core、Transformer引擎

五、Warp 调度与 Occupancy#

5.1 Warp 调度机制#

SM 内部的 Warp Scheduler 是 GPU 实现高吞吐的关键。每个 SM 包含 2-4 个 Warp Scheduler,每个调度器每个周期从就绪的 Warp 中选一个发射指令。当某个 Warp 等待内存访问返回时,调度器立即切换到另一个就绪的 Warp——这种零开销切换正是 GPU 隐藏延迟的核心手段。

graph TB subgraph "Warp Scheduler 工作流程" WS["Warp Scheduler"] -->|"周期 0"| W0["Warp 0<br/>FFMA 指令"] WS -->|"周期 1"| W1["Warp 1<br/>FFMA 指令"] WS -->|"周期 2"| W2["Warp 2<br/>LOAD 指令<br/>→ 等待内存"] WS -->|"周期 3"| W3["Warp 3<br/>FFMA 指令"] WS -->|"周期 4"| W0 W2 -.->|"内存返回后<br/>重新就绪"| WS end NOTE["关键:Warp 切换零开销<br/>无需保存/恢复寄存器<br/>所有 Warp 的寄存器常驻 SM"] style NOTE fill:#fff9c4,stroke:#f9a825 style W2 fill:#ffcdd2,stroke:#c62828

与 CPU 的线程切换不同,GPU 的 Warp 切换不需要保存和恢复寄存器——所有活跃 Warp 的寄存器都常驻在 SM 的寄存器文件中。调度器只需修改一个指针,下一周期就能执行新 Warp 的指令。

5.2 Occupancy:SM 利用率#

Occupancy 衡量的是 SM 上实际活跃的 Warp 数量与最大支持数量的比值。高 Occupancy 意味着更多 Warp 可供调度,从而更好地隐藏内存延迟。

限制因素影响计算方式
寄存器数量每个 Thread 使用的寄存器越多,SM 能容纳的 Block 越少65536 ÷ (threads_per_block × regs_per_thread)
共享内存每个 Block 使用的共享内存越多,SM 能容纳的 Block 越少shared_mem_per_SM ÷ shared_mem_per_block
Block 大小必须是 32 的倍数才有好的 Warp 利用率blockDim.x × blockDim.y × blockDim.z
最大 Block 数硬件限制每个 SM 最多 16-32 个 Block架构决定
// 使用 CUDA Occupancy API 查询最优配置
int blockSize = 256;
int numBlocks;
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocks,
myKernel, blockSize, 0);
float occupancy = (numBlocks * blockSize) /
(float)maxThreadsPerSM;
printf("Occupancy: %.1f%%\n", occupancy * 100);

Occupancy 不是越高越好。当寄存器压力导致溢出(spill to local memory)时,反而会降低性能。实际调优中,50%-75% 的 Occupancy 往往就能达到最佳吞吐。

六、Tensor Core 与混合精度#

6.1 Tensor Core 的工作原理#

从 Volta 架构开始,NVIDIA 在每个 SM 中加入了 Tensor Core——专门执行矩阵乘加运算(MMA)的硬件单元。一条 Tensor Core 指令可以完成 D = A × B + C,其中 A、B 是 4×4 矩阵,一次计算 128 个乘加操作。

// 使用 WMMA (Warp Matrix Multiply-Accumulate) API
#include <mma.h>
using namespace nvcuda::wmma;
__global__ void tensorCoreMatmul(half* A, half* B, float* C, int N) {
fragment<matrix_a, 16, 16, 16, half, row_major> a_frag;
fragment<matrix_b, 16, 16, 16, half, col_major> b_frag;
fragment<accumulator, 16, 16, 16, float> c_frag;
fill_fragment(c_frag, 0.0f);
for (int k = 0; k < N; k += 16) {
load_matrix_sync(a_frag, A + ..., N);
load_matrix_sync(b_frag, B + ..., N);
mma_sync(c_frag, a_frag, b_frag, c_frag);
}
store_matrix_sync(C + ..., c_frag, N, mem_row_major);
}

6.2 精度格式对比#

混合精度训练的核心思路:用低精度做前向和反向的计算(快),用高精度做梯度更新(准)。

格式位宽范围精度典型用途
FP3232 位±3.4e387 位十进制模型参数更新、损失计算
FP1616 位±6.5e43 位十进制前向/反向计算(需 loss scaling)
BF1616 位±3.4e382 位十进制前向/反向计算(无需 loss scaling)
TF3219 位±3.4e383 位十进制Tensor Core 默认格式(Ampere+)
INT88 位-128~127整数推理量化

BF16 保持了 FP32 的动态范围但牺牲了精度,FP16 精度更高但范围小、容易溢出。TF32 是 Ampere 架构引入的折中——用 FP32 的寄存器和数据路径,但只保留 10 位尾数,在 Tensor Core 上获得接近 FP16 的吞吐。

七、GPU 编程模型深入#

7.1 CUDA Streams 与异步执行#

CUDA Stream 是 GPU 上的任务队列——同一个 Stream 内的操作串行执行,不同 Stream 之间的操作可以并行。合理使用多 Stream 可以实现数据传输与计算的 overlap。

// 多 Stream 实现 CPU-GPU 传输与计算的 overlap
cudaStream_t stream0, stream1;
cudaStreamCreate(&stream0);
cudaStreamCreate(&stream1);
int chunkSize = N / 2;
// Stream 0:处理前半部分数据
cudaMemcpyAsync(d_A0, h_A0, chunkSize * sizeof(float),
cudaMemcpyHostToDevice, stream0);
kernel<<<grid, block, 0, stream0>>>(d_A0, d_B0, d_C0, chunkSize);
cudaMemcpyAsync(d_C0, h_C0, chunkSize * sizeof(float),
cudaMemcpyDeviceToHost, stream0);
// Stream 1:处理后半部分数据(与 Stream 0 并行)
cudaMemcpyAsync(d_A1, h_A1, chunkSize * sizeof(float),
cudaMemcpyHostToDevice, stream1);
kernel<<<grid, block, 0, stream1>>>(d_A1, d_B1, d_C1, chunkSize);
cudaMemcpyAsync(d_C1, h_C1, chunkSize * sizeof(float),
cudaMemcpyDeviceToHost, stream1);
cudaDeviceSynchronize(); // 等待所有 Stream 完成
graph LR subgraph "单 Stream(串行)" S1_H2D["H2D 传输"] --> S1_K["Kernel 计算"] --> S1_D2H["D2H 传输"] end subgraph "双 Stream(重叠)" S2_H2D["Stream0: H2D"] --> S2_K["Stream0: Kernel"] S2_H2D2["Stream1: H2D"] --> S2_K2["Stream1: Kernel"] S2_K --> S2_D2H["Stream0: D2H"] S2_K2 --> S2_D2H2["Stream1: D2H"] end style S1_H2D fill:#bbdefb style S2_H2D fill:#c8e6c9 style S2_H2D2 fill:#c8e6c9

7.2 Unified Memory#

Unified Memory 让 CPU 和 GPU 共享同一块虚拟地址空间,驱动自动在 CPU 和 GPU 之间迁移数据:

// Unified Memory:无需手动 cudaMemcpy
float* data;
cudaMallocManaged(&data, N * sizeof(float));
// CPU 初始化
for (int i = 0; i < N; i++) data[i] = i * 0.5f;
// GPU 计算(驱动自动将数据迁移到 GPU)
kernel<<<grid, block>>>(data, N);
cudaDeviceSynchronize();
// CPU 读取结果(驱动自动将数据迁移回 CPU)
printf("result[0] = %f\n", data[0]);
cudaFree(data);

Unified Memory 简化了编程,但首次访问时的页面迁移会产生额外延迟。生产环境中,通常用 cudaMemPrefetchAsync 主动预取数据到目标设备。

八、GPU 存储一致性#

8.1 GPU 的弱序内存模型#

GPU 采用弱序内存模型(Weakly Ordered Memory Model)——不同线程的内存操作对其他线程的可见顺序不保证与程序顺序一致。这与 CPU 的内存排序问题类似(详见第 8 章:内存排序),但 GPU 的模型更弱。

// GPU 上的可见性问题
__device__ int data = 0;
__device__ int flag = 0;
// Thread 0(生产者)
data = 42; // 写入数据
__threadfence(); // 确保所有先前写操作对全局可见
flag = 1; // 设置标志
// Thread 1(消费者)
while (flag != 1); // 等待标志
// 没有 __threadfence(),可能看到 flag=1 但 data 仍是 0!
int val = data; // 需要 fence 保证读到 42

8.2 同步原语#

原语作用域功能
__syncthreads()Block 内所有线程到达屏障后才继续,并保证共享内存可见性
__threadfence()全局确保此线程之前的所有内存写操作对全局可见
__threadfence_block()Block 内确保此线程之前的写操作对 Block 内其他线程可见
__threadfence_system()系统级跨 GPU/CPU 的可见性保证(Pascal+)
Note

GPU 的弱序模型比 x86 TSO 更弱——x86 至少保证 Store-Store 顺序,而 GPU 连这个都不保证。在 GPU 上写并发代码时,必须显式使用 fence 和 barrier,不能依赖”直觉上的”顺序保证。

九、实战:矩阵乘法优化#

9.1 基础版本#

// 基础矩阵乘法:C = A × B
__global__ void matmul_naive(float* A, float* B, float* C, int N) {
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row < N && col < N) {
float sum = 0.0f;
for (int k = 0; k < N; k++) {
sum += A[row * N + k] * B[k * N + col];
}
C[row * N + col] = sum;
}
}
// 性能:~1 GFLOPS(N=1024)
// 问题:全局内存访问 N 次,每次 ~400 ns

9.2 共享内存优化#

// 使用共享内存的 tiled 矩阵乘法
#define TILE_SIZE 16
__global__ void matmul_tiled(float* A, float* B, float* C, int N) {
__shared__ float As[TILE_SIZE][TILE_SIZE];
__shared__ float Bs[TILE_SIZE][TILE_SIZE];
int row = blockIdx.y * TILE_SIZE + threadIdx.y;
int col = blockIdx.x * TILE_SIZE + threadIdx.x;
float sum = 0.0f;
for (int t = 0; t < N / TILE_SIZE; t++) {
// 加载 tile 到共享内存
As[threadIdx.y][threadIdx.x] = A[row * N + t * TILE_SIZE + threadIdx.x];
Bs[threadIdx.y][threadIdx.x] = B[(t * TILE_SIZE + threadIdx.y) * N + col];
__syncthreads(); // Block 内同步
// 在共享内存中计算
for (int k = 0; k < TILE_SIZE; k++) {
sum += As[threadIdx.y][k] * Bs[k][threadIdx.x];
}
__syncthreads();
}
C[row * N + col] = sum;
}
// 性能:~50 GFLOPS(N=1024)
// 优化:共享内存减少全局内存访问次数

9.3 性能对比#

版本GFLOPS优化手段
Naive~1
Tiled (共享内存)~50共享内存 + 分块
Tiled + 向量化~100float4 加载
Tensor Core~500WMMA API
cuBLAS~1000官方优化库

十、GPU 性能分析#

10.1 Nsight 工具链#

GPU 程序的性能瓶颈不像 CPU 那样直观——你看到的”慢”可能是内存带宽受限、Occupancy 过低、Warp 分歧,或是指令吞吐不足。NVIDIA 提供了两款互补的分析工具:

工具层级用途适合场景
Nsight Systems系统级时间线视图,看 Kernel/传输/Stream 的时序关系发现传输瓶颈、Stream 未重叠
Nsight ComputeKernel 级指令级剖析,看 SM 利用率、内存吞吐、Occupancy定位具体 Kernel 的瓶颈
# Nsight Systems:宏观时间线分析
nsys profile --stats=true ./my_gpu_app
nsys report report1.qdrep # 生成时间线报告
# Nsight Compute:微观 Kernel 剖析
ncu --set full --target-processes all ./my_gpu_app
ncu --launch-skip 10 --launch-count 1 ./my_gpu_app # 跳过 warmup,只剖析第 11 次

10.2 Roofline 模型#

Roofline 模型将 GPU 性能分析简化为一个二维图:横轴是算术强度(FLOP/Byte),纵轴是可达性能(GFLOPS)。模型的”屋顶”由两个约束构成——内存带宽(左侧斜线)和计算吞吐(右侧平顶)。一个 Kernel 的实测点如果落在屋顶下方,说明还有优化空间。

瓶颈类型算术强度优化方向
内存受限< ~10 FLOP/Byte减少内存访问、提高合并率、使用共享内存
计算受限> ~30 FLOP/Byte使用 Tensor Core、提高指令级并行
延迟受限Occupancy 过低增加 Block 数量、减少寄存器使用
Warning

GPU 程序最常见的错误是”凭直觉优化”——看到 Kernel 慢就加共享内存,实际上瓶颈可能在 PCIe 传输或 Kernel 启动开销。先用 Nsight Systems 定位瓶颈层级,再用 Nsight Compute 深入分析具体 Kernel。

十一、GPU 在后端系统中的应用#

11.1 GPU 加速数据库#

-- GPU 加速的数据库查询
-- BlazingSQL / OmniDB 等项目
-- 传统:CPU 执行聚合
SELECT user_id, SUM(amount)
FROM orders
WHERE created_at >= '2026-01-01'
GROUP BY user_id;
-- 执行时间:~5 秒(1 亿行)
-- GPU 加速:将数据传输到 GPU 执行
-- 1. 数据从磁盘加载到 CPU 内存
-- 2. CPU 内存 → GPU 内存(PCIe,~12 GB/s)
-- 3. GPU 执行聚合(数千核心并行)
-- 4. 结果 GPU 内存 → CPU 内存
-- 执行时间:~0.5 秒(10x 加速)

11.2 GPU 在网络中的应用#

GPU-Direct RDMA:
传统:网卡 → CPU 内存 → GPU 内存(2 次拷贝)
GPU-Direct:网卡 → GPU 内存(0 次额外拷贝)
应用场景:
- 高频交易:市场数据直接到 GPU 进行分析
- 深度学习推理:网络接收数据直接到 GPU 处理
- 视频处理:视频流直接到 GPU 编解码

11.3 GPU 推理服务架构#

现代 LLM 推理服务(如 vLLM、TensorRT-LLM)采用 CPU+GPU 协同架构:CPU 负责请求调度、KV Cache 管理和 Token 采样,GPU 负责模型前向计算。

graph LR subgraph "GPU 推理服务架构" CLIENT["客户端请求"] --> SCHED["CPU 调度器<br/>请求排队/批处理"] SCHED --> PRE["CPU 预处理<br/>Tokenize + Embedding"] PRE --> GPU_FWD["GPU 前向计算<br/>Transformer 层"] GPU_FWD --> POST["CPU 后处理<br/>采样 + 解码"] POST --> CLIENT KV["KV Cache<br/>GPU 显存管理"] --- GPU_FWD end style GPU_FWD fill:#c8e6c9,stroke:#2e7d32 style SCHED fill:#bbdefb,stroke:#1565c0
组件运行位置瓶颈类型
请求调度与批处理CPUCPU 密集(排序、合并)
Tokenize / EmbeddingCPU / GPU内存带宽
Transformer 前向计算GPU计算密集(Tensor Core)
KV Cache 管理GPU 显存内存容量与带宽
Token 采样CPU随机数生成

十二、动手实践#

12.1 完整的 CUDA 向量加法程序#

// vecadd.cu — 完整的 CUDA 程序
#include <stdio.h>
#include <stdlib.h>
__global__ void vecAdd(const float* A, const float* B, float* C, int N) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < N) C[i] = A[i] + B[i];
}
int main() {
int N = 1 << 20; // 1M 元素
size_t bytes = N * sizeof(float);
float *h_A = (float*)malloc(bytes);
float *h_B = (float*)malloc(bytes);
float *h_C = (float*)malloc(bytes);
for (int i = 0; i < N; i++) { h_A[i] = 1.0f; h_B[i] = 2.0f; }
float *d_A, *d_B, *d_C;
cudaMalloc(&d_A, bytes);
cudaMalloc(&d_B, bytes);
cudaMalloc(&d_C, bytes);
cudaMemcpy(d_A, h_A, bytes, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, bytes, cudaMemcpyHostToDevice);
int blockSize = 256;
int numBlocks = (N + blockSize - 1) / blockSize;
vecAdd<<<numBlocks, blockSize>>>(d_A, d_B, d_C, N);
cudaMemcpy(h_C, d_C, bytes, cudaMemcpyDeviceToHost);
printf("h_C[0] = %f (expected 3.0)\n", h_C[0]);
cudaFree(d_A); cudaFree(d_B); cudaFree(d_C);
free(h_A); free(h_B); free(h_C);
return 0;
}

12.2 编译与运行#

# 编译 CUDA 程序
nvcc -O3 -o vecadd vecadd.cu
# 运行
./vecadd
# 输出:h_C[0] = 3.000000 (expected 3.0)
# 使用 Nsight Systems 分析时间线
nsys profile --stats=true ./vecadd
nsys report report1.qdrep
# 使用 Nsight Compute 剖析 Kernel
ncu --set basic ./vecadd
# 关注指标:Memory Throughput、Compute Throughput、Occupancy

12.3 性能剖析#

# 使用 nvprof 快速查看 Kernel 执行时间(旧版工具)
nvprof ./vecadd
# 输出示例:
# GPU activities: 99.3% vecAdd 12.3us
# API calls: 85.1% cudaMalloc 320ms
# 对比不同 Block 大小的性能
for bs in 128 256 512 1024; do
echo "Block size = $bs"
ncu --metrics gpu__time_duration.sum ./vecadd
done

十三、总结#

上一章理解了无锁编程与原子操作。

维度CPUGPU
设计哲学延迟优化吞吐优化
核心数少(4-8)多(数千)
单线程性能
并行吞吐极高
内存带宽~50 GB/s~3000 GB/s
编程模型串行 + 线程SIMT
适用场景通用计算、复杂逻辑大规模并行、矩阵运算
Tip

GPU 不是 CPU 的替代品,而是互补品。CPU 处理复杂逻辑和串行任务,GPU 处理大规模并行任务。现代系统越来越采用 CPU+GPU 协同计算——CPU 负责调度和控制,GPU 负责计算密集型工作。

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

GPU 架构概览
https://blog.souloss.com/posts/cpu-architecture/gpu-architecture/
作者
Souloss
发布于
2026-03-05
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时