CUDA Warp 解释(3D Grid / Block)
示例配置
cpp
dim3 grid_size(2, 3, 4);
dim3 block_size(4, 8, 4);
kernel<<<grid_size, block_size>>>();
1. Block 内线程数量
每个 block 的线程数:
4 × 8 × 4 = 128
warp 大小:
32 threads
所以:
128 / 32 = 4 个 warp
2. 关键结论
该配置 符合 warp=32 的要求,因为:
- block 内线程总数是 32 的整数倍
- 没有残缺 warp
- 每个 block 正好 4 个完整 warp
3. 线程线性展开
CUDA 会把 3D thread 展平成一维:
linear_tid = tz * (blockDim.x * blockDim.y)
+ ty * blockDim.x
+ tx
在本例中:
blockDim.x = 4
blockDim.y = 8
blockDim.z = 4
blockDim.x * blockDim.y = 32
所以:
linear_tid = tz * 32 + ty * 4 + tx
4. warp 划分
warp 计算方式:
warp_id = linear_tid / 32
由于每个 z 层正好有 32 个线程:
- tz = 0 → warp 0
- tz = 1 → warp 1
- tz = 2 → warp 2
- tz = 3 → warp 3
关键点
每一个 z 层就是一个 warp
这是因为:
blockDim.x × blockDim.y = 32
5. grid 层统计
grid:
2 × 3 × 4 = 24 个 block
线程总数:
24 × 128 = 3072
warp 总数:
24 × 4 = 96
6. 为什么这个结构很好
- 完全对齐 warp(没有浪费)
- 结构清晰,易理解
- 每个 z 层就是一个 warp(非常直观)
7. 重要提醒
warp 对齐 ≠ 高性能
性能还取决于:
- 内存访问是否连续(coalescing)
- shared memory 访问
- bank conflict
- register 使用
- occupancy
8. 总结
cpp
dim3 block_size(4, 8, 4);
这个配置:
- 128 个线程
- 4 个 warp
- 每个 z 层对应一个 warp
是一个结构非常规整的 CUDA 示例,非常适合理解执行模型。
#include <stdio.h>
#include <cuda_runtime.h>
__global__ void hello_warp_3d()
{
int bx = blockIdx.x;
int by = blockIdx.y;
int bz = blockIdx.z;
int tx = threadIdx.x;
int ty = threadIdx.y;
int tz = threadIdx.z;
int bdx = blockDim.x;
int bdy = blockDim.y;
int bdz = blockDim.z;
// 3D thread 坐标压平成线性 thread id
int linear_tid = tz * (bdx * bdy) + ty * bdx + tx;
// warp 信息
int warp_id_in_block = linear_tid / 32;
int lane_id = linear_tid % 32;
printf("Block(%d,%d,%d) Thread(%d,%d,%d) linear_tid=%d warp_id=%d lane_id=%d\n",
bx, by, bz,
tx, ty, tz,
linear_tid, warp_id_in_block, lane_id);
}
int main()
{
dim3 grid_size(2, 3, 4);
dim3 block_size(4, 8, 4);
hello_warp_3d<<<grid_size, block_size>>>();
cudaError_t err = cudaDeviceSynchronize();
if (err != cudaSuccess) {
printf("CUDA error: %s\n", cudaGetErrorString(err));
return 1;
}
return 0;
}