【问题标题】:Cuda reduction in nested for loops嵌套 for 循环中的 Cuda 减少
【发布时间】:2013-07-12 10:47:33
【问题描述】:

我有一个关于 CUDA 减少的问题。

distance 是具有gridSize*numberOfAngles 元素的矩阵,fftData 是具有numberOfAngles*NFFT 元素的矩阵。 grid_magnitude 是我要存储计算结果的结果矩阵,它有 gridSize 元素。

我想计算fftData 中对应于distance 中一个特定值的索引。之后,fftData 中此索引处的值将添加到对应的gridPoint 处的grid_magnitude。

这是我目前的代码:

__global__ void calcBackProjection(cuFloatComplex* fftData, 
                                   cuFloatComplex* grid_magnitude,
                                   float* distance,
                                   int gridSize,
                                   int numberOfAngles,
                                   float rangeBin,
                                   int NFFT)
{
 int gridPointIdx = threadIdx.x + blockIdx.x*blockDim.x;

 while(gridPointIdx < gridSize)
 {
    for(int angleIdx = 0; angleIdx < numberOfAngles; angleIdx++)
    {       
        //find rangeBin in fftData corresponding to distance
        float curDistance = distance[gridPointIdx + angleIdx*gridSize];
        int wantedIdx = floor(curDistance / rangeBin);
        if(wantedIdx < NFFT)
            {                                   
                grid_magnitude[gridPointIdx + angleIdx*gridSize] =  
              addCmplx(fftData[wantedIdx + angleIdx*NFFT], grid_magnitude[gridPointIdx +     
                angleIdx*gridSize]);

            }                   
    }
    gridPointIdx += blockDim.x * gridDim.x;     
 }   
}

gridPointIdx 对于每个线程应该是唯一的,因此每个线程应该在grid_magnitude 的不同位置写入。但似乎这不起作用,因为grid_magnitude 没有任何更改。

我错过了什么?

我没有设法在完全并行的二维索引中做到这一点,也许我应该使用共享内存,但我如何将 grid_magnitude 部分分配给线程使用?

【问题讨论】:

  • 你确定内核已经执行了吗?您是否对所有 CUDA 调用进行了正确的错误检查?
  • 是的,你是对的,但这看起来很奇怪。内核执行后我做了 if ( cudaSuccess != cudaGetLastError() ){ cout
  • 内核启动是异步的,内核执行过程中的错误将在稍后由于某些其他CUDA函数调用而报告。
  • 所以这就是为什么最后一个错误不是cudaSuccess而是0的原因。但是为什么内核崩溃了?
  • 0 表示 cudaSuccess。我不确定内核是否崩溃,我只是说这是一种可能性。能否提供一个完整的代码示例来重现问题?

标签: c++ cuda nested-loops reduction


【解决方案1】:

我稍微更改了代码。

__global__ void calcBackProjection(cuFloatComplex* fftData, cuFloatComplex* grid_magnitude,
float* distance, int gridSize, int numberOfAngles, float rangeBin, int NFFT){
int gridPointIdx = threadIdx.x + blockIdx.x*blockDim.x;
while(gridPointIdx < gridSize){
    for(int angleIdx = 0; angleIdx < numberOfAngles; angleIdx++){       
        float curDistance = distance[gridPointIdx + angleIdx*gridSize];
        int wantedIdx = ceil(curDistance / rangeBin) - 1;
        if(wantedIdx){
            int fftIdx = wantedIdx + angleIdx*NFFT;
            int gridIdx=  gridPointIdx + angleIdx*gridSize;
            if((fftIdx < NFFT*numberOfAngles) && (gridIdx < gridSize*numberOfAngles)){                  
                grid_magnitude[gridIdx] = cuCaddf(fftData[fftIdx], grid_magnitude[gridIdx]);
            }
        }
    }
    gridPointIdx += blockDim.x * gridDim.x;     }}

问题似乎是,变量 curDistance 和 WantIdx 没有被编译器评估。当我想知道这些值时,它会说“在目标位置没有价值”。这似乎是在grid_magnitude[gridIdx] = cuCaddf(fftData[fftIdx], grid_magnitude[gridIdx]); 检测到访问冲突的原因 我查看了有关此问题的其他一些答案,例如 here 和 here,但这些对我帮助不大。

【讨论】:

  • 我不认为你的逻辑是合理的。也许您的意思是变量curDistance 和wantedIdx 被编译器优化,这基本上就是消息“在目标位置没有价值”的意思。由于优化,源代码中变量的范围可能与编译代码中的范围不匹配。这可能会导致您正在观察的消息。但是基于此推断某些事情是错误的可能没有意义。它不会导致“访问冲突”。到目前为止,您似乎跳过了很多关于您的分析的描述。
  • 但是编译器为什么要优化curDistance和wantedIdx呢?两者都用于计算另一个数组的索引,因此读取它们是为了做某事。我知道当我设置一个未使用的变量时,它会得到优化,但这里不应该是这种情况。
  • 内核执行后,cudaPeekError() 和cudaGetLastError() 的结果都是“未知错误”。
  • 这不是使用与否的问题,而是范围的问题。编译器可能仅在代码中实际需要该值时才将值变为存在(即进入确定的寄存器),而在其他时候将该寄存器用于其他用途。如果您在编译器已经释放寄存器以执行其他操作时尝试查询该值,则相关变量不再在范围内并且无法查询。因此,变量的可用性很大程度上取决于您停止代码执行以访问它的时间和地点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-27
相关资源
最近更新 更多