首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CUDA中的块缩减

CUDA中的块缩减
EN

Stack Overflow用户
提问于 2014-04-08 21:47:39
回答 3查看 27.5K关注 0票数 14

我正在尝试减少CUDA,我真的是一个新手。我目前正在研究NVIDIA的一个示例代码。

我想我真的不确定如何设置块大小和网格大小,特别是当我的输入数组大于单个块大小(512 X 512)时。

下面是代码。

代码语言:javascript
复制
template <unsigned int blockSize>
__global__ void reduce6(int *g_idata, int *g_odata, unsigned int n)
{
    extern __shared__ int sdata[];
    unsigned int tid = threadIdx.x;
    unsigned int i = blockIdx.x*(blockSize*2) + tid;
    unsigned int gridSize = blockSize*2*gridDim.x;
    sdata[tid] = 0;

    while (i < n) 
    { 
        sdata[tid] += g_idata[i] + g_idata[i+blockSize]; 
        i += gridSize; 
    }

    __syncthreads();

    if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); }
    if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); }
    if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); }

    if (tid < 32) 
    {
        if (blockSize >= 64) sdata[tid] += sdata[tid + 32];
        if (blockSize >= 32) sdata[tid] += sdata[tid + 16];
        if (blockSize >= 16) sdata[tid] += sdata[tid + 8];
        if (blockSize >= 8) sdata[tid] += sdata[tid + 4];
        if (blockSize >= 4) sdata[tid] += sdata[tid + 2];
        if (blockSize >= 2) sdata[tid] += sdata[tid + 1];
    }

    if (tid == 0) g_odata[blockIdx.x] = sdata[0];
}

然而,在我看来,g_odata[blockIdx.x]保存了所有块的部分和,如果我想得到最终结果,我需要对g_odata[blockIdx.x]数组中的所有项求和。

我想知道:有没有一个内核来做整个求和?还是我误解了这里的事情?如果有人能教我这方面的知识,我会非常感激。非常感谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-11-18 21:23:57

为了更好地了解这个主题,您可以查看NVIDIA的this pdf,它以图形方式解释了您在代码中使用的所有策略。

票数 7
EN

Stack Overflow用户

发布于 2014-04-08 21:58:18

你的理解是正确的。缩减表明,here最终以存放在全局内存中的一系列块和结束。

要将所有这些块和加在一起,需要某种形式的全局同步。您必须等到所有块都完成后才能将它们的总和相加。在这一点上,您有许多选项,其中包括:

  1. 在主内核之后启动一个新内核将块和加在一起
  2. 在主机

上添加块和

  1. 使用原子将块和加在一起,在主内核的末尾
  2. 使用类似threadfence reduction的方法将块和加在主内核中。< code >H210
  3. 使用CUDA cooperative groups在内核代码中放置网格范围的同步。对网格范围同步后的块总和求和(可能在一个块中)。

如果你在CUDA标签周围搜索,你可以找到所有这些的例子,以及它们的优缺点的讨论。要查看您发布的主内核是如何用于完全缩减的,请查看parallel reduction sample code

票数 14
EN

Stack Overflow用户

发布于 2015-07-31 01:32:43

Robert Crovella已经回答了这个问题,这个问题主要是关于理解而不是性能。

然而,对于所有遇到这个问题的人,我只想强调一下,CUB提供了块减少功能。下面,我将提供一个简单的工作示例,说明如何使用CUB的BlockReduce

代码语言:javascript
复制
#include <cub/cub.cuh>
#include <cuda.h>

#include "Utilities.cuh"

#include <iostream>

#define BLOCKSIZE   32

const int N = 1024;

/**************************/
/* BLOCK REDUCTION KERNEL */
/**************************/
__global__ void sum(const float * __restrict__ indata, float * __restrict__ outdata) {

    unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;

    // --- Specialize BlockReduce for type float. 
    typedef cub::BlockReduce<float, BLOCKSIZE> BlockReduceT; 

    // --- Allocate temporary storage in shared memory 
    __shared__ typename BlockReduceT::TempStorage temp_storage; 

    float result;
    if(tid < N) result = BlockReduceT(temp_storage).Sum(indata[tid]);

    // --- Update block reduction value
    if(threadIdx.x == 0) outdata[blockIdx.x] = result;

    return;  
}

/********/
/* MAIN */
/********/
int main() {

    // --- Allocate host side space for 
    float *h_data       = (float *)malloc(N * sizeof(float));
    float *h_result     = (float *)malloc((N / BLOCKSIZE) * sizeof(float));

    float *d_data;      gpuErrchk(cudaMalloc(&d_data, N * sizeof(float)));
    float *d_result;    gpuErrchk(cudaMalloc(&d_result, (N / BLOCKSIZE) * sizeof(float)));

    for (int i = 0; i < N; i++) h_data[i] = (float)i;

    gpuErrchk(cudaMemcpy(d_data, h_data, N * sizeof(float), cudaMemcpyHostToDevice));

    sum<<<iDivUp(N, BLOCKSIZE), BLOCKSIZE>>>(d_data, d_result);
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());

    gpuErrchk(cudaMemcpy(h_result, d_result, (N / BLOCKSIZE) * sizeof(float), cudaMemcpyDeviceToHost));

    std::cout << "output: ";
    for(int i = 0; i < (N / BLOCKSIZE); i++) std::cout << h_result[i] << " ";
    std::cout << std::endl;

    gpuErrchk(cudaFree(d_data));
    gpuErrchk(cudaFree(d_result));

    return 0;
}

在本例中,创建了一个长度为N的数组,结果是32个连续元素的和。所以

代码语言:javascript
复制
result[0] = data[0] + ... + data[31];
result[1] = data[32] + ... + data[63];
....
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22939034

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档