gpgpu

在我们以前的一篇文章中,我们讨论了图形处理单元(GPGPU)的通用处理概念和体系结构。 对于C / C ++程序员来说,这一切都很棒,但是对于Java程序员而言,写C / C ++而不是Java至少可以带来不便。 那么为Java程序员提供哪些工具呢?

在我们开始编写一些背景知识之前。 有两个竞争的GPGPU SDK: OpenCL和CUDA 。 OpenCL是所有GPU供应商(即AMD,NVIDIA和Intel)支持的开放标准,而CUDA是NVIDIA特定的,并且仅在NVIDIA卡上工作。 这两个SDK都支持C / C ++代码,这无疑使我们的Java开发人员感到冷漠。 到目前为止,还没有纯Java OpenCL或CUDA支持。 对于需要利用GPU大量并行潜力的Java程序员来说,这并没有太大帮助,除非她摆弄Java Native接口。 当然,有一些Java工具可以减轻GPGPU Java编程的麻烦。

最受欢迎的两个(IMHO)是jocl和jcuda 。 使用这些工具,您仍然必须编写C / C ++代码,但这至少仅适用于将在GPU中执行的代码,从而极大地减少了工作量。

这次,我将看一看jcuda,看看如何编写一个简单的GPGPU程序。

让我们从设置CUDA GPGPU linux开发环境开始(尽管Windows和Mac环境也不难设置):

步骤1 :在计算机中安装启用了NVIDIA CUDA的GPU。 NVIDIA开发人员网站上有支持CUDA的GPU列表。 新的NVIDIA GPU几乎可以肯定已启用CUDA,但以防万一,请检查卡的规格以确保…

步骤2 :安装NVIDIA驱动程序和CUDA SDK。 下载它们并从此处找到安装说明。

步骤3 :转到目录〜/ NVIDIA_GPU_Computing_SDK / C / src / deviceQuery并运行make

步骤4 :如果编译成功,请转到目录〜/ NVIDIA_GPU_Computing_SDK / C / bin / linux / release并运行文件deviceQuery 。 您将获得有关卡的许多技术信息。

这是我的GeForce GT 430卡所获得的:

注意2个具有48个CUDA核心的多处理器,每个核心共有96个核心,对于价值约40欧元的低端视频卡来说还不错!!!

步骤5 :现在您已经有了CUDA环境,让我们用C语言编写和编译CUDA程序。编写以下代码并将其保存为multiple.cu。

#include <iostream>__global__ void multiply(float a, float b, float* c)
{*c=a*b;
}int main()
{float a, b, c;float *c_pointer;a=1.35;b=2.5;cudaMalloc((void**)&c_pointer, sizeof(float));multiply<<<1,1>>>(a, b, c_pointer);cudaMemcpy(&c, c_pointer, sizeof(float),cudaMemcpyDeviceToHost);
/*** This is C!!! You manage your garbage on your own!  ***/    cudaFree(c_pointer);printf("Result = %f\n",c);
}

使用cuda编译器对其进行编译并运行:

$ nvcc multiply.cu -o multiply
$ ./multiply
Result = 3.375000
$

那么上面的代码做什么? 带有__global__限定符的乘法函数称为内核 ,是将在GPU中执行的实际代码。 尽管存在一些语义差异,但main函数中的代码在CPU中作为普通C代码执行:

  1. 用<<< 1,1 >>>括号调用乘法函数。 方括号内的两个数字告诉CUDA代码应执行多少次。 CUDA使我们能够创建所谓的一维,二维或什至三维线程块。 此示例中的数字表示一个维度上运行的单个线程块,因此我们的代码将执行1×1 = 1次。
  2. cudaMalloc,cudaMemcpy和cudaFree函数用于处理GPU内存的方式与处理C语言中计算机的普通内存类似。cudaMemcpy函数非常重要,因为GPU具有自己的RAM,并且在处理内核中的任何数据之前我们需要将它们加载到GPU内存中。 当然,完成后,我们还需要将结果复制回普通内存。

现在我们掌握了如何在GPU中执行代码的基础知识,让我们看看如何从Java运行GPGPU代码。 请记住,内核代码仍将用C编写,但是至少现在主要功能是在jcuda的帮助下的Java代码。

下载jcuda二进制文件,解压缩它们,并确保包含.so文件的目录(或Windows的.dll)在JVM的java.library.path参数中给出,或将其附加到LD_LIBRARY_PATH环境变量中(或Windows中的PATH变量)。 同样,在编译和执行Java程序期间,jcuda-xxxxxxx.jar文件必须位于类路径中。

现在,我们有了jcuda设置,让我们看一下与jcuda兼容的内核:

extern "C"
__global__ void multiply(float *a, float *b, float *c)/*************** Kernel Code **************/
{c[0]= a[0] * b[0];
}

您会注意到与以前的内核方法有以下区别:

  1. 我们使用extern“ C”限定符来告诉编译器不要混用乘法方法名称,因此可以使用其原始名称进行调用。
  2. 对于a,b和c,我们使用数组而不是基元。 jcuda要求这样做,因为jcuda不支持Java原语。 在jcuda中,数据作为诸如浮点数,整数等之类的事物数组来回传递给GPU。

将此文件另存为multiple2.cu 。 这次我们不想将文件编译为可执行文件,而是编译为将在我们的Java程序中调用的CUDA库。 我们可以将内核编译为PTX文件或CUBIN文件。 PTX是人类可读的文件,其中包含将即时编译的程序集(如代码)。 CUBIN文件是已编译的CUda BINaries,无需进行即时编译即可直接调用。 除非您需要最佳的启动性能,否则PTX文件是可取的,因为它们不会与编译时使用的GPU的特定计算能力挂钩,而CUBIN文件将无法在计算能力较低的GPU上运行。

为了编译我们的内核,输入以下内容:

$ nvcc -ptx multiply2.cu -o multiply2.ptx

成功创建我们的PTX文件后,让我们看一下与我们的C示例中使用的main方法等效的java:

import static jcuda.driver.JCudaDriver.*;
import jcuda.*;
import jcuda.driver.*;
import jcuda.runtime.JCuda;public class MultiplyJ {public static void main(String[] args) {float[] a = new float[] {(float)1.35};float[] b = new float[] {(float)2.5};float[] c = new float[1];cuInit(0);CUcontext pctx = new CUcontext();CUdevice dev = new CUdevice();cuDeviceGet(dev, 0);cuCtxCreate(pctx, 0, dev);CUmodule module = new CUmodule();cuModuleLoad(module, "multiply2.ptx");CUfunction function = new CUfunction();cuModuleGetFunction(function, module, "multiply");CUdeviceptr a_dev = new CUdeviceptr();cuMemAlloc(a_dev, Sizeof.FLOAT);cuMemcpyHtoD(a_dev, Pointer.to(a), Sizeof.FLOAT);CUdeviceptr b_dev = new CUdeviceptr();cuMemAlloc(b_dev, Sizeof.FLOAT);cuMemcpyHtoD(b_dev, Pointer.to(b), Sizeof.FLOAT);CUdeviceptr c_dev = new CUdeviceptr();cuMemAlloc(c_dev, Sizeof.FLOAT);Pointer kernelParameters = Pointer.to(Pointer.to(a_dev),Pointer.to(b_dev),Pointer.to(c_dev));cuLaunchKernel(function, 1, 1, 1, 1, 1, 1, 0, null, kernelParameters, null);cuMemcpyDtoH(Pointer.to(c), c_dev, Sizeof.FLOAT);JCuda.cudaFree(a_dev);JCuda.cudaFree(b_dev);JCuda.cudaFree(c_dev);System.out.println("Result = "+c[0]);}
}

好的,看起来很多代码只是将两个数字相乘,但是请记住,有关Java和C指针的限制。 因此,从第9至11行开始,我们将a,b和c参数转换为名为a,b和c的数组,每个数组仅包含一个浮点数。

在第13至17行中,我们告诉jcuda我们将在系统中使用第一个GPU(高端系统中可能有多个GPU。)

在第19至22行中,我们告诉jcuda我们的PTX文件是,以及我们要使用的内核方法的名称(在我们的例子中是乘法)

在第24行,事情变得有趣起来,在第24行,我们使用了一个特殊的jcuda类CUdeviceptr,它充当指针占位符。 在第25行中,我们使用刚创建的CUdeviceptr指针分配GPU内存。 请注意,如果我们的数组有多个项目,则需要将Sizeof.FLOAT常数乘以数组中元素的数量。 最后,在第26行中,我们将第一个数组的内容复制到GPU。 同样,我们创建指针并将内容复制到第二个数组(b)的GPU RAM中。 对于我们的输出数组(c),我们现在仅需要分配GPU内存。

在第35行中,我们创建一个Pointer对象,该对象将保存我们要传递给乘法方法的所有参数。

我们在第41行执行内核代码,在此执行实用程序方法cuKernelLaunch,将函数和指针类作为参数传递。 函数参数之后的前六个参数定义了网格的数量(一个网格是一组块),并且在我们的示例中,这些块全为1,因为我们只执行一次内核。 接下来的两个参数为0和null ,用于标识我们可能定义的任何共享内存(可以在线程之间共享的内存),在本例中为无。 下一个参数包含创建的指针对象,该对象包含a,b,c设备指针,最后一个参数用于其他选项。

内核返回后,我们只需将dev_c的内容复制到我们的c数组,释放我们在GPU中分配的所有内存,并打印存储在c [0]中的结果,这当然与我们的C示例相同。

这是我们编译和执行MultiplyJ.java程序的方式(假设multiple2.ptx在同一目录中):

$ javac -cp ~/GPGPU/jcuda/JCuda-All-0.4.0-beta1-bin-linux-x86_64/jcuda-0.4.0-beta1.jar MultiplyJ.java$ java -cp ~/GPGPU/jcuda/JCuda-All-0.4.0-beta1-bin-linux-x86_64/jcuda-0.4.0-beta1.jar:. MultiplyJ
Result = 3.375
$

请注意,在此示例中,目录〜/ GPGPU / jcuda / JCuda-All-0.4.0-beta1-bin-linux-x86_64已经在我的LD_LIBRARY_PATH中,因此不需要在java.library.path中设置参数。 JVM。

希望到目前为止,jcuda的机制已经很清楚了,尽管我们并未真正涉及到GPU真正的强大功能,即大规模并行性。 在以后的文章中,我将提供一个示例,说明如何使用java在CUDA中运行并行线程,并附带一个示例,说明哪些内容不能在GPU中运行。 GPU处理对于非常专业的任务很有意义,大多数任务最好由我们受信任的旧CPU处理。

参考: W4G合作伙伴 Spyros Sakellariou的 GPGPU Java编程

相关文章 :

  • CPU与GPGPU
  • Java Lambda语法替代
  • JVM如何处理锁
  • Java Fork / Join进行并行编程
  • Java最佳实践系列
  • 如何在Java中获得类似于C的性能

翻译自: https://www.javacodegeeks.com/2011/09/gpgpu-java-programming.html

gpgpu

gpgpu_GPGPU Java编程相关推荐

  1. 除了java还学什么_学好Java编程除了努力还需要具备什么?

    Java编程语言的热流席卷了全球,它的出现摆脱了C语言尾大不掉的困境,灵活.多变,塑造性强的特点不仅符合当下互联网的发展趋势,也得到一批批青年俊才的青睐,Java编程抛出的橄榄枝,也吸引了大量计算机专 ...

  2. 偏执却管用的 10 条 Java 编程技巧

    经过一段时间的编码(咦,我已经经历了将近20年的编程生涯,快乐的日子总是过得很快),我们开始感谢那些好习惯.因为,你知道- "任何可能出错的事情,最后都会出错." 这就是人们为什么 ...

  3. 学习Java编程培训的书籍有哪些

    学习java技术除了线上线下的培训学习,书籍的知识也是非常重要的,今天小编为大家整理的就是学习Java的一些书籍,Java书籍是程序员学习提升技能的重要学习渠道,通过书籍Java程序员可以学习当前流行 ...

  4. Java编程的逻辑 (39) - 剖析LinkedList

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  5. 某程序员吐槽:免费教妹子Java编程,妹子却不让自己找她闲聊!

    许多程序员教妹子编程.带妹子打游戏,都是醉翁之意不在酒,名为教学,实为追求,但有一个程序员小哥哥却比较悲催,他答应一个妹子当她师傅,教她Java编程,结果妹子却说,学习是学习,平时是平时,让小哥哥平时 ...

  6. Java 编程技巧之数据结构

    Photo @markusspiske 文 | 常意 导读 唐宋八大家之一欧阳修在<卖油翁>中写道: 翁取一葫芦置于地,以钱覆其口,徐以杓酌油沥之,自钱孔入,而钱不湿.因曰:"我 ...

  7. java开发编程周末班_今天,Java编程周末提高班(第一期)正式结束

    Java编程周末提高班(第一期),走过了近两个月历程,一共同拥有68人次学生周末到老师家进行Java学习与交流.近距离的和一群年轻的学习接触,收获非常多,特别是对以后教学的改进.在学习的闲暇.大家自己 ...

  8. jar java classpath_win7中java编程工具安装 java环境变量设置

    win7中java编程工具安装 java环境变量设置 Question:编译是显示'javac'不是内部或外部命令,也不是可运行的程序或批处理文件 解决: 在[系统变量]里编辑java_home.cl ...

  9. Java编程笔试时输入问题:如何输入固定长度、不定长度的一维数组?如何输入固定长度、不定长度的二维数组?

    Java编程笔试时输入问题: 如何输入固定长度.不定长度的一维数组? 如何输入固定长度.不定长度的二维数组? 如何将数组中的内容直接输出,不要中括号和逗号? 文章目录 ==Java编程笔试时输入问题= ...

最新文章

  1. metaSPAdes:新型多功能宏基因组拼接工具
  2. 构建 编译和运行Urho3D工程
  3. HTTP Server Error 500 内部服务器错误
  4. 高校c语言题库,C语言-中国大学mooc-题库零氪
  5. 01背包怎么不重复_带有重复物品的背包
  6. 搭建Cacti监控系统(三)-- 监控Linux 主机
  7. jquery删除空图片错误图片,$('img[src=]').remove();
  8. 洛谷 题解 P1757 【通天之分组背包】
  9. PL3369C原边12W电源芯片
  10. 1602液晶显示屏工作原理引脚电路图51单片机
  11. android序列帧动画纯代码,H5序列帧动画实现过程(附源码)
  12. Linux内存卡槽故障判断,内存插槽损坏的三种常见故障
  13. 安装向导无法创建文件夹
  14. 激活具有 eSIM 功能的消费类物联网设备的 4 种方法
  15. 使用京东云免费云主机搭建CentOS
  16. may have been in progress in another thread when fork() was called.
  17. WML语言基础(WAP建站)四
  18. aspx repeater 用法_详解ASP.NET数据绑定操作中Repeater控件的用法
  19. C++实现生产者和消费者模型
  20. NOIP初赛真题集锦

热门文章

  1. Android一键锁屏,去除锁屏密码
  2. 2019年个人总结,写在人生不惑之年
  3. 如何看待华文的《二十岁无资本无未来》?
  4. python制表符的作用_Python制表符是什么
  5. web端动效 lottie-web 使用
  6. Python----操作MySql数据库2
  7. 数据仓库之维度表和事实表
  8. Day 1: 音标学习
  9. python interpreter配置_PyCharm使用之配置SSH Interpreter
  10. 点菜系统中的命令模式