Parallel processing CUDA内核中的无限循环

Parallel processing CUDA内核中的无限循环,parallel-processing,cuda,Parallel Processing,Cuda,我有一个CUDA内核,其中每个线程都遍历一棵树。由于这个原因,我有一个while循环,这个循环一直循环到线程到达一个叶子。在树下的每一步,它都会检查应该挑选哪个孩子跟随 代码如下: __global__ void search(float* centroids, float* features, int featureCount, int *votes) { int tid = threadIdx.x + blockIdx.x * blockDim.x; if(tid <

我有一个CUDA内核,其中每个线程都遍历一棵树。由于这个原因,我有一个while循环,这个循环一直循环到线程到达一个叶子。在树下的每一步,它都会检查应该挑选哪个孩子跟随

代码如下:

__global__ void search(float* centroids, float* features, int featureCount, int *votes)
{
    int tid = threadIdx.x + blockIdx.x * blockDim.x;

    if(tid < featureCount)
    {
        int index = 0;
        while (index < N) 
        {
            votes[tid] = index;
            int childIndex = index * CHILDREN + 1;
            float minValue = FLT_MAX;

            if(childIndex >= (N-CHILDREN)) break;

            for(int i = 0; i < CHILDREN; i++)
            {
                int centroidIndex = childIndex + i;
                float value = distance(centroids, features, centroidIndex, tid);
                if(value < minValue)
                {
                    minValue = value;
                    index = childIndex + i;
                }
            }
        }
        tid += blockDim.x * gridDim.x;
    }
}

__device__ float distance(float* a, float* b, int aIndex, int bIndex)
{
    float sum = 0.0f;
    for(int i = 0; i < FEATURESIZE; i++)
    {
        float val = a[aIndex + i] - b[bIndex + i];
        sum += val * val;
    }

    return sum;
}
\uuuuu全局\uuuuuu无效搜索(浮点*质心、浮点*特征、整数特征计数、整数*投票)
{
int tid=threadIdx.x+blockIdx.x*blockDim.x;
如果(tid<特征计数)
{
int指数=0;
while(指数=(N个孩子))中断;
for(int i=0;i
这段代码进入无限循环。这就是我觉得奇怪的地方。 如果我更改distance方法以返回一个常量,它将起作用(即在树中向左遍历)


我是否错过了CUDA中的一些循环,或者只是有一些隐藏的bug我看不见?因为我不知道代码是如何进入无限循环的。在cUDA C++中,

循环与C++中的语义相同,所以代码中一定有bug。调试它的一种策略是在主机上进行调试

首先,因为您的代码是标量的(例如,它不包含对
\uuuuuu syncthreads
)的调用),所以您可以将其重构为
\uuuuuuuu主机\uuuuuuuuu设备\uuuuuu
函数

distance
不包含CUDA特定的标识符或函数,因此您只需在
\uuuuu主机\uuuuuu
前面加上前缀即可:

__host__ __device__ float distance(float* a, float* b, int aIndex, int bIndex);
要重构
搜索
功能,请将
tid
(取决于CUDA特定标识符
threadIndex
等)从其外部提升为一个参数,并使其成为
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu主机
功能:

__host__ __device__ void search(int tid, float* centroids, float* features, int featureCount, int *votes)
{
  if(tid < featureCount)
  {
    int index = 0;
    while (index < N) 
    {
      votes[tid] = index;
      int childIndex = index * CHILDREN + 1;
      float minValue = FLT_MAX;

      if(childIndex >= (N-CHILDREN)) break;

      for(int i = 0; i < CHILDREN; i++)
      {
        int centroidIndex = childIndex + i;
        float value = distance(centroids, features, centroidIndex, tid);
        if(value < minValue)
        {
          minValue = value;
          index = childIndex + i;
        }
      }
    }
  }
}
由于
search
现在是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

for(int tid = 0; tid < featureCount; ++tid)
{
  search(tid, centroids, features, featureCount, votes);
}
for(int-tid=0;tid
它应该像在设备上一样挂在主机上。将一个
printf
粘贴到内部,以查找位置。当然,您需要确保创建阵列的主机端副本,例如
质心
,因为主机无法取消对设备内存指针的引用


即使
printf
可以从
\uuuu device\uuuu
函数与较新硬件一起使用,您可能更喜欢这种方法的原因是,从内核调用
printf
直到内核退役后才会提交。如果内核永远不会退役(显然它不在你的情况下),那么你的调试输出永远不会出现在屏幕上。CUDA C++中的

循环与C++中的语义相同,所以代码中一定有bug。调试它的一种策略是在主机上进行调试

首先,因为您的代码是标量的(例如,它不包含对
\uuuuuu syncthreads
)的调用),所以您可以将其重构为
\uuuuuuuu主机\uuuuuuuuu设备\uuuuuu
函数

distance
不包含CUDA特定的标识符或函数,因此您只需在
\uuuuu主机\uuuuuu
前面加上前缀即可:

__host__ __device__ float distance(float* a, float* b, int aIndex, int bIndex);
要重构
搜索
功能,请将
tid
(取决于CUDA特定标识符
threadIndex
等)从其外部提升为一个参数,并使其成为
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu主机
功能:

__host__ __device__ void search(int tid, float* centroids, float* features, int featureCount, int *votes)
{
  if(tid < featureCount)
  {
    int index = 0;
    while (index < N) 
    {
      votes[tid] = index;
      int childIndex = index * CHILDREN + 1;
      float minValue = FLT_MAX;

      if(childIndex >= (N-CHILDREN)) break;

      for(int i = 0; i < CHILDREN; i++)
      {
        int centroidIndex = childIndex + i;
        float value = distance(centroids, features, centroidIndex, tid);
        if(value < minValue)
        {
          minValue = value;
          index = childIndex + i;
        }
      }
    }
  }
}
由于
search
现在是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

for(int tid = 0; tid < featureCount; ++tid)
{
  search(tid, centroids, features, featureCount, votes);
}
for(int-tid=0;tid
它应该像在设备上一样挂在主机上。将一个
printf
粘贴到内部,以查找位置。当然,您需要确保创建阵列的主机端副本,例如
质心
,因为主机无法取消对设备内存指针的引用


即使
printf
可以从
\uuuu device\uuuu
函数与较新硬件一起使用,您可能更喜欢这种方法的原因是,从内核调用
printf
直到内核退役后才会提交。如果内核从未失效(在您的情况下显然不会失效)然后,您的调试输出将永远不会出现在屏幕上。

有一个隐藏的错误:)您可以尝试通过在主机上执行此代码并检查哪个
tid
导致无限循环来调试此代码。在主机上执行并检查哪个tid导致无限循环是什么意思?我只能从设备代码中获取tid:)我已尝试使用“cuPrintf”来自nvidea,但我不确定我是否可以信任它。有一个隐藏的错误:)您可以通过在主机上执行此代码并检查哪个
tid
导致无限循环来尝试调试此代码。您在主机上执行并检查哪个tid导致无限循环是什么意思?我只能从设备代码中获取tid:)我已经尝试使用nvidea的“cuPrintf”,但我不确定我是否可以信任它。谢谢!我没有意识到这一点。这将有助于调试我想:)谢谢!我没有意识到这一点。这将有助于调试,我认为:)