有几个原因可能会说服你,编写自己的openCL代码可能比纯粹依赖包编译器更有吸引力:

  1. 你需要的功能在包里没有

  2. 编译代码的性能不符合要求

  3. 您熟悉openCL,并希望直接使用openCL代码

与传统的openCL语言的枯燥而痛苦的编程过程不同,用R编写自己的代码相当简单:只需向包提供代码,包就会为您设置一切。该包还提供了一个类似模板的特性,可以将您从恼人的参数类型一致性问题中解脱出来。如果你不熟悉openCL语言,在互联网上有大量的介绍,请先阅读它们,并确保在阅读下一节之前你有openCL的基本概念。

从最简单的例子开始教程总是好的,让我们假设我们想要计算A + B在哪里一个而且B都是向量。如果我们使用原生的openCL代码来编写它,它将是。

#内核代码src="内核void vecAdd(global double* A, global double* B, global double* res){uint id=get_global_id(0);res [id] = [id] + B (id);} " #检查并设置设备getDeviceList() #>没有发现设备,请确保计算机有显卡或驱动程序已正确安装。#>提示:#> CPU, intel / AMD的CPU可以分别安装intel / ATI的图形驱动。对于GPU,您需要从供应商的网站下载图形驱动程序。#>没有发现设备!#> NULL setDevice(1) #>没有发现设备!#> NULL #数据准备n=1000 A=runif(n) B=runif(n) #将数据发送到设备#参数type和device可选A_dev=gpuMatrix(A,type="double",device =1) #>未找到设备!B_dev=gpuMatrix(B,type="double",device = 1) #>没有发现设备!#创建一个空向量来存储结果res_dev=gpuEmptMatrix(row=n,col=1,type="double",device =1) #>没有发现设备! #Call the kernel function to excute the code #No return value .kernel(src = src,kernel="vecAdd",parms=list(A_dev,B_dev,res_dev),.device = 1,.globalThreadNum = n) #> No device has been found! #> NULL #retrieve the data and convert it into a vector res_dev=download(res_dev) res=as.vector(res_dev) #Check the error range(res-A-B) #> [1] NA NA

正如您在这里看到的,在gpuMagic中使用openCL代码与在Rcpp中使用c++代码非常相似。主要的区别在于,您需要在代码执行之前和之后发送和检索数据。的.kernel函数从S4类开始就没有任何返回值gpuMatrix包含一个指针,它能够在代码执行后检索最终结果。请注意.kernel函数将不会阻塞您的控制台,因此只要不调用下载函数。

你可能会注意到,在将R对象转换为变量类型时,可以指定变量类型gpuMatrix类。可用的类型将在本文档的末尾列出。然而,当您更改变量类型时,您需要确保openCL代码中的函数参数也匹配它,这是笨拙的。因此,.kernel函数提供一组宏来处理变量类型。这些宏将自动找到正确的变量类型,并提供类似模板的功能,它们是:汽车gAutolAuto.的汽车Macro会找到变量类型;gAuto而且lAuto都是全球汽车而且当地的汽车分别。如果你不知道全球而且当地的,请参考opencl地址空间限定符。这里我们使用相同的示例来说明宏的使用。

#使用auto宏声明函数参数#第一个参数为auto1,第二个参数为auto2,依此类推。#gAuto是global auto src=" kernel void vecAdd(gAuto1* A, gAuto2* B, gAuto3* res){uint id=get_global_id(0);res [id] = [id] + B (id);} " #将数据发送到设备#注意变量A和B是一个浮动类型A_dev=gpuMatrix(A,type="float",device = 1) #>没有发现设备!B_dev=gpuMatrix(B,type="float",device = 1) #>没有发现设备!#创建一个空向量来存储结果res_dev=gpuEmptMatrix(row=n,col=1,type="float",device =1) #>没有发现设备!#没有返回值。kernel(src = src,kernel="vecAdd",parms=list(A_dev,B_dev,res_dev),.device = 1,。globalThreadNum = n) #>没有发现设备!#> NULL #检索数据并将其转换为向量res_dev=download(res_dev) res=as.vector(res_dev) #检查错误范围(res- a - b) #> [1] NA NA

我们在示例中做了两个更改。首先,我们使用gAuto宏在openCL代码中声明函数参数,因此函数定义独立于将传递给函数的实际数据。其次,我们使用float类型变量来存储数据。降低变量精度可以使代码运行得更快,但结果不如前面的示例那么准确。

#附加信息

在这里我们提供一些关于的使用的附加信息.kernel函数时,读者可参考文档.kernel ?详情如下:

  1. 在指定设备之前,通过.device参数时,您需要确保设备已初始化,请通过调用setDevice函数。

  2. .device参数只允许一个设备id作为输入,您只能在一个设备上运行该代码.kernel函数调用。然而,自从.kernel功能不阻塞控制台,可以有多个.kernel函数调用使用不同的设备id来并行化硬件。

  3. 你可以将编译标志传递给openCL编译器(不能gpuMagic包编译器,它是厂商的编译器)通过.options论点

  4. src参数可以是文件目录或代码。

#附录##可用数据类型

  1. 整数类型:保龄球字符使用uintintulong

  2. 浮子式:一半浮动