我有一大组数据,表示为一维数组。每个单独的条目大小约为50个字节。我想使用CUDA在GPU上的给定数量的桶上对这些数据进行分区。
为了能够在GPU中一次性处理单个批处理中的数据,我希望包含存储桶内容的缓冲区尽可能小,因为我的输入数据的副本是考虑到内存限制,不太可行。使用引用大输入缓冲区的整数索引似乎是这里的方法。
一种天真的方法是在每个桶中分配一定数量的这些引用。不幸的是,输入数据集并不是完全均匀分布的。这可能会导致某些存储桶最终变满并溢出,而其他存储桶甚至可能没有单个条目。不幸的是,对于我的应用程序,存储桶具有实际意义,因此放入存储桶的条目确实 以最终存储在所述存储桶中。
据我所知,最节省内存的方法是分配一个每个桶包含一个索引的数组。随后,您将分配包含结构的第二个缓冲区,该结构又包含指向大输入数据缓冲区中条目的指针,以及后续元素的索引(从而为每个存储区的大缓冲区中的每个条目创建链接列表)。
这使得预先知道两个缓冲区的总必需大小,从而允许有效分配。不幸的是,在构造缓冲区时,有必要跟踪到目前为止已经使用了多少缓冲区。为了避免竞争条件,有必要对单个变量使用原子增量。
这意味着许多线程需要等待单个变量来分配存储桶链接列表中的下一个条目。我希望它能在瞬间将性能降到最低点。
因此我认为最好保持使用链接列表来定义每个存储桶的内容,但扩展每个条目以保留不是一个而是多个对大输入缓冲区的引用,以减少次数需要执行原子操作。当链接列表条目没有完全填充时,这会导致一些浪费内存的代价,尽管我认为这应该是可以接受的。
我对这个策略有两个问题:
答案 0 :(得分:1)
缓冲区中的结构与原始数据项之间已经存在一对一的对应关系。因此,不是通过递增原子计数器在缓冲区中分配结构,而是可以使用原始项的索引来定位缓冲区中的结构。
如果使用与原始数据相同的索引索引缓冲区,则还不需要保留指向原始数据项的指针,并且结构的缓冲区将成为一个简单的整数数组,用于保存下一个条目在链表中。
或者,对数据的两遍方法也适用:在第一遍中,只计算每个桶中的项目数。然后,您可以在第二次传递之前通过inclusive scan为每个存储桶分配适当的内存量,以实际填充存储桶。