parallel-processing - 与 CUDA 中的线程和块并行化
问题描述
我有以下简单的嵌套 for 循环
float a[1024][1024], b[1024]
for(i=1; i < 1024; i++){
for(j = 1; j < 1024 - i; j++){
b[i + j] += a[i][j];
}
}
而且我正在尝试了解如何使用 CUDA 线程和线程块来划分这个问题以与 GPU 并行化。到目前为止,我相信我总共进行了 N = 522753 次计算。我不完全确定如何从这里开始:我知道每个块中的线程数应该是 32 的倍数。例如,如果每个块的线程数是 1024,那么我至少需要 511 个块,其中每个线程从 1 -> N 进行计算。有人可以解释如何选择每个块的最佳线程数,以及如何实际并行实现。
解决方案
长评:
编辑:c 矩阵应该是列主要而不是行主要,并且排序应该在列而不是行上,但为了便于阅读,我将其保留为行主要。
您可以(一次)为每个工作项准备一个计数和引用矩阵,以便第一列是计数,其余是引用,最后一列是写入地址
c[0] = {1, &a[1][1], &b[2]}; // b[2]
c[1] = {2, &a[1][2],&a[2][1], &b[3]}; // b[3]
c[2] = {3, &a[1][3],&a[2][2],&a[3][1], &b[4]}; // b[4]
..
然后根据它们的索引数量/子数组大小对它们进行排序(一次),使它们成为
c[0] = {1, &a[1][1], &b[2]} // b[2]
c[1] = {1, &a[1022][1], &b[1023]} // b[1023]
..
c[k] = {5, x1,y1,z1,t1,w1, &b[m]} // b[m]
c[k+1] = {5, x2,y2,z2,t2,w2, &b[n]} // b[n]
平衡经线/块的 cuda 线程之间的工作量。
然后访问 c 矩阵(每行 1 个 cuda 线程)以了解在每个工作项的普通 for 循环中要添加哪些元素。
const int length = (int)c[workitemId][0];
for(int i=1;i<length+1;i++)
resultOfWorkitem += *(c[workitemId][i]);
*(c[workitemId][length+1])=resultOfWorkitem;
由于所有排序列表只会排序一次,如果您要经常进行计算部分,那么这个额外的引用部分可能比使用原子更快,并且可能会被缓存以供 c 和数组的只读访问。
如果随机写入地址成为性能问题,您可以根据最后一项的地址(连续的 b 索引)对 c 数组进行排序,但这会降低相邻 cuda 线程之间的工作平衡。也许这更快,没有测试。也许对 a 的第二个索引值排序 c 可以通过减少读取次数来加快速度,尤其是当您对它们之间的每一行元素进行排序时,它们会与相邻线程的读取连续,类似于第一部分
c[0] = {1, &a[1][1] // address x \
c[1] = {2, &a[1][2] // address x+1 > less than L1 cache line size 128byte?
c[2] = {3, &a[1][3] // address x+2 /
保持每个工作项的连续地址访问和平衡工作是不可能的。
推荐阅读
- javascript - 如何使用 FileReader 在 JS 中添加图像覆盖?
- python - Matplotlib:在 plt.subplots 中绘制多个直方图
- ruby-on-rails - 文章中的参数错误
- sql - 用于多行插入的“批量自动增量”ID
- oracle - 卸载 32 位版本的 oracle 客户端后,SSIS 中的 Oracle 连接中断
- python - 如何在熊猫中分组、循环和获取结果作为数据框
- python - 当只有 1 个类被实例化时,如何在 2 个类之间共享变量?
- php - 如何验证 Laravel 中两个字段的唯一组合?
- c# - 如何在视图中显示基于月份的列表数据
- r - 如何让 Shiny 的 updateSelectionInput 使用值列表进行更新