线程&阻止配置要求

时间:2012-09-26 02:28:08

标签: cuda

我正在开发一个程序,我在其中调用一个输入随机二进制数的函数。 总数将在运行时提供,例如:1000或10,00,000 .. 在生成随机数后,我需要使用COUNTERS计算0的总数和1的总数。 我有以下疑问:

  1. 多少线程,块和&我应该分配哪些网格?
  2. 我是否需要2D线程,或者它只适用于1D线程?
  3. 函数线程将在其中执行,我觉得应该检查特定值是1还是0这听起来不错吗?
  4. 我应该如何使用warp或tile方法?

1 个答案:

答案 0 :(得分:2)

我猜这可能是一个家庭作业问题,特别是基于你在SO上发布的唯一其他问题。

  1. 多少线程/块/网格?这个问题的答案取决于你的线程策略。每个线程会做什么?对于产生大量输出的问题,如图像处理或矩阵乘法,常见的线程策略是分配每个线程来完成工作以创建一个输出点。但是这个问题只会产生少量的输出值(似乎是2),并且存在一系列问题,包括减少,流压缩和直方图。这些问题通常分两步解决(可能是2个内核......),一个共同的线程策略(至少对于第一步或内核)是为每个输入点分配一个线程。但另见下面2的答案。一旦你知道你需要多少线程,通常每个块选择一些线程,如256或512(绝对使用2的幂),然后创建足够的块,使每块的线程数乘以块的数量等于或大于问题大小(在这种情况下是输入点的数量)。
  2. 2D还是1D?你的问题本质上不是2D,所以一维线程是一个合理的起点。但是,在一维线程网格中,您可以在网格中创建的最大线程数限制为您正在使用的GPU的最大网格X维度,乘以每个块的线程数。这些数字通常类似于65535和1024,因此在输入点的大约64M元素之后,您将耗尽线程。此时转换为使用2D网格结构并不难,这会将可能的线程数增加到大于GPU可以同时处理的大小。然而,另一种策略而不是切换到线程块的2D网格是保留一维线程块网格,但让每个线程处理多个输入点/元素,可能使用内核代码中的循环。例如,如果您的循环最多可以处理512个元素,那么65535x1024x512应该可以覆盖您的问题大小。对于这类问题,这也是一种方便的线程策略,因为线程可以保留它创建的中间结果的本地副本(到目前为止的1和0的计数),而不会干扰或与其他线程同步。
  3. 基于以上内容的建议是,单个线程将执行循环,循环的每次传递都会查看一个元素,并更新包含1和0计数的局部变量。这将是2部分算法的第一部分。然后第二部分必须收集这些中间结果。您将想要考虑第二部分如何从第一部分收集结果。例如,在内核完成时,您可能希望将中间结果存储回全局内存。
  4. 翘曲/平铺? Warps指的是将线程分组为32个线程的单元以供执行。这将自动发生。您应该安排算法,以便在从全局内存中读取值(或将值写入全局内存)时,每个线程在连续的连续块中读取(或写入)。这是线程0从位置0读取,线程1从下一个位置读取,等等。如果您在线程中没有做任何异常,这将自动或多或少地自动发生。由cudaMalloc创建的数据存储将正确对齐,如果您的数组索引策略类似于[thread_number],那么您将在整个warp中获得对齐和合并的访问,建议从GPU获得良好的速度。平铺是指组织数据访问以突出位置的过程,这通常有利于缓存依赖的体系结构。如果你做好了内存合并,你就不会依赖缓存。
  5. 如果您可以节省时间,CUDA C programming guide是一个非常易读的文档,它将向您展示良好GPU编程所需的基本概念。此外,nvidia网站上还有webinars,可以在大约2小时内覆盖重要资料。此外,thrust可以用最少的编码工作(在C ++中)方便地处理这样的问题,但我猜这不在你现在想做的范围之内。