Han*_*ans 131 java cuda gpu-programming multi-gpu
我正在开发一个用java完成的业务项目,需要巨大的计算能力来计算业务市场.简单的数学,但有大量的数据.
我们订购了一些cuda gpu来尝试,因为cuda不支持Java,我想知道从哪里开始.我应该构建一个JNI接口吗?我应该使用JCUDA还是有其他方法?
我没有这方面的经验,我想如果有人可以指导我,我可以开始研究和学习.
Mar*_*o13 410
首先,您应该意识到CUDA不会自动更快地进行计算.在一方面,由于GPU编程是一门艺术,它可以是非常,非常具有挑战性得到它的权利.另一方面,因为GPU非常适合某些类型的计算.
这可能听起来令人困惑,因为您基本上可以在GPU上计算任何内容.当然,关键是你是否能达到很好的加速.这里最重要的分类是问题是并行任务还是数据并行.粗略地说,第一个涉及多个线程正在处理自己的任务的问题,或多或少是独立的.第二个是指许多线程都在做同样的问题 - 但是在数据的不同部分.
后者是GPU擅长的问题:它们有许多内核,所有内核都做同样的事情,但是对输入数据的不同部分进行操作.
你提到你有"简单的数学,但有大量的数据".虽然这可能听起来像一个完美的数据并行问题,因此它非常适合GPU,但还有另一个需要考虑的方面:GPU在理论计算能力(FLOPS,每秒浮点运算)方面非常快.但它们经常受到内存带宽的限制.
这导致了另一种问题分类.即问题是内存绑定还是计算绑定.
第一个是指对每个数据元素执行的指令数量较少的问题.例如,考虑并行向量加法:你必须读两个数据元素,然后进行单次加入,然后写将总和结果向量.在GPU上执行此操作时,您不会看到加速,因为单次添加不会补偿读取/写入内存的工作量.
第二项"计算边界"指的是指令数量与内存读取/写入次数相比较高的问题.例如,考虑矩阵乘法:当n是矩阵的大小时,指令的数量将是O(n ^ 3).在这种情况下,可以预期GPU将以特定矩阵大小胜过CPU.另一个例子可能是在"少数"数据元素上执行许多复杂的三角计算(正弦/余弦等).
根据经验:您可以假设从"主"GPU内存中读取/写入一个数据元素的延迟大约为500条指令....
因此,GPU性能的另一个关键点是数据局部性:如果你必须读取或写入数据(在大多数情况下,你必须;-)),那么你应该确保数据保持尽可能接近可以使用GPU核心.因此,GPU具有某些存储区域(称为"本地存储器"或"共享存储器"),其大小通常仅为几KB,但对于即将涉及计算的数据特别有效.
所以再次强调这一点:GPU编程是一门艺术,它只与CPU上的并行编程有很大关系.比如像Java中的线程,所有并发的基础设施一样ThreadPoolExecutors
,ForkJoinPools
等可能给人的印象是,你只需要以某种方式分拆您的工作和多个处理器之间分配它.在GPU上,您可能会遇到更低级别的挑战:占用率,注册压力,共享内存压力,内存合并......仅举几例.
但是,如果要解决数据并行的计算限制问题,GPU就是最佳选择.
一般评论:你特别要求CUDA.但我强烈建议你也看看OpenCL.它有几个优点.首先,它是独立于供应商的开放式行业标准,AMD,Apple,Intel和NVIDIA都在实施OpenCL.此外,Java世界中对OpenCL有更广泛的支持.我宁愿选择CUDA的唯一情况是你想要使用CUDA运行时库,比如用于FFT的CUFFT或用于BLAS的CUBLAS(矩阵/向量运算).虽然有一些方法可以为OpenCL提供类似的库,但是除非您为这些库创建自己的JNI绑定,否则它们不能直接在Java端使用.
您可能还会发现有趣的是,在2012年10月,OpenJDK HotSpot小组启动了"苏门答腊"项目: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/的作者)
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绑定.允许特殊的Scala集合与OpenCL并行处理.在集合的元素上调用的函数可以是通常的Scala函数(有一些限制),然后将它们转换为OpenCL内核.
http://www.ateji.com/px/index.html:Java的语言扩展,允许并行构造(例如,并行for循环,OpenMP样式),然后使用OpenCL在GPU上执行.不幸的是,这个非常有前景的项目已不再保留.
http://www.habanero.rice.edu/Publications.html(JCUDA):一个可以将特殊Java代码(称为JCUDA代码)转换为Java和CUDA-C代码的库,然后可以在该代码上编译和执行GPU.但是,图书馆似乎不公开.
https://www2.informatik.uni-erlangen.de/EN/research/JavaOpenMP/index.html:OpenMP构造的Java语言扩展,带有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绑定.似乎不再维护
根据我所做的研究,如果您的目标是 Nvidia GPU 并决定使用 CUDA 而不是OpenCL,我发现了三种在 java 中使用 CUDA API 的方法。
所有这些答案基本上都是在 Java 中使用 C/C++ 代码的方法。您应该问自己为什么需要使用 Java,以及是否不能用 C/C++ 代替。
如果您喜欢 Java 并且知道如何使用它,并且不想使用所有指针管理以及 C/C++ 附带的东西,那么 JCuda 可能就是答案。另一方面,CUDA Thrust 库和其他类似的库可用于在 C/C++ 中执行大量指针管理,也许您应该看看它。
如果您喜欢 C/C++ 并且不介意指针管理,但有其他限制迫使您使用 Java,那么 JNI 可能是最好的方法。不过,如果您的 JNI 方法只是内核命令的包装器,您不妨使用 JCuda。
JCuda 有一些替代品,例如 Cuda4J 和 Root Beer,但这些似乎没有得到维护。而在撰写本文时,JCuda 支持 CUDA 10.1。这是最新的 CUDA SDK。
此外,还有一些使用 CUDA 的 java 库,例如 deeplearning4j 和 Hadoop,它们可能能够满足您的需求,而无需您直接编写内核代码。不过我还没有对它们进行过多的研究。
归档时间: |
|
查看次数: |
90184 次 |
最近记录: |