【问题标题】:Calling sum reduction kernel from another kernel从另一个内核调用求和内核
【发布时间】:2011-11-21 02:11:28
【问题描述】:

我正在尝试对内核中的数组进行求和,而无需将数据发送回 CPU 主机,但我没有得到正确的结果。这是我使用的 sum 内核(根据 NVIDIA 提供的稍作修改):

template <class T, unsigned int blockSize, bool nIsPow2>
__device__ void
reduce(T *g_idata, T *g_odata, unsigned int n)
{
    __shared__ T sdata[blockSize];

    // perform first level of reduction,
    // reading from global memory, writing to shared memory
    unsigned int tid = threadIdx.x;
    unsigned int i = blockIdx.x*blockSize*2 + threadIdx.x;
    unsigned int gridSize = blockSize*2*gridDim.x;

    T mySum = 0;

    // we reduce multiple elements per thread.  The number is determined by the 
    // number of active thread blocks (via gridDim).  More blocks will result
    // in a larger gridSize and therefore fewer elements per thread
    while (i < n)
    {         
        mySum += g_idata[i];
        // ensure we don't read out of bounds -- this is optimized away for powerOf2 sized arrays
        if (nIsPow2 || i + blockSize < n) 
            mySum += g_idata[i+blockSize];  
        i += gridSize;
    } 

    // each thread puts its local sum into shared memory 
    sdata[tid] = mySum;
    __syncthreads();


    // do reduction in shared mem
    if (blockSize >= 512) { if (tid < 256) { sdata[tid] = mySum = mySum + sdata[tid + 256]; } __syncthreads(); }
    if (blockSize >= 256) { if (tid < 128) { sdata[tid] = mySum = mySum + sdata[tid + 128]; } __syncthreads(); }
    if (blockSize >= 128) { if (tid <  64) { sdata[tid] = mySum = mySum + sdata[tid +  64]; } __syncthreads(); }

#ifndef __DEVICE_EMULATION__
    if (tid < 32)
#endif
    {
        // now that we are using warp-synchronous programming (below)
        // we need to declare our shared memory volatile so that the compiler
        // doesn't reorder stores to it and induce incorrect behavior.
        volatile T* smem = sdata;
        if (blockSize >=  64) { smem[tid] = mySum = mySum + smem[tid + 32]; EMUSYNC; }
        if (blockSize >=  32) { smem[tid] = mySum = mySum + smem[tid + 16]; EMUSYNC; }
        if (blockSize >=  16) { smem[tid] = mySum = mySum + smem[tid +  8]; EMUSYNC; }
        if (blockSize >=   8) { smem[tid] = mySum = mySum + smem[tid +  4]; EMUSYNC; }
        if (blockSize >=   4) { smem[tid] = mySum = mySum + smem[tid +  2]; EMUSYNC; }
        if (blockSize >=   2) { smem[tid] = mySum = mySum + smem[tid +  1]; EMUSYNC; }
    }

    // write result for this block to global mem 
    if (tid == 0) 
        g_odata[blockIdx.x] = sdata[0];
}

template <unsigned int blockSize>
__global__ void compute(   int *values, int *temp, int *temp2, int* results, unsigned int N, unsigned int M )
{   
    int tdx = threadIdx.x;
    int idx = blockIdx.x * blockDim.x + tdx;

    int val = 0;
    int cpt = 0;

    if( idx < N )
    {
        for( int i = 0; i < M; ++i )
        {

            for( int j = i+1; j < M; ++j )
            {

                val = values[i*N+idx];
                __syncthreads();

                reduce<int, blockSize, false>( temp, temp2, N );
                __syncthreads();

                if( tdx == 0 )
                {

                    val = 0;

                    for( int k=0; k < gridDim.x; ++k )
                    {
                        val += temp2[k];
                        temp2[k] = 0;
                    }


                    results[cpt] = val;
                }

                __syncthreads();
                ++cpt;
            }
        }

    }
}

我错过了什么吗?谢谢!

【问题讨论】:

  • 题外话:你检查过推力吗?
  • 没有。 Thrust 有我可以使用的东西吗?
  • 在我看来,thrust 是一个用于简化主机到设备代码的 API,例如缩减。但是对于给定的迭代,我需要在内核中使用缩减。
  • 不,你只能使用推力来操作设备中的东西。

标签: cuda sum reduction


【解决方案1】:

请记住,您无法同步网格中的块。 Block 1 可能会执行reduce 函数并向 temp2[1] 写入一个值,而 Block2 可能仍在等待并且 temp2[2] 仍然包含一些垃圾。

如果您真的需要,您可以强制执行块同步,但它很笨拙、繁琐且效率不高。考虑一些替代方案:

  • 您可以将一个数组分配给单个块来执行归约;让不同的块对独立的数组执行独立的归约。
  • 您可以将缩减作为单独的内核调用(如在原始 CUDA 示例中),但您可以决定将结果数据传输回主机。相反,您启动另一个内核,然后处理前一个内核的输出。全局内存的内容在内核调用之间保留。

【讨论】:

  • 哇,我没想到网格同步的事情。非常感谢!我一直在进行数据竞赛......
猜你喜欢
  • 2011-12-06
  • 1970-01-01
  • 1970-01-01
  • 2012-11-02
  • 2021-02-07
  • 1970-01-01
  • 2016-01-22
  • 2011-11-04
  • 1970-01-01
相关资源
最近更新 更多