我想知道为什么需要在以下循环中使用grid-stride步幅:
for (int i = index; i < ITERATIONS; i =+ stride)
{
C[i] = A[i] + B[i];
}
我们将步幅和索引设置为:
index = blockIdx.x * blockDim.x + threadIdx.x;
stride = blockDim.x * gridDim.x;
调用内核时我们有:
int blockSize = 5;
int ITERATIONS = 20;
int numBlocks = (ITERATIONS + blockSize - 1) / blockSize;
bench<<<numBlocks, blockSize>>>(A, B, C);
因此,当我们启动内核时,我们将拥有blockDim.x = 5和gridDim = 4,并且stride将等于20。
我的观点是,每当使用这种方法时,步幅总是等于或大于计算中元素的数量,因此每次增量循环都会结束。
这就是问题,为什么需要使用循环或步长,为什么不运行索引,像这样?:
index = blockIdx.x * blockDim.x + threadIdx.x;
C[index] = A[index] + B[index];
另一个问题是,在这个特殊情况下,我现在怎样才能同时在我的GPU上运行多少个线程,然后“跳转”到一个非常大的阵列的另一部分(例如2000000)?
答案 0 :(得分:2)
我的观点是,每当使用这种方法时,步幅总是如此 等于或大于计算中的元素数,所以每个 它将会增加循环的时间将结束。
你的理解存在问题。要有效地使用该内核,您只需运行尽可能多的块,以实现设备的最大设备占用率,而不是处理所有数据所需的块数。那些较少的块然后变为“驻留”并且每个线程处理多个输入/输出对。网格跨度还保留了内核可能具有的任何内存合并和缓存一致性属性。
通过这样做,您可以消除调度和淘汰块的开销。通过这样做,简单内核可以获得相当大的效率提升。这种设计模式没有其他原因。