首先,您应该知道 CUDA 不会自动加快计算速度。一方面,因为 GPU 编程是一门艺术,要做好它可能非常非常具有挑战性。另一方面,因为 GPU 仅适用于某些类型的计算。
这听起来可能令人困惑,因为您基本上可以在 GPU 上计算任何东西。当然,关键是您是否会实现良好的加速。这里最重要的分类是问题是任务并行还是数据并行。粗略地说,第一个是指多个线程或多或少独立地处理自己的任务的问题。第二个问题是许多线程都在做同样的事情——但在数据的不同部分。
后者是 GPU 擅长的一类问题:它们有很多核心,所有核心都做同样的事情,但对输入数据的不同部分进行操作。
你提到你有“简单的数学,但有大量的数据”。尽管这听起来像是一个完美的数据并行问题,因此非常适合 GPU,但还有另一个方面需要考虑:GPU 在理论计算能力(FLOPS,每秒浮点运算数)方面速度快得离谱。但是它们经常受到内存带宽的限制。
这导致了问题的另一种分类。即问题是内存限制还是计算限制。
第一个是指为每个数据元素执行的指令数量很少的问题。例如,考虑一个并行向量加法:您必须读取两个数据元素,然后执行一次加法,然后将总和写入结果向量。在 GPU 上执行此操作时您不会看到加速,因为单次添加并不能补偿读取/写入内存的工作量。
第二个术语“计算受限”是指指令数量与内存读取/写入数量相比较高的问题。例如,考虑一个矩阵乘法:当 n 是矩阵的大小时,指令的数量将为 O(n^3)。在这种情况下,可以预期 GPU 在特定矩阵大小下的性能将优于 CPU。另一个示例可能是在“少数”数据元素上执行许多复杂的三角计算(正弦/余弦等)时。
根据经验:您可以假设从“主”GPU 内存读取/写入一个数据元素的延迟约为 500 条指令......
因此,GPU 性能的另一个关键点是数据局部性:如果您必须读取或写入数据(并且在大多数情况下,您将不得不;-)),那么您应该确保数据保持尽可能接近可能适用于 GPU 内核。因此,GPU 具有某些内存区域(称为“本地内存”或“共享内存”),通常只有几 KB 大小,但对于即将参与计算的数据特别有效。
所以再次强调这一点:GPU 编程是一门艺术,它只与 CPU 上的并行编程远程相关。ThreadPoolExecutors
诸如 Java 中的 Threads 之类的东西,以及诸如等所有并发基础设施ForkJoinPools
可能会给人一种印象,即您只需要以某种方式拆分您的工作并将其分布在多个处理器之间即可。在 GPU 上,您可能会遇到低得多的挑战:占用、寄存器压力、共享内存压力、内存合并……仅举几例。
但是,当您要解决数据并行、计算受限的问题时,GPU 是您的最佳选择。
一般性评论:您专门要求使用 CUDA。但我强烈建议您也看看 OpenCL。它有几个优点。首先,它是一个独立于供应商的开放行业标准,并且有 AMD、Apple、Intel 和 NVIDIA 实施的 OpenCL。此外,Java 世界对 OpenCL 有更广泛的支持。我宁愿满足于 CUDA 的唯一情况是当您想要使用 CUDA 运行时库时,例如用于 FFT 的 CUFFT 或用于 BLAS(矩阵/向量操作)的 CUBLAS。尽管有一些方法可以为 OpenCL 提供类似的库,但它们不能直接从 Java 端使用,除非您为这些库创建自己的 JNI 绑定。
您可能还会觉得有趣的是,2012 年 10 月,OpenJDK HotSpot 小组启动了“Sumatra”项目:http: //openjdk.java.net/projects/sumatra/。该项目的目标是在 JIT 的支持下直接在 JVM 中提供 GPU 支持。当前状态和第一个结果可以在他们的邮件列表中看到: http: //mail.openjdk.java.net/mailman/listinfo/sumatra-dev
但是,前段时间,我收集了一些与“GPU 上的 Java”相关的资源。我将在这里再次总结这些,没有特别的顺序。
(免责声明:我是http://jcuda.org/和http://jocl.org/的作者)
(字节)代码翻译和 OpenCL 代码生成:
https://github.com/aparapi/aparapi:由 AMD 创建并积极维护的开源库。在一个特殊的“内核”类中,可以覆盖应该并行执行的特定方法。此方法的字节码在运行时使用自己的字节码阅读器加载。代码被翻译成 OpenCL 代码,然后使用 OpenCL 编译器进行编译。然后可以在 OpenCL 设备上执行结果,该设备可能是 GPU 或 CPU。如果无法编译成 OpenCL(或没有可用的 OpenCL),代码仍将使用线程池并行执行。
https://github.com/pcpratts/rootbeer1:一个用于将部分 Java 转换为 CUDA 程序的开源库。它提供了可以实现的专用接口,以指示应该在 GPU 上执行某个类。与 Aparapi 相比,它尝试将“相关”数据(即对象图的完整相关部分!)自动序列化为适合 GPU 的表示。
https://code.google.com/archive/p/java-gpu/:用于将带注释的 Java 代码(有一些限制)转换为 CUDA 代码的库,然后将其编译为在 GPU 上执行代码的库。该图书馆是在博士论文的背景下开发的,其中包含有关翻译过程的深刻背景信息。
https://github.com/ochafik/ScalaCL:OpenCL的 Scala 绑定。允许与 OpenCL 并行处理特殊的 Scala 集合。在集合元素上调用的函数可以是通常的 Scala 函数(有一些限制),然后将其转换为 OpenCL 内核。
语言扩展
http://www.ateji.com/px/index.html:Java的一种语言扩展,允许并行构造(例如并行 for 循环、OpenMP 风格),然后在 GPU 上使用 OpenCL 执行这些构造。不幸的是,这个非常有前途的项目不再维护。
http://www.habanero.rice.edu/Publications.html (JCUDA):一个可以将特殊的 Java 代码(称为 JCUDA 代码)翻译成 Java 和 CUDA-C 代码的库,然后可以在显卡。但是,该库似乎并不公开。
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html:用于 OpenMP 结构的 Java 语言扩展,带有 CUDA 后端
Java OpenCL/CUDA 绑定库
https://github.com/ochafik/JavaCL:OpenCL的 Java 绑定:一个面向对象的 OpenCL 库,基于自动生成的低级绑定
http://jogamp.org/jocl/www/:OpenCL的 Java 绑定:一个面向对象的 OpenCL 库,基于自动生成的低级绑定
http://www.lwjgl.org/:OpenCL的 Java 绑定:自动生成的低级绑定和面向对象的便利类
http://jocl.org/:OpenCL的 Java 绑定:原始 OpenCL API 的 1:1 映射的低级绑定
http://jcuda.org/:CUDA的 Java 绑定:原始 CUDA API 的 1:1 映射的低级绑定
各种各样的
http://sourceforge.net/projects/jopencl/:OpenCL的 Java 绑定。自 2010 年以来似乎不再维护
http://www.hoopoe-cloud.com/:CUDA的 Java 绑定。似乎不再维护