根据经验确定扭曲中有多少个线程

时间:2014-02-04 16:45:29

标签: cuda

是否有可能编写一个CUDA内核,显示warp中有多少线程而不使用任何与warp相关的CUDA设备函数并且不使用基准测试?如果是这样,怎么样?

2 个答案:

答案 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设备上显示以下假设:

  • %clock被定义为无符号32位只读周期计数器,它静默包装并更新每个发布周期
  • warp中的所有线程读取%clock
  • 的相同值
  • 由于warp启动延迟和指令获取同一SM上的warp但不同的warp调度程序无法在同一周期发出warp的第一条指令

块中所有在CC1.0上具有相同时钟时间的线程 - 3.5个设备(将来可能会改变)将具有相同的时钟时间。

解决方案3:使用Nsight VSE或cuda-gdb调试器。扭曲状态视图向您显示确定扭曲尺寸的足够信息。也可以单步执行并查看每个线程的PC地址更改。

解决方案4:使用Nsight VSE,Visual Profiler,nvprof等。启动1个块的内核,每次启动的线程数增加。确定导致warps_launched的线程数从1变为2的时间。