是否可以在CUDA设备上定义全局内存阵列?

时间:2013-04-14 12:26:12

标签: memory-management cuda

我要分配一个cuda全局内存数组。我有总结的核心:

__device__ float R_d = 0;
__global__ void perform_summation(float* A, int N){
    int idx = blockDim.x*blockIdx.x+threadIdx.x;
    extern __shared__ float sharedArray [];
    float result[]; //THIS IS THE THING i TRIED TO CREATE
    if(idx < N){
        sharedArray[threadIdx.x] = A[idx];
        //  }else{
        //      sharedArray[threadIdx.x] = 0 ;
        //  }

        for (unsigned int stride = 1; stride < blockDim.x; stride *= 2) {
            __syncthreads();
            if(threadIdx.x % (2*stride) == 0){
                sharedArray[threadIdx.x]+=sharedArray[threadIdx.x+stride];
            }
        }
    }
    if(idx % blockDim.x == 0){
//      R_d += sharedArray[threadIdx.x];
        result[blockIdx.x] = sharedArray[threadIdx.x];
    }
    for (int i = 0; i < gridDim.x; ++i) {
        R_d += result[i];
    }
}

总结y内核采用数组并通过map reduce方法找到元素的总和。每个块将相关元素放入共享内存并对内部的所有数据求和,而不是将结果放入我尝试创建的全局数组中。在决赛中,我将总结全局数组的所有数字以找到最后的答案。

作为第一种方法,我没有使用全局数组来收集每个块的结果,我只是将块的结果加到变量R_d中,但它不起作用,只显示来自最后一块作为结果。我想因为我没有同步。块之间的最后一个块会覆盖最后的所有值。这是我在内核结束时第一次尝试所做的事情

f(idx < N){
        sharedArray[threadIdx.x] = A[idx];
        //  }else{
        //      sharedArray[threadIdx.x] = 0 ;
        //  }

        for (unsigned int stride = 1; stride < blockDim.x; stride *= 2) {
            __syncthreads();
            if(threadIdx.x % (2*stride) == 0){
                sharedArray[threadIdx.x]+=sharedArray[threadIdx.x+stride];
            }
        }

        if(threadIdx.x == 0){
            R_d += sharedArray[threadIdx.x];
        }
    }

所以我实际上有两个问题。如何在设备内存中为我提出的第一个解决方案定义全局内存数组,对于仅使用R_d变量的第二个解决方案是否有任何解决方案?

1 个答案:

答案 0 :(得分:1)

您可以通过cudaMalloc:

在全局设备内存中分配数组
cudaMalloc((void **)&ptr, size);

但你不想在内核中执行此操作,在调用内核并将指针传递给内核之前,请执行此操作。

关于减少,请看these nVidia slides,它解释得很好。基本上,它取决于您使用的块和线程数。可以说有几个街区。因此,在共享内存中定义一个数组:

__shared__ float cache[BLOCK_THREADS];

为每个块分配共享内存,因此我们将每个块中的值与cache中的第一个元素相加。

__syncthreads();

int step = (BLOCK_THREADS >> 1); //the same result as BLOCK_THREADS/2
while(step > 0) {
    if (threadInBlock < step) {
        cache[threadInBlock] += cache[threadInBlock + step];
    }
    __syncthreads();
    step = (step >> 1);
}

因此,这将每个块中的所有元素加总为cache[0]。现在我们可以再次使用简化,或者我们可以将每个块的所有总和与原子操作相加。如果块数明显少于每个块的线程数,那就没问题。

__syncthreads();
if (threadInBlock == 0) {
    atomicAdd(result, cache[0]);
}   

请注意,result是指向全局内存中单个值的指针。另请注意,这仅在BLOCK_THREADS为2的幂时才有效 - 这很常见,因为每个块的线程数应为32的倍数(与warp对齐)。