是否有可能编写一个CUDA内核,显示warp中有多少线程而不使用任何与warp相关的CUDA设备函数并且不使用基准测试?如果是这样,怎么样?
答案 0 :(得分:2)
既然你指出了一个有原子的解决方案会很有趣,我推进这个作为我认为给出答案的东西,但我不确定它是否是你正在寻找的答案。我承认这在某种程度上是统计性的。我提供此仅仅是因为我发现这个问题很有意思。我不认为这是“正确”的答案,我怀疑有人聪明会想出一个“更好”的答案。但是,这可能会提供一些想法。
为了避免使用任何明确引用warp的东西,我认为有必要关注“隐式”warp-synchronous行为。我最初走的是一条思考如何使用if-then-else结构的路径(它有一些经线同步的含义),但是却对此挣扎并提出了这种方法:
#include <stdio.h>
#define LOOPS 100000
__device__ volatile int test2 = 0;
__device__ int test3 = 32767;
__global__ void kernel(){
for (int i = 0; i < LOOPS; i++){
unsigned long time = clock64();
// while (clock64() < (time + (threadIdx.x * 1000)));
int start = test2;
atomicAdd((int *)&test2, 1);
int end = test2;
int diff = end - start;
atomicMin(&test3, diff);
}
}
int main() {
kernel<<<1, 1024>>>();
int result;
cudaMemcpyFromSymbol(&result, test3, sizeof(int));
printf("result = %d threads\n", result);
return 0;
}
我编译:
nvcc -O3 -arch=sm_20 -o t331 t331.cu
我将其称为“统计”,因为它需要大量的迭代(LOOPS
)来产生正确的估计(32)。随着迭代次数的减少,“估计值”会增加。
我们可以通过取消注释内核中注释掉的行来应用额外的warp-synchronous杠杆。对于我的测试用例*,如果该行未注释,即使LOOPS
= 1
*我的测试用例是CUDA 5,Quadro5000,RHEL 5.5
答案 1 :(得分:2)
以下是几个简单的解决方案。还有其他解决方案使用warp同步编程;但是,许多解决方案无法在所有设备上运行。
解决方案1:启动一个或多个具有每个块最大线程数的块,读取特殊寄存器%smid和%warpid,以及blockIdx并将值写入内存。通过三个变量分组数据来查找warp大小。如果将启动限制为单个块然后只需要%warpid,则更容易。
解决方案2:启动一个块,每个块具有最大线程数,并读取特殊寄存器%clock。这需要在CC 1.0-3.5设备上显示以下假设:
块中所有在CC1.0上具有相同时钟时间的线程 - 3.5个设备(将来可能会改变)将具有相同的时钟时间。
解决方案3:使用Nsight VSE或cuda-gdb调试器。扭曲状态视图向您显示确定扭曲尺寸的足够信息。也可以单步执行并查看每个线程的PC地址更改。
解决方案4:使用Nsight VSE,Visual Profiler,nvprof等。启动1个块的内核,每次启动的线程数增加。确定导致warps_launched的线程数从1变为2的时间。