【问题标题】:CUDA computing a histogram with shared memoryCUDA 使用共享内存计算直方图
【发布时间】:2016-04-14 09:05:23
【问题描述】:

我正在关注a udacity problem set lesson,从一长串 numElems 值中计算出 numBins 元素的直方图。在这个简单的例子中,每个元素的值也是他自己在直方图中的 bin,因此使用 CPU 代码生成直方图就像

for (i = 0; i < numElems; ++i)
  histo[val[i]]++;

我没有得到“快速直方图计算”的视频解释,据此我应该按“粗略 bin id”对值进行排序,然后计算最终的直方图。

问题是:

  • 我为什么要按“粗分箱索引”对值进行排序?

【问题讨论】:

  • 在这个特定问题中,您需要以这种方式对它们进行排序,因为您正在使用那些粗略的直方图数据桶执行计算,以将工作负载分配给线程。将数据从主内存传输到 GPU 内存是一项昂贵的操作,访问 GPU 内的共享内存也很昂贵。所以,为了最大化性能,你把所有的数据放在一起,所以当一个线程请求数据时,它会得到它需要的数据加上它将来需要的数据,而不是每次计算都必须访问共享内存。
  • 谢谢 Nadir.. 所以我必须先对所有值进行排序?这不比读取并执行 atomicAdd 到正确的 bin 更昂贵吗?
  • 我建议你两种方法都做,这样你就能看到区别。但我对 CUDA 的经验是,排列不当的内存比额外的计算负载更糟糕

标签: c++ cuda


【解决方案1】:

我为什么要按“粗分类索引”对值进行排序?

这是一种尝试将工作分解为可由单个线程块处理的部分。这里有几个注意事项:

  1. 在 GPU 上,最好有多个线程块,以便所有 SM 都可以参与解决问题。
  2. 给定的线程块在单个 SM 上存在和运行,因此它仅限于该 SM 上的可用资源,主要限制是线程数和可用共享内存的大小。
  3. 由于共享内存特别有限,工作分工为每个线程块创建了一个较小的直方图操作,它可能适合 SM 共享内存,而整个直方图范围可能不适合。例如,如果我在 4 个十进制数字范围内进行直方图绘制,那么总共将有 10,000 个 bin。每个 bin 可能需要一个 int 值,因此是 40Kbytes,这几乎不适合共享内存(并且作为占用限制器可能会对性能产生负面影响)。超过 5 个十进制数字的直方图可能不适合。另一方面,通过一个十进制数字的“粗分类”,我可以将每个块的共享内存需求从 40Kbytes 减少到 4Kbytes(大约)。

共享内存原子通常比全局内存原子快得多,因此以这种方式分解工作可以有效使用共享内存原子,这可能是一个有用的优化。

所以我必须先对所有值进行排序?这不是比阅读并执行 atomicAdd 到正确的 bin 更昂贵吗?

也许吧。但是粗分类的想法是,它在计算上可能比完整分类便宜得多。 radix sort 是一种常用的、相对快速的排序操作,可以在 GPU 上并行完成。基数排序具有排序操作从最重要的“数字”开始并迭代地进行到最低有效数字的特征。然而,粗略的 bin 排序意味着实际上只有最高有效数字的一些子集需要“排序”。因此,使用基数排序技术的“粗分类”在计算上可能大大比完全排序更便宜。如果您只对 udacity 示例中所示的 3 位数字中的最高有效位进行排序,这意味着您的排序仅是完整排序的大约 1/3。

我并不是说这是保证在任何情况下都能获得更快性能的方法。细节很重要(例如直方图的大小、范围、bin 的最终数量等)。您使用的特定 GPU 也可能会影响权衡。例如,Kepler 和更新的设备将大大改进全局内存原子,因此比较会受到很大影响。 (OTOH,Pascal 大大改进了共享内存原子,这将再次影响另一个方向的比较。)

【讨论】:

    猜你喜欢
    • 2013-02-09
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    • 2023-01-17
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 2012-07-01
    相关资源
    最近更新 更多