我有一个简单的CUDA内核,它可以通过基本缩减来进行向量累积。我正在扩展它以通过将其分成多个块来处理更大的数据。但是,我关于分配内核使用的适当数量的共享内存的假设是非法内存访问失败。当我增加这个限制时它会消失,但我想知道原因。 这是我正在谈论的代码:
CORE KERNEL:
__global__ static
void vec_add(int *buffer,
int numElem, // The actual number of elements
int numIntermediates) // The next power of two of numElem
{
extern __shared__ unsigned int interim[];
int index = blockDim.x * blockIdx.x + threadIdx.x;
// Copy global intermediate values into shared memory.
interim[threadIdx.x] =
(index < numElem) ? buffer[index] : 0;
__syncthreads();
// numIntermediates2 *must* be a power of two!
for (unsigned int s = numIntermediates / 2; s > 0; s >>= 1) {
if (threadIdx.x < s) {
interim[threadIdx.x] += interim[threadIdx.x + s];
}
__syncthreads();
}
if (threadIdx.x == 0) {
buffer[blockIdx.x] = interim[0];
}
}
这是来电者:
void accumulate (int* buffer, int numElem)
{
unsigned int numReductionThreads =
nextPowerOfTwo(numElem); // A routine to return the next higher power of 2.
const unsigned int maxThreadsPerBlock = 1024; // deviceProp.maxThreadsPerBlock
unsigned int numThreadsPerBlock, numReductionBlocks, reductionBlockSharedDataSize;
while (numReductionThreads > 1) {
numThreadsPerBlock = numReductionThreads < maxThreadsPerBlock ?
numReductionThreads : maxThreadsPerBlock;
numReductionBlocks = (numReductionThreads + numThreadsPerBlock - 1) / numThreadsPerBlock;
reductionBlockSharedDataSize = numThreadsPerBlock * sizeof(unsigned int);
vec_add <<< numReductionBlocks, numThreadsPerBlock, reductionBlockSharedDataSize >>>
(buffer, numElem, numReductionThreads);
numReductionThreads = nextPowerOfTwo(numReductionBlocks);
}
}
我在GPU上使用1152个元素的示例集尝试了此代码,其配置如下: 类型:Quadro 600 MaxThreadsPerBlock:1024 MaxSharedMemory:48KB
输出:
Loop 1: numElem = 1152, numReductionThreads = 2048, numReductionBlocks = 2, numThreadsPerBlock = 1024, reductionBlockSharedDataSize = 4096
Loop 2: numElem = 1152, numReductionThreads = 2, numReductionBlocks = 1, numThreadsPerBlock = 2, reductionBlockSharedDataSize = 8
CUDA Error 77: an illegal memory access was encountered
怀疑我的临时&#39;共享内存导致非法内存访问,我在以下行中任意增加共享内存两次:
reductionBlockSharedDataSize = 2 * numThreadsPerBlock * sizeof(unsigned int);
我的内核工作正常!
我不明白的是 - 为什么我必须提供这个额外的共享内存才能让我的问题消失(暂时)。
作为检查这个神奇数字的进一步实验,我用更大的数据集运行了我的代码6912点。这一次,即使是2X或4X也没有帮助我。
Loop 1: numElem = 6912, numReductionThreads = 8192, numReductionBlocks = 8, numThreadsPerBlock = 1024, reductionBlockSharedDataSize = 16384
Loop 2: numElem = 6912, numReductionThreads = 8, numReductionBlocks = 1, numThreadsPerBlock = 8, reductionBlockSharedDataSize = 128
CUDA Error 77: an illegal memory access was encountered
但是当我将共享内存大小增加8倍时,问题又消失了。
当然,我不能随意为更大和更大的数据集选择这个缩放因子,因为我很快就会耗尽48KB的共享内存限制。所以我想知道解决问题的合法方法。
答案 0 :(得分:1)
感谢@havogt指出了索引之外的访问权限。 问题是我使用了错误的参数作为vec_add方法的numIntermediates。目的是让内核在与线程数完全相同的数据点上运行,这应该始终为1024。 我使用numThreadsPerBlock作为参数来修复它:
{{1}}