CUDA - 如何返回未知大小的结果

Posted

技术标签:

【中文标题】CUDA - 如何返回未知大小的结果【英文标题】:CUDA - How to return results of unknown size 【发布时间】:2015-01-14 13:27:24 【问题描述】:

我将一个大型二维数组(C 语言)传递给设备并确定所有可能的组合。例如:

A = 
id  val1 val2
1   100  200
2   400  800

Combination = 
id1  id2  sumval1  sumval2
1    2    500      1000

由于原始数组的大小,不可能存储和返回所有可能的组合。我想返回 sumval1 > 500 和 sumval2 > 1000 的所有组合。

我怎样才能将这个组合子集返回到要写入文件的主机;鉴于我不知道有多少组合符合条件?

【问题讨论】:

【参考方案1】:

一些可能的方法:

    (从主机)分配您在 GPU 内存中剩余的任何空间用于缓冲区。如果超过了这个值,那么无论如何您都无法在一次传输中将所有组合传回。 (这可能会导致您使用 mtk99 提出的解决方案)。 使用内核内malloc 在设备上根据需要动态分配空间。完成组合创建后,将所有单独的组合收集到使用malloc 创建的单个缓冲区中。然后将此缓冲区的总大小和指向此缓冲区的指针传递回主机。然后主机使用cudaMalloc 分配该大小的新缓冲区,并启动内核以将数据从使用malloc 创建的缓冲区复制到使用cudaMalloc 创建的缓冲区。复制内核完成后,主机可以将数据从使用cudaMalloc 创建的缓冲区传回主机。

我建议 1 可能是最好的方法,而无需了解您正在尝试做什么。在内核中malloc 在分配大量小分配时并不是特别快。此外,当使用内核malloc 时,请注意可以增加的默认大小限制 (8MB)。

【讨论】:

我喜欢分页的想法。我将为结果分配数组 R,但我应该如何索引数组?在 C 中,每次输入结果时我都会 i++。我会遇到使用相同 i 的所有线程的问题吗? 是的,如果您有多个线程尝试更新单个缓冲区,则会出现问题。我的回答 here 对于让多个线程将数据推送到单个缓冲区中可能很有用。【参考方案2】:

您可以对结果进行分页:

创建一个修复结果数组(比如 Z 项)。

不仅返回结果,还返回您停止的点(last_id1、last_id2)。

在下一次调用时,根据您上次的结果传递一个新的起点(start_id1、start_id2)。

您可以使用流来保持 GPU 加载。

基于此,您甚至可以使用多个 GPU 分配计算。

【讨论】:

我喜欢分页的想法。我将为结果分配数组 R,但我应该如何索引数组?在 C 中,每次输入结果时我都会 i++。我会遇到使用相同 i 的所有线程的问题吗? 你应该做流压缩,看看thrust::remove_if。在输出数组中生成尽可能多的组合。也许您需要输入是纹理,因此您可以使用谓词中的值而无需将它们复制到输出。运行流压缩并返回 last_id1 和 lastid_2。随着数据的推进,以不同的起点多次调用内核。

以上是关于CUDA - 如何返回未知大小的结果的主要内容,如果未能解决你的问题,请参考以下文章

CUDA 结果使用非常大的数组返回垃圾,但不报告错误

如何在大小未知时使用 while..do 循环初始化 F# 列表

使用ctypes python包装C函数返回未知大小的数组

如何在 SwiftUI 中创建一个获取 View 并返回自定义结果的函数?

GPU 上的 tensorflow:没有已知设备,尽管 cuda 的 deviceQuery 返回“PASS”结果

如何编组包含未知大小的 int 数组的结构?