我按照教科书“专业CUDA C编程”中的翘曲发散示例(以下代码)。
__global__ void math_kernel1(float *c) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
float a, b;
a = b = 0.f;
if (tid % 2 == 0) {
a = 100.0f;
} else {
b = 200.0f;
}
c[tid] = a + b;
}
__global__ void math_kernel2(float *c) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
float a, b;
a = b = 0.f;
if ((tid / warpSize) % 2 == 0) {
a = 100.0f;
} else {
b = 200.0f;
}
c[tid] = a + b;
}
__global__ void math_kernel3(float *c) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
float a, b;
bool ipred = (tid % 2 == 0);
a = b = 0.f;
if (ipred) {
a = 100.0f;
}
if (!ipred) {
b = 200.0f;
}
c[tid] = a + b;
}
显然(并且写在教科书上),math_kernel2
应该有最好的分支效率,math_kernel1
遵循并math_kernel3
有最差的结果。然而,nvprof
报告给我的结果与教科书相矛盾。我使用 CUDA 8.0 在 GTX 1080 Ti 上对这些内核进行了基准测试(我还添加了编译器标志-g -G
以nvcc
禁用优化),它报告了以下分支效率:
- 数学内核1 83.33%
- 数学内核2 100.00%
- math_kernel3 100.00%(预计小于math_kernel1,教科书上是71.43%)