【发布时间】:2017-05-15 06:34:00
【问题描述】:
我的 Cuda 程序获得显着的性能提升(平均而言)取决于块的大小和块的数量;其中“线程”的总数保持不变。 (我不确定线程是否是正确的术语......但我将在这里使用它;每个内核的线程总数是(块数)*(块大小))。我做了一些图表来说明我的观点。
但首先请允许我先解释一下我的算法是什么,但是我不确定它的相关性,因为我想这是适用于所有 GPGPU 程序的东西。但也许我我错了。
基本上我会遇到逻辑上被视为二维数组的大型数组,其中每个线程从数组中添加一个元素,并将该值的平方添加到另一个变量,然后最后将值写入另一个数组,在每次读取期间,所有线程都以某种方式移动。这是我的内核代码:
__global__ void MoveoutAndStackCuda(const float* __restrict__ prestackTraces, float* __restrict__ stackTracesOut,
float* __restrict__ powerTracesOut, const int* __restrict__ sampleShift,
const unsigned int samplesPerT, const unsigned int readIns,
const unsigned int readWidth, const unsigned int defaultOffset) {
unsigned int globalId = ((blockIdx.x * blockDim.x) + threadIdx.x); // Global ID of this thread, starting from 0 to total # of threads
unsigned int jobNum = (globalId / readWidth); // Which array within the overall program this thread works on
unsigned int readIndex = (globalId % readWidth) + defaultOffset; // Which sample within the array this thread works on
globalId = (jobNum * samplesPerT) + readIndex; // Incorperate default offset (since default offset will also be the offset of
// index we will be writing to), actual globalID only needed for above two variables.
float stackF = 0.0;
float powerF = 0.0;
for (unsigned int x = 0; x < readIns; x++) {
unsigned int indexRead = x + (jobNum * readIns);
float value = prestackTraces[readIndex + (x * samplesPerT) + sampleShift[indexRead]];
stackF += value;
powerF += (value * value);
}
stackTracesOut[globalId] = stackF;
powerTracesOut[globalId] = powerF;
}
现在是这篇文章的重点,调用这段代码时
MoveoutAndStackCuda<<<threadGroups, threadsPerGroup>>>(*prestackTracesCudaPtr,
*stackTracesOutCudaPtr, *powerTracesOutCudaPtr,
*sampleShiftCudaPtr, samplesPerT, readIns,
readWidth, defaultOffset);
我所做的只是在 >> 中使用不同的 threadGroups 和 threadsPerGroup,其中 threadGroups.x * threadsPerGroup.x 保持不变。 (如前所述,这是一个一维问题)。
我将块大小增加了 64,直到达到 1024。我预计不会有任何变化,因为我认为只要块大小大于 32,我相信这是内核中 ALU 的数量,它就会运行得一样快尽可能。看看我制作的这张图表:
对于这个特定大小,线程总数为 5000 * 5120,例如,如果块大小为 64,则有 ((5000 * 5120) / 64) 个块。 由于某种原因,在 896、768 和 512 块大小时性能显着提升。为什么?
我知道这看起来是随机的,但该图中的每个点都是 50 次测试的平均值!
这是另一个图表,这次是线程总数为 (8000 * 8192) 的时间。这次的提升是 768 和 960。
再举一个例子,这次是针对比其他两个问题更小的作业(总线程数为 2000 * 2048):
事实上,这是我用这些图表制作的专辑,每张图表代表不同大小的问题:graph album。
我正在运行这个Quadro M5000,它有 2048 个 Cuda 核心。我相信每个 Cuda Core 都有 32 个 ALU,所以我假设在任何给定时间可能发生的计算总数是 (2048 * 32)?
那么是什么解释了这些神奇的数字呢?我认为它可能是线程总数除以 cuda 核心数,或除以 (2048 * 32),但到目前为止,我发现与专辑中所有图表的任何内容都没有相关性。我可以做另一项测试来帮助缩小范围吗?我想找出运行这个程序的块大小以获得最佳结果。
我也没有包括它,但我也做了一个测试,块大小从 32 减少了 1,事情变得指数级地变慢。这对我来说很有意义,从那时起,我们每组的本地线程比给定多处理器中的 ALU 少。
【问题讨论】:
-
我没有详细分析您的问题,但我鼓励您使用 CUDA 的分析工具(如 NVIDIA Visual Profiler),因为它们非常好。对于您考虑的各种情况,他们可以准确地告诉您程序的哪个部分更慢/更快。
标签: performance cuda performance-testing gpgpu