CUDA 进阶核心机制笔记 + C++示例代码(第五章重点)
一、核心笔记(整合前五章核心)
1. 线程、块、网格深度解析
核心层级与多维配置
-
线程(Thread):最小执行单元,拥有独立寄存器和局部内存;支持 1D/2D/3D ID(
threadIdx.x/y/z),适配矩阵、图像等多维数据。 -
块(Block):线程的集合(最大 1024 线程/块),支持 1D/2D/3D 组织(
blockIdx.x/y/z);块内线程可通过共享内存通信,通过`__syncthreads()`同步。 -
网格(Grid):块的集合,支持 1D/2D/3D 组织(
gridDim.x/y/z);块间无共享内存,执行顺序无序。 -
关键硬件概念:
-
Warp(线程束):硬件层面的线程组(32 个线程),同一 warp 执行相同指令,分支会导致线程闲置。
-
Occupancy(占用率):SM 上活跃 warp 数与最大支持 warp 数的比值,合理配置块大小可提升占用率,掩盖内存延迟。
-
全局索引计算(核心映射逻辑)
| 维度 | 全局索引公式 | 适用场景 |
|---|---|---|
1D |
|
向量运算 |
2D |
|
矩阵运算、图像像素处理 |
3D |
|
3D 模型渲染、体积数据处理 |
2. 异步数据传输(突破传输瓶颈)
3. CUDA 流(Streams):并行化执行流程
核心概念
-
流是 GPU 任务的队列(内核执行、数据传输),按入队顺序串行执行,不同流可并行。
-
默认流(Stream 0):同步流,所有操作串行执行,简化编程但限制性能。
-
非默认流:异步流,可实现数据传输与计算重叠,需手动创建和管理。
二、C++(CUDA)示例代码
示例 1:2D 线程配置 - 矩阵加法(多维索引映射)
核心功能
演示 2D 块/网格配置,适配矩阵运算的多维索引映射,呼应第五章“多维线程组织”核心知识点。
#include <cuda_runtime.h>
#include <iostream>
#include <vector>
#include <chrono>
using namespace std;
using namespace chrono;
#define CHECK_CUDA_ERR(err) \
if (err != cudaSuccess) { \
cerr << "CUDA错误:" << cudaGetErrorString(err) << "(行号:" << __LINE__ << ")" << endl; \
exit(1); \
}
// 块大小(2D:16x16,总256线程/块,≤1024)
const dim3 BLOCK_DIM(16, 16);
// GPU核函数:2D矩阵加法(2D线程配置)
__global__ void matrixAddGPU(const float* d_A, const float* d_B, float* d_C, int rows, int cols) {
// 2D全局索引(映射到矩阵的行和列)
int row = threadIdx.y + blockIdx.y * blockDim.y; // y维度对应矩阵行
int col = threadIdx.x + blockIdx.x * blockDim.x; // x维度对应矩阵列
// Guard Clause:避免索引越界
if (row < rows && col < cols) {
int idx = row * cols + col; // 矩阵一维索引
d_C[idx] = d_A[idx] + d_B[idx];
}
}
// CPU串行矩阵加法
void matrixAddCPU(const float* h_A, const float* h_B, float* h_C, int rows, int cols) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
int idx = i * cols + j;
h_C[idx] = h_A[idx] + h_B[idx];
}
}
}
int main() {
// 矩阵尺寸(1024x1024,适配16x16块大小)
const int ROWS = 1024;
const int COLS = 1024;
const size_t data_size = ROWS * COLS * sizeof(float);
// 1. 主机内存初始化
vector<float> h_A(ROWS * COLS, 2.3f);
vector<float> h_B(ROWS * COLS, 5.7f);
vector<float> h_C_CPU(ROWS * COLS, 0.0f);
vector<float> h_C_GPU(ROWS * COLS, 0.0f);
// 2. CPU串行计算
auto cpu_start = high_resolution_clock::now();
matrixAddCPU(h_A.data(), h_B.data(), h_C_CPU.data(), ROWS, COLS);
auto cpu_time = duration_cast<milliseconds>(high_resolution_clock::now() - cpu_start).count();
cout << "CPU矩阵加法耗时:" << cpu_time << " ms" << endl;
// 3. GPU并行计算
// 设备内存分配
float *d_A, *d_B, *d_C;
CHECK_CUDA_ERR(cudaMalloc((void**)&d_A, data_size));
CHECK_CUDA_ERR(cudaMalloc((void**)&d_B, data_size));
CHECK_CUDA_ERR(cudaMalloc((void**)&d_C, data_size));
// 2D网格大小计算:ceil(ROWS/BLOCK_DIM.y) × ceil(COLS/BLOCK_DIM.x)
const dim3 GRID_DIM((COLS + BLOCK_DIM.x - 1) / BLOCK_DIM.x,
(ROWS + BLOCK_DIM.y - 1) / BLOCK_DIM.y);
// GPU计时
cudaEvent_t gpu_start, gpu_stop;
CHECK_CUDA_ERR(cudaEventCreate(&gpu_start));
CHECK_CUDA_ERR(cudaEventCreate(&gpu_stop));
CHECK_CUDA_ERR(cudaEventRecord(gpu_start, 0));
// 数据拷贝(主机→设备)
CHECK_CUDA_ERR(cudaMemcpy(d_A, h_A.data(), data_size, cudaMemcpyHostToDevice));
CHECK_CUDA_ERR(cudaMemcpy(d_B, h_B.data(), data_size, cudaMemcpyHostToDevice));
// 启动核函数(2D网格+2D块)
matrixAddGPU<<<GRID_DIM, BLOCK_DIM>>>(d_A, d_B, d_C, ROWS, COLS);
CHECK_CUDA_ERR(cudaGetLastError());
// 数据拷贝(设备→主机)
CHECK_CUDA_ERR(cudaMemcpy(h_C_GPU.data(), d_C, data_size, cudaMemcpyDeviceToHost));
// 计时结束
CHECK_CUDA_ERR(cudaEventRecord(gpu_stop, 0));
CHECK_CUDA_ERR(cudaEventSynchronize(gpu_stop));
float gpu_time;
CHECK_CUDA_ERR(cudaEventElapsedTime(&gpu_time, gpu_start, gpu_stop));
// 4. 结果验证
bool valid = true;
for (int i = 0; i < 10; ++i) { // 验证前10个元素
if (abs(h_C_CPU[i] - h_C_GPU[i]) > 1e-5) {
valid = false;
break;
}
}
// 输出结果
cout << "GPU矩阵加法耗时:" << gpu_time << " ms" << endl;
cout << "结果验证:" << (valid ? "正确" : "错误") << endl;
cout << "GPU加速比:" << (double)cpu_time / gpu_time << "x" << endl;
// 5. 释放资源
CHECK_CUDA_ERR(cudaFree(d_A));
CHECK_CUDA_ERR(cudaFree(d_B));
CHECK_CUDA_ERR(cudaFree(d_C));
CHECK_CUDA_ERR(cudaEventDestroy(gpu_start));
CHECK_CUDA_ERR(cudaEventDestroy(gpu_stop));
return 0;
}
示例 2:流与异步传输 - 数据传输与计算重叠
核心功能
使用非默认流实现“数据传输”与“内核计算”重叠,突破传输瓶颈,呼应第五章“异步优化”核心知识点。
#include <cuda_runtime.h>
#include <iostream>
#include <vector>
#include <chrono>
using namespace std;
using namespace chrono;
#define CHECK_CUDA_ERR(err) \
if (err != cudaSuccess) { \
cerr << "CUDA错误:" << cudaGetErrorString(err) << "(行号:" << __LINE__ << ")" << endl; \
exit(1); \
}
// 块大小
const int THREADS_PER_BLOCK = 256;
// 流数量(根据GPU并发能力调整,消费级GPU建议3-4个)
const int NUM_STREAMS = 4;
// 数据分块大小(总数据量=NUM_STREAMS×BLOCK_SIZE)
const int BLOCK_SIZE = 2'500'000; // 每个流处理250万个float元素(10MB/块)
// GPU核函数:向量加法(单流任务)
__global__ void vectorAddStreamGPU(const float* d_A, const float* d_B, float* d_C, int size) {
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (idx < size) {
d_C[idx] = d_A[idx] + d_B[idx];
}
}
int main() {
const int TOTAL_SIZE = NUM_STREAMS * BLOCK_SIZE;
const size_t total_data_size = TOTAL_SIZE * sizeof(float);
const size_t block_data_size = BLOCK_SIZE * sizeof(float);
// 1. 分配分页锁定内存(提升传输速度,支持异步传输)
float *h_A, *h_B, *h_C;
CHECK_CUDA_ERR(cudaHostAlloc((void**)&h_A, total_data_size, cudaHostAllocDefault));
CHECK_CUDA_ERR(cudaHostAlloc((void**)&h_B, total_data_size, cudaHostAllocDefault));
CHECK_CUDA_ERR(cudaHostAlloc((void**)&h_C, total_data_size, cudaHostAllocDefault));
// 初始化数据
for (int i = 0; i < TOTAL_SIZE; ++i) {
h_A[i] = 1.1f;
h_B[i] = 2.2f;
}
// 2. 设备资源分配(每个流独立的设备内存)
float *d_A[NUM_STREAMS], *d_B[NUM_STREAMS], *d_C[NUM_STREAMS];
cudaStream_t streams[NUM_STREAMS];
for (int i = 0; i < NUM_STREAMS; ++i) {
// 创建非默认流
CHECK_CUDA_ERR(cudaStreamCreate(&streams[i]));
// 分配每个流的设备内存
CHECK_CUDA_ERR(cudaMalloc((void**)&d_A[i], block_data_size));
CHECK_CUDA_ERR(cudaMalloc((void**)&d_B[i], block_data_size));
CHECK_CUDA_ERR(cudaMalloc((void**)&d_C[i], block_data_size));
}
// 3. 流任务执行(异步传输+计算重叠)
cudaEvent_t start, stop;
CHECK_CUDA_ERR(cudaEventCreate(&start));
CHECK_CUDA_ERR(cudaEventCreate(&stop));
CHECK_CUDA_ERR(cudaEventRecord(start, 0));
for (int i = 0; i < NUM_STREAMS; ++i) {
// 计算当前分块的主机内存偏移
int offset = i * BLOCK_SIZE;
// 异步传输:主机→设备(绑定到当前流)
CHECK_CUDA_ERR(cudaMemcpyAsync(d_A[i], h_A + offset, block_data_size,
cudaMemcpyHostToDevice, streams[i]));
CHECK_CUDA_ERR(cudaMemcpyAsync(d_B[i], h_B + offset, block_data_size,
cudaMemcpyHostToDevice, streams[i]));
// 核函数配置
int blocksPerGrid = (BLOCK_SIZE + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
// 异步执行核函数(绑定到当前流,自动等待流内前序传输完成)
vectorAddStreamGPU<<<blocksPerGrid, THREADS_PER_BLOCK, 0, streams[i]>>>(
d_A[i], d_B[i], d_C[i], BLOCK_SIZE);
CHECK_CUDA_ERR(cudaGetLastError());
// 异步传输:设备→主机(绑定到当前流,自动等待核函数完成)
CHECK_CUDA_ERR(cudaMemcpyAsync(h_C + offset, d_C[i], block_data_size,
cudaMemcpyDeviceToHost, streams[i]));
}
// 等待所有流完成
for (int i = 0; i < NUM_STREAMS; ++i) {
CHECK_CUDA_ERR(cudaStreamSynchronize(streams[i]));
}
// 计时结束
CHECK_CUDA_ERR(cudaEventRecord(stop, 0));
CHECK_CUDA_ERR(cudaEventSynchronize(stop));
float total_time;
CHECK_CUDA_ERR(cudaEventElapsedTime(&total_time, start, stop));
// 4. 结果验证
bool valid = true;
for (int i = 0; i < 10; ++i) {
if (abs(h_C[i] - 3.3f) > 1e-5) { // 1.1+2.2=3.3
valid = false;
break;
}
}
// 输出结果
cout << "总数据量:" << TOTAL_SIZE << " 个float元素(" << total_data_size / (1024*1024) << " MB)" << endl;
cout << "流数量:" << NUM_STREAMS << " 个" << endl;
cout << "总耗时(传输+计算):" << total_time << " ms" << endl;
cout << "结果验证:" << (valid ? "正确" : "错误") << endl;
// 5. 释放资源
for (int i = 0; i < NUM_STREAMS; ++i) {
CHECK_CUDA_ERR(cudaFree(d_A[i]));
CHECK_CUDA_ERR(cudaFree(d_B[i]));
CHECK_CUDA_ERR(cudaFree(d_C[i]));
CHECK_CUDA_ERR(cudaStreamDestroy(streams[i]));
}
CHECK_CUDA_ERR(cudaFreeHost(h_A));
CHECK_CUDA_ERR(cudaFreeHost(h_B));
CHECK_CUDA_ERR(cudaFreeHost(h_C));
CHECK_CUDA_ERR(cudaEventDestroy(start));
CHECK_CUDA_ERR(cudaEventDestroy(stop));
return 0;
}
示例 3:共享内存优化 - 矩阵乘法(核心加速示例)
核心功能
使用共享内存预取数据,减少全局内存访问次数,呼应第五章“共享内存是性能加速器”的核心知识点。
#include <cuda_runtime.h>
#include <iostream>
#include <vector>
#include <chrono>
#include <cmath>
using namespace std;
using namespace chrono;
#define CHECK_CUDA_ERR(err) \
if (err != cudaSuccess) { \
cerr << "CUDA错误:" << cudaGetErrorString(err) << "(行号:" << __LINE__ << ")" << endl; \
exit(1); \
}
// 块大小(对应共享内存分块大小,通常设32,适配warp大小)
const int TILE_SIZE = 32;
// 矩阵尺寸(必须是TILE_SIZE的整数倍)
const int MATRIX_SIZE = 1024;
// CPU串行矩阵乘法(A[M×K] × B[K×N] = C[M×N])
void matrixMulCPU(const float* h_A, const float* h_B, float* h_C, int M, int K, int N) {
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
float sum = 0.0f;
for (int k = 0; k < K; ++k) {
sum += h_A[i * K + k] * h_B[k * N + j];
}
h_C[i * N + j] = sum;
}
}
}
// GPU核函数:共享内存优化矩阵乘法(分块计算)
__global__ void matrixMulSharedGPU(const float* d_A, const float* d_B, float* d_C, int M, int K, int N) {
// 共享内存:存储A的分块(tile)和B的分块
__shared__ float shared_A[TILE_SIZE][TILE_SIZE];
__shared__ float shared_B[TILE_SIZE][TILE_SIZE];
// 2D全局索引(映射到C矩阵的行和列)
int row = threadIdx.y + blockIdx.y * blockDim.y;
int col = threadIdx.x + blockIdx.x * blockDim.x;
float result = 0.0f;
// 分块遍历K维度(每次加载一个tile到共享内存)
for (int tile = 0; tile < (K + TILE_SIZE - 1) / TILE_SIZE; ++tile) {
// 加载A的当前tile到共享内存(避免越界)
if (row < M && (tile * TILE_SIZE + threadIdx.x) < K) {
shared_A[threadIdx.y][threadIdx.x] = d_A[row * K + tile * TILE_SIZE + threadIdx.x];
} else {
shared_A[threadIdx.y][threadIdx.x] = 0.0f; // 超出范围填0
}
// 加载B的当前tile到共享内存(避免越界)
if (col < N && (tile * TILE_SIZE + threadIdx.y) < K) {
shared_B[threadIdx.y][threadIdx.x] = d_B[(tile * TILE_SIZE + threadIdx.y) * N + col];
} else {
shared_B[threadIdx.y][threadIdx.x] = 0.0f; // 超出范围填0
}
// 等待所有线程加载完成(共享内存同步)
__syncthreads();
// 计算当前tile的部分和(使用共享内存,避免全局内存访问)
for (int k = 0; k < TILE_SIZE; ++k) {
result += shared_A[threadIdx.y][k] * shared_B[k][threadIdx.x];
}
// 等待所有线程计算完成,避免覆盖共享内存
__syncthreads();
}
// 存储结果到C矩阵
if (row < M && col < N) {
d_C[row * N + col] = result;
}
}
int main() {
const int M = MATRIX_SIZE; // A矩阵行数
const int K = MATRIX_SIZE; // A矩阵列数 = B矩阵行数
const int N = MATRIX_SIZE; // B矩阵列数
const size_t size_A = M * K * sizeof(float);
const size_t size_B = K * N * sizeof(float);
const size_t size_C = M * N * sizeof(float);
// 1. 主机内存初始化
vector<float> h_A(M * K, 1.0f); // A矩阵全1
vector<float> h_B(K * N, 1.0f); // B矩阵全1
vector<float> h_C_CPU(M * N, 0.0f);
vector<float> h_C_GPU(M * N, 0.0f);
// 2. CPU串行计算(耗时较长,耐心等待)
auto cpu_start = high_resolution_clock::now();
matrixMulCPU(h_A.data(), h_B.data(), h_C_CPU.data(), M, K, N);
auto cpu_time = duration_cast<seconds>(high_resolution_clock::now() - cpu_start).count();
cout << "CPU矩阵乘法耗时:" << cpu_time << " s" << endl;
// 3. GPU并行计算(共享内存优化)
float *d_A, *d_B, *d_C;
CHECK_CUDA_ERR(cudaMalloc((void**)&d_A, size_A));
CHECK_CUDA_ERR(cudaMalloc((void**)&d_B, size_B));
CHECK_CUDA_ERR(cudaMalloc((void**)&d_C, size_C));
// 2D块/网格配置
const dim3 BLOCK_DIM(TILE_SIZE, TILE_SIZE);
const dim3 GRID_DIM((N + BLOCK_DIM.x - 1) / BLOCK_DIM.x,
(M + BLOCK_DIM.y - 1) / BLOCK_DIM.y);
// GPU计时
cudaEvent_t gpu_start, gpu_stop;
CHECK_CUDA_ERR(cudaEventCreate(&gpu_start));
CHECK_CUDA_ERR(cudaEventCreate(&gpu_stop));
CHECK_CUDA_ERR(cudaEventRecord(gpu_start, 0));
// 数据拷贝(主机→设备)
CHECK_CUDA_ERR(cudaMemcpy(d_A, h_A.data(), size_A, cudaMemcpyHostToDevice));
CHECK_CUDA_ERR(cudaMemcpy(d_B, h_B.data(), size_B, cudaMemcpyHostToDevice));
// 启动核函数(共享内存优化)
matrixMulSharedGPU<<<GRID_DIM, BLOCK_DIM>>>(d_A, d_B, d_C, M, K, N);
CHECK_CUDA_ERR(cudaGetLastError());
// 数据拷贝(设备→主机)
CHECK_CUDA_ERR(cudaMemcpy(h_C_GPU.data(), d_C, size_C, cudaMemcpyDeviceToHost));
// 计时结束
CHECK_CUDA_ERR(cudaEventRecord(gpu_stop, 0));
CHECK_CUDA_ERR(cudaEventSynchronize(gpu_stop));
float gpu_time_ms;
CHECK_CUDA_ERR(cudaEventElapsedTime(&gpu_time_ms, gpu_start, gpu_stop));
float gpu_time_s = gpu_time_ms / 1000.0f;
// 4. 结果验证(前10个元素,预期值均为MATRIX_SIZE)
bool valid = true;
for (int i = 0; i < 10; ++i) {
if (abs(h_C_CPU[i] - MATRIX_SIZE) > 1e-5 || abs(h_C_GPU[i] - MATRIX_SIZE) > 1e-5) {
valid = false;
break;
}
}
// 输出结果
cout << "GPU矩阵乘法(共享内存优化)耗时:" << gpu_time_s << " s" << endl;
cout << "结果验证:" << (valid ? "正确" : "错误") << endl;
cout << "GPU加速比:" << (double)cpu_time / gpu_time_s << "x" << endl;
// 5. 释放资源
CHECK_CUDA_ERR(cudaFree(d_A));
CHECK_CUDA_ERR(cudaFree(d_B));
CHECK_CUDA_ERR(cudaFree(d_C));
CHECK_CUDA_ERR(cudaEventDestroy(gpu_start));
CHECK_CUDA_ERR(cudaEventDestroy(gpu_stop));
return 0;
}
三、关键说明
1. 代码与知识点关联
-
示例 1(2D 矩阵加法):演示多维线程配置与索引映射,适配矩阵/图像等实际场景,呼应第五章“多维线程组织”;
-
示例 2(流与异步传输):展示非默认流、分页锁定内存的使用,实现传输与计算重叠,解决第五章强调的“传输瓶颈”;
-
示例 3(共享内存矩阵乘法):核心演示共享内存的“数据预取”与“线程同步”,是第五章最关键的性能优化手段,直接突破全局内存访问限制。