【发布时间】:2012-02-18 15:51:59
【问题描述】:
我在 GPU 上实现了一个字符串匹配算法。与算法的顺序版本相比,并行版本的搜索时间已大大减少,但通过使用不同数量的块和线程,我得到不同的结果。 如何确定块数和线程数以获得最佳结果?
【问题讨论】:
-
“使用不同数量的块和线程我得到不同的结果”是什么意思?你是说性能不同,还是说代码不行?
我在 GPU 上实现了一个字符串匹配算法。与算法的顺序版本相比,并行版本的搜索时间已大大减少,但通过使用不同数量的块和线程,我得到不同的结果。 如何确定块数和线程数以获得最佳结果?
【问题讨论】:
我认为这个问题即使不是不可能也很难回答,因为它实际上取决于算法及其运行方式。由于我看不到你的实现,我可以给你一些线索:
不要使用全局内存并检查如何最大限度地使用共享内存。大致了解线程如何访问内存以及如何检索数据等。
了解您的经线是如何运作的。有时,如果您在线程和数据之间存在 1 对 1 映射,warp 中的线程可能会等待其他线程完成。因此,您可以将线程映射到多个数据,以便它们保持忙碌状态,而不是这种 1 对 1 映射。
避免曲折中的分歧路径。
我希望它会有所帮助。
【讨论】:
@Chris 积分也很重要,但更多地取决于算法本身。
查看 Cuda 手册,了解有关内存查找的线程对齐。共享内存数组的大小也应该是 16 的倍数。
使用合并的全局内存读取。但根据算法设计,这通常是这种情况,使用共享内存会有所帮助。
尽可能不要在全局内存中使用原子操作,或者根本不要使用。他们很慢。一些使用原子操作的算法可以使用不同的技术重写。
没有显示的代码,没有人可以告诉您什么是最好的或性能变化的原因。
内核中每个块的线程数是最重要的值。
计算该值的重要值是:
您的算法应该可以在所有 GPU 达到 100% 占用率时进行扩展。为此,我为自己创建了一个辅助类,它自动检测所用 GPU 的最佳线程数,并将其作为 DEFINE 传递给内核。
/**
* Number of Threads in a Block
*
* Maximum number of resident blocks per multiprocessor : 8
*
* ///////////////////
* Compute capability:
* ///////////////////
*
* Cuda [1.0 - 1.1] =
* Maximum number of resident threads per multiprocessor 768
* Optimal Usage: 768 / 8 = 96
* Cuda [1.2 - 1.3] =
* Maximum number of resident threads per multiprocessor 1024
* Optimal Usage: 1024 / 8 = 128
* Cuda [2.x] =
* Maximum number of resident threads per multiprocessor 1536
* Optimal Usage: 1536 / 8 = 192
*/
public static int BLOCK_SIZE_DEF = 96;
以 Cuda 1.1 为例,每个 SM 拥有 786 个常驻线程
这在书中也有提及:
大规模并行处理器编程:实践方法(GPU 计算系列的应用)
良好的编程建议:
示例:我的一个与矩阵无关的行向量归一化内核。
/*
* ////////////////////////
* // Compute capability //
* ////////////////////////
*
* Used 12 registers, 540+16 bytes smem, 36 bytes cmem[1]
* Used 10 registers, 540+16 bytes smem, 36 bytes cmem[1] <-- with -maxregcount 10 Limit for Cuda 1.1
* I: Maximum number of Rows = max(x-dim)^max(dimGrid)
* II: Maximum number of Columns = unlimited, since they are loaded in a tile loop
*
* Cuda [1.0 - 1.3]:
* I: 65535^2 = 4.294.836.225
*
* Cuda [2.0]:
* II: 65535^3 = 281.462.092.005.375
*/
【讨论】: