在cuda

时间:2016-03-27 01:54:43

标签: cuda

我想在矢量s.t中构建二叉树。父母的价值将是两个孩子的总和。在C中递归构建树看起来像:

int construct(int elements[], int start, int end, int* tree, int index) {
    if (start == end) {
        tree[index] = elements[start];
        return tree[index];
    }
    int middle = start + (end - start) / 2;
    tree[index] = construct(elements, start, middle, tree, index*2) +
                  construct(elements, middle, end, tree, index*2+1);
    return tree[index];
}

但我不知道如何通过利用线程以并行方式在CUDA中构建它。我觉得有用的一个reference

  

我们应该如何并行化这种递归算法呢?一种方法是使用Garanzha等人提出的方法,该方法从根开始按顺序处理节点的级别。我们的想法是以广度优先的顺序维护不断增长的节点阵列,以便层次结构中的每个级别对应于线性范围的节点。在给定的级别上,我们为落入此范围的每个节点启动一个线程。该线程首先从节点数组中读取第一个和最后一个并调用findSplit()。然后,它使用原子计数器将生成的子节点附加到同一节点数组,并写出相应的子范围。这个过程迭代,以便每个级别输出下一级包含的节点,然后在下一轮中处理。

按顺序处理每个级别并并行化每个级别的节点。我认为这是完全有道理的,但我不知道如何完全实现,有人能给我一个关于如何做到这一点的想法或例子吗?

1 个答案:

答案 0 :(得分:1)

我不确定上述索引方案是否有效。

以下是可以使用的示例代码:(尽管树索引可能不适合您的需求):

__global__ void buildtreelevel(const int* elements, int count, int* tree)
{
    int parentcount = (count + 1) >> 1;
    for (int k = threadIdx.x + blockDim.x * blockIdx.x ; k < parentcount ; k += blockDim.x * gridDim.x)
    {
        if ((2*k+1) < count)
            tree[k] = elements[k*2] + elements[k*2+1] ;
        else
            tree[k] = elements[k*2] ;
    }
}

此功能一次只处理一个树级别。整体树大小由以下提供:

int treesize (int count, int& maxlevel)
{
    int res = 1 ;
    while (count > 1)
    {
        count = (count + 1) >> 1 ;
        res += count ;
        ++maxlevel;
    }
    return res ;
}

构建整个树需要多次调用buildtreelevel内核:

int buildtree (int grid, int block, const int* d_elements, int count, int** h_tree, int* d_data)
{
    const int* ptr_elements = d_elements ;
    int* ptr_data = d_data ;
    int level = 0 ;
    int levelcount = count ;
    while (levelcount > 1)
    {
        buildtreelevel <<< grid, block >>> (ptr_elements, levelcount, ptr_data) ;
        levelcount = (levelcount + 1) >> 1 ;

        h_tree [level++] = ptr_data ;
        ptr_elements = ptr_data ;
        ptr_data += levelcount ;
    }
    return level ;
}

同步只需要在最后发生,因为所有内核都在流0上执行。

int main()
{
    int nElements = 10000000 ;
    int* d_elements ;
    int* d_data ;
    int** h_tree ;
    int maxlevel = 1 ;

    cudaMalloc ((void**)&d_elements, nElements * sizeof (int)) ;
    cudaMalloc ((void**)&d_data, treesize(nElements, maxlevel) * sizeof (int)) ;

    h_tree = new int*[maxlevel];

    buildtree (64, 256, d_elements, nElements, h_tree, d_data) ;

    cudaError_t res = cudaDeviceSynchronize() ;
    if (cudaSuccess != res)
        fprintf (stderr, "ERROR (%d) : %s \n", res, cudaGetErrorString(res));
    cudaDeviceReset();
}

您的树结构存储在h_tree中,h_tree是设备指针的主机数组。

这不是最佳选择,但可能是一个好的开始(使用带有__ldg的对齐int4)并且一次处理4个级别可能会提高性能。