CUDA:while循环索引的正确性

时间:2012-04-12 12:34:38

标签: optimization cuda while-loop

这个内核正在做正确的事情,给我正确的结果。如果我想提高性能,我的问题更多的是while循环的正确性。我尝试了几种块和线程的配置但是如果我要更改它们,while循环将不会给我正确的结果。 我改变内核配置的结果是firstArray和secondArray不会被完全填充(它们在单元格内部会有0)。必须使用从 if循环获得的curValue填充两个数组。

欢迎任何建议:)

提前谢谢

#define N 65536

__global__ void whileLoop(int* firstArray_device, int* secondArray_device)
{   
    int curValue = 0;
    int curIndex = 1;

    int i = (threadIdx.x)+2;

    while(i < N) {
        if (i % curIndex == 0) {
            curValue = curValue + curIndex;
            curIndex *= 2;
        }
        firstArray_device[i] = curValue;
        secondArray_device[i] = curValue;
        i += blockDim.x * gridDim.x;
    }
}

int main(){

  firstArray_host[0] = 0;
  firstArray_host[1] = 1;

  secondArray_host[0] = 0;
  secondArray_host[1] = 1;


  // memory allocation + copy on GPU

  // definition number of blocks and threads
  dim3 dimBlock(1, 1);
  dim3 dimGrid(1, 1);

  whileLoop<<<dimGrid, dimBlock>>>(firstArray_device, secondArray_device);

  // copy back to CPU + free memory
}

3 个答案:

答案 0 :(得分:3)

这里存在数据依赖性问题,这会阻碍您进行一些有意义的优化。变量curValue和curIndex在while循环中更改并前馈到下一次运行。只要您尝试优化循环,您就会发现在这些变量具有不同状态并且结果发生变化的情况下。

我真的不知道你试图实现什么,但是尝试使while循环不受前一次循环运行的值的影响,以避免依赖。尝试将数据分成线程和数据块,以便在环境状态(如threadIdx,blockDim,gridDim ......)上计算indizes和值。

还尝试避免条件循环。最好使用具有恒定运行次数的循环。这也更容易优化。

答案 1 :(得分:1)

一些事情:

  1. 您遗漏了用于在其上声明全局数组的代码 设备。获得此信息会很有帮助。
  2. 你的算法是 使用多个块时不是线程安全的。换句话说,如果你正在运行多个 块,他们不仅会做多余的工作(因此给予 你没有收获),但他们也可能在某些时候尝试写 到相同的全局内存位置,创建错误。
  3. 您的代码就是这样 当只使用一个块时更正,但这使得它毫无意义......您正在并行设备上运行串行或轻度线程操作。您无法运行所有可用资源(多个SMP上的多个块没有内存冲突(见下文)...
  4. 目前,从平行的角度来看,此代码存在两个主要问题:

    1. int i = (threadIdx.x)+2; ...为a生成2的起始索引 单线程;对于单个块中的两个线程,23,依此类推。我怀疑这是 您想要的前两个位置(01)永远不会得到 解决。 (请记住,数组从C中的索引0开始。)

    2. 此外,如果您包含多个块(比如2个块) 每个都有一个线程)然后你会有多个重复的索引 (例如,对于2 b x 1 t - >索引b1t1:2,b1t2:2),当您使用索引时 写入全局内存会产生冲突和错误。执行int i = threadIdx.x + blockDim.x * blockIdx.x;之类的操作将是正确计算索引的典型方法,以避免出现此问题。

    3. 您 最终表达式i += blockDim.x * gridDim.x;没问题,因为它 为i添加一个等于线程总数的数字 不会造成额外的冲突或重叠。

    4. 为什么要使用GPU来重排内存并进行简单的计算?当您考虑将阵列带入和拔出设备的时间时,您可能看不到快速CPU的速度。
    5. 如果您愿意,可以解决问题1和问题2,但除此之外,请考虑您的总体目标以及您尝试优化的算法类型,并提出更加并行友好的解决方案 - 或者考虑GPU计算是否真的使用感觉你的问题。

答案 2 :(得分:1)

要并行化此算法,您需要提供一个公式,该公式可以直接计算数组中给定索引的值。因此,选择数组范围内的随机索引,然后考虑确定该位置的值的因素。找到公式后,通过将随机索引的输出值与串行算法中的计算值进行比较来测试它。如果这是正确的,那么创建一个内核,通过根据它的线程和块索引选择唯一索引来开始。然后计算该索引的值并将其存储在数组中的相应索引中。

一个简单的例子:

串行:

__global__ void serial(int* array)
{
  int j(0);
  for (int i(0); i < 1024; ++i) {
    array[i] = j;
    j += 5;
}

int main() {
  dim3 dimBlock(1);
  dim3 dimGrid(1);
  serial<<<dimGrid, dimBlock>>>(array);
}

并行:

__global__ void parallel(int* array)
{
  int i(threadIdx.x + blockDim.x * blockIdx.x);
  int j(i * 5);
  array[i] = j;
}

int main(){
  dim3 dimBlock(256);
  dim3 dimGrid(1024 / 256);
  parallel<<<dimGrid, dimBlock>>>(array);
}