主要内容

运行CUDA或在GPU PTX代码

CUDA工具包的需求

如果你想生成CUDA®内核对象从铜代码或使用GPU编码器™源代码,编译CUDA兼容库和可执行文件,您必须安装一个CUDA工具包。CUDA工具包包含编译的CUDA库和工具。

请注意

你不需要运行MATLAB工具箱®函数生成CUDA GPU或使墨西哥人的功能。

任务 需求
  • 使用gpuArray和GPU-enabled MATLAB函数。

  • 编译CUDA MEX-functions使用GPU编码器或启用mexcuda

获得最新的显卡驱动英伟达驱动程序下载

你不需要CUDA工具包。

  • 从铜代码创建CUDA的内核对象。*

  • 编译CUDA兼容的源代码,使用GPU编码器库和可执行文件。

安装的版本CUDA工具包支持你的MATLAB版本。金宝app

*在MATLAB创建CUDA内核对象,你必须有铜文件和相应PTX文件。从铜文件编译PTX文件需要CUDA工具包。如果你已经有相应的PTX文件,您不需要工具箱。并不是所有的编译器支持的CUDA工具金宝app包在MATLAB支持。

工具箱版本需要取决于您所使用的版本的MATLAB。检查哪个版本MATLAB工具箱与您的版本兼容的版本在下表中。推荐的最佳实践是使用你的最新版本支持工具包,包括NVIDIA的任何更新和补丁金宝app®

MATLAB版本 CUDA工具包版本
R2022a 11.2
R2021b 11.0
R2021a 11.0
R2020b 10.2
R2020a 10.1
R2019b 10.1
R2019a 10.0
R2018b 9.1
R2018a 9.0
R2017b 8.0
R2017a 8.0
R2016b 7.5
R2016a 7.5
R2015b 7.0
R2015a 6.5
R2014b 6.0
R2014a 5.5
R2013b 5.0
R2013a 5.0
R2012b 4.2
R2012a 4.0
R2011b 4.0

关于CUDA工具包的更多信息并下载你的支持版本,看看金宝appCUDA工具包存档(英伟达)

CUDAKernel工作流程概述

这一主题解释了如何创建一个可执行的内核从铜或PTX(并行线程执行)文件,并运行内核在MATLAB的GPU。内核在MATLAB表示CUDAKernelMATLAB数组或对象,它可以操作gpuArray变量。

下面的步骤描述了CUDAKernel一般工作流程:

  1. 使用PTX编译代码来创建一个CUDAKernel对象,其中包含GPU可执行代码。

  2. CUDAKernel对象设置属性来控制其执行在GPU上。

  3. 调用函数宏指令在CUDAKernel所需的输入,在GPU上运行的内核。

MATLAB代码遵循这些步骤可能会看起来像这样:

% 1。创建CUDAKernel对象。k = parallel.gpu.CUDAKernel (“myfun.ptx”,“myfun.cu”,“entryPt1”);% 2。设置对象的属性。k。GridSize = 8 [1];k。ThreadBlockSize = [16 1];% 3。调用函数宏指令定义的输入。g1 = gpuArray (in);输入gpuArray %。g2 = gpuArray (in2);输入gpuArray %。结果=函数宏指令(k, g1, g2);

以下部分提供了这些命令和工作流步骤的细节。

创建一个CUDAKernel对象

从铜文件编译PTX文件

如果你有一个铜文件你想在GPU上执行,您必须首先创建一个PTX文件编译它。这是方法之一学校网站编译器在NVIDIA CUDA工具包。例如,如果您的文件被称为铜myfun.cu,您可以创建一个编译PTX文件使用shell命令:

nvcc -ptx myfun.cu

这个生成文件命名myfun.ptx

构建CUDAKernel对象与铜文件输入

与一个.cu文件和一个.ptx您可以创建一个文件CUDAKernel对象在MATLAB计算内核,然后您可以使用:

k = parallel.gpu.CUDAKernel (“myfun.ptx”,“myfun.cu”);

请注意

你不能保存负载CUDAKernel对象。

构建CUDAKernel对象与C原型输入

如果你没有铜文件对应PTX文件,您可以指定C原型C内核而不是铜的文件。例如:

k = parallel.gpu.CUDAKernel (“myfun.ptx”,“浮*,const *浮动,浮动”);

输入C原型的另一个用途是当你的源代码使用一个未被重命名一个受支持的数据类型。金宝app(见下面的支持类型金宝app。)假设您的内核包含以下代码。

typedef ArgType浮动;__global__空白add3 (ArgType * v1, const ArgType * v2) {int idx = threadIdx.x;[idx] v1 + v2 = [idx];}

ArgType本身是不被认为是一个受支持的数据类型,所以铜文件,包括它不能金宝app直接用作输入MATLAB中创建CUDAKernel时对象。然而,支持输入类型金宝appadd3内核可以指定为C原型CUDAKernel构造函数的输入。例如:

k = parallel.gpu.CUDAKernel (“test.ptx”,“浮浮*,const *”,“add3”);

金宝app支持的数据类型

支持C 金宝app/ c++标准数据类型列在下表中。

浮点数类型 整数类型 布尔和字符类型

,double2

浮动,float2

,无符号短,short2,ushort2

int,无符号整型,int2,uint2

,无符号长,马龙,ulong2

很久很久,无符号长时间长,longlong2,ulonglong2

ptrdiff,size_t

bool

字符,无符号字符,char2,uchar2

另外,以下支持当你包括整数类型金宝apptmwtypes.h在程序头文件。

整数类型

int8_T,int16_T,int32_T,int64_T

uint8_T,uint16_T,uint32_T,uint64_T

头文件是出货matlabroot/走读生/ include / tmwtypes.h。包括文件与程序:

# include“tmwtypes.h”

参数的限制

所有输入可以是标量或指针,可以标记常量

C内核总是宣言的形式:

__global__空白aKernel(输入…)
  • 内核必须返回什么,只能在其输入参数(标量或指针)。

  • 一个内核无法分配任何形式的内存,所以所有输出之前必须预先分配内核执行。因此,所有的输出必须是已知的大小之前运行的内核。

  • 原则上,所有指针传递给内核常量可能含有输出数据,因为很多线程的内核可以修改该数据。

当翻译内核在C到MATLAB的定义:

  • 所有标量输入C (,浮动,int在MATLAB等)必须标量,或标量(即。单元素)gpuArray变量。

  • 所有常量指针在C输入(const双*等)可以是标量或在MATLAB矩阵。他们把正确的类型,复制到设备上,和一个指针指向第一个元素传递给内核。没有原始大小的信息传递给内核。好像内核直接收到的结果mxGetData在一个mxArray

  • 所有非常数的指针输入C是转移到内核中一样非常数的指针。然而,由于一个非常数的指针可以改变由内核,这将被视为一个输出从内核。

  • 从MATLAB工作区标量、数组输入转换为请求的类型,然后传递给内核。然而,gpuArray输入不会自动投,所以它们的类型和复杂性必须精确匹配这些预期。

这些规则有一些影响。最值得注意的是,每输出一个内核必须也必然是一个内核的输入,输入允许用户自定义大小的输出(GPU)从无法分配内存。

CUDAKernel对象属性

当你创建一个内核对象没有终止分号,或者当你在命令行类型对象变量,MATLAB显示内核对象属性。例如:

k = parallel.gpu.CUDAKernel (“conv.ptx”,“conv.cu”)
k = parallel.gpu。CUDAKernelhandle Package: parallel.gpu Properties: ThreadBlockSize: [1 1 1] MaxThreadsPerBlock: 512 GridSize: [1 1 1] SharedMemorySize: 0 EntryPoint: '_Z8theEntryPf' MaxNumLHSArguments: 1 NumRHSArguments: 2 ArgumentTypes: {'in single vector' 'inout single vector'}

一个内核对象的属性控制的执行行为。使用点符号改变那些可以改变的属性。

对象属性的描述,请参阅CUDAKernel对象引用页面。一个典型的原因修改可设置的属性是指定线程的数量,如下所述。

指定入口点

如果你PTX文件包含多个入口点,您可以识别特定的内核myfun.ptx你想要的内核对象k引用:

k = parallel.gpu.CUDAKernel (“myfun.ptx”,“myfun.cu”,“myKernel1”);

一个PTX文件可以包含多个入口点不同的内核。每一个入口点都有一个惟一名称。这些名字通常破坏(如c++矫直)。然而,当生成的学校网站PTX名称总是从铜文件包含原始的函数名称。例如,如果铜文件定义内核函数

__global__空白simplestKernelEver (* x浮动,浮动val)

然后PTX可能被称为代码包含一个条目_Z18simplestKernelEverPff

当你有多个入口点,指定特定的条目名称调用内核CUDAKernel生成您的内核。

请注意

CUDAKernel函数搜索PTX文件中的条目名称,和匹配子串出现。因此,你不应该名称条目的子字符串的任何其他人。

你可能没有控制原始条目名称,在这种情况下,你必须意识到独特的破坏为每个派生而来。例如,考虑下面的函数模板。

模板< typename T > __global__空白add4 (T * v1, const T * v2) {int idx = threadIdx.x;[idx] v1 + v2 = [idx];}

当模板扩展为浮点数和双精度数,它导致两个入口点,这两个包含子字符串add4

模板__global__空白add4 <飘>(浮浮*,const *);模板__global__空白add4 <双>(双*,const双*);

PTX有相应的条目:

_Z4add4IfEvPT_PKS0_ _Z4add4IdEvPT_PKS0_

使用入口点add4If浮动的版本,和add4Id双版本。

k = parallel.gpu.CUDAKernel (“test.ptx”,“双*,const双*’,“add4Id”);

指定的线程数量

你指定计算线程的数量CUDAKernel通过设置两个对象的属性:

  • GridSize-一个向量的三个元素,产品确定块的数量。

  • ThreadBlockSize-一个向量的三个元素,产品决定了每个块的线程数量。(注意产品不能超过财产的价值MaxThreadsPerBlock。)

这两个属性的默认值(1 1 1),但是假设您想使用500个线程运行element-wise并行向量的500个元素上的操作。一个简单的方法来实现这一目标是创建你的CUDAKernel并相应地设置它的属性:

k = parallel.gpu.CUDAKernel (“myfun.ptx”、“myfun.cu”);k。ThreadBlockSize =(500年,1,1);

一般来说,设置网格和线程块大小根据你输入的大小。有关线程层次结构的信息,和多维网格块,看到NVIDIA CUDA C编程指南。

运行一个CUDAKernel

使用函数宏指令函数来评估一个CUDAKernel GPU。下面的例子展示如何使用MATLAB工作区执行内核变量和gpuArray变量。

使用工作空间变量

假设你已经写了一些内核在母语和想使用MATLAB在GPU执行。你有一个内核,卷积两个向量;加载并运行这两个随机输入向量:

k = parallel.gpu.CUDAKernel (“conv.ptx”,“conv.cu”);结果=函数宏指令(k,兰德(100 1),兰特(100 1));

即使输入常量或变量对于MATLAB工作区数据,输出gpuArray

使用gpuArray变量

它可能是更有效的使用gpuArray对象作为输入一个内核运行时:

k = parallel.gpu.CUDAKernel (“conv.ptx”,“conv.cu”);i1 = gpuArray (rand(100年1“单一”));i2 = gpuArray (rand(100年1“单一”));result1 =函数宏指令编写此表达式(k, i1、i2);

因为输出是一个gpuArray,您现在可以执行其他操作使用该输入或输出数据没有进一步的MATLAB工作区和GPU之间的转移。当你所有的GPU计算完成后,收集你的最终结果数据为MATLAB工作区:

result2 =函数宏指令(k, i1、i2);r1 =收集(result1)编写此表达式;r2 =收集(result2);

确定输入和输出对应

当调用[着干活,out2] =函数宏指令(内核、三机in2 in3),输入三机一体,in2,in3对应于每个输入参数铜中的C函数文件。输出着干活out2商店第一和第二non-const指针的值输入参数后的C函数C内核被执行。

例如,如果C内核在铜文件有以下签名:

空白reallySimple(*引出线浮动,浮动c)

相应的内核对象(k在MATLAB具有以下属性:

MaxNumLHSArguments: 1 NumRHSArguments: 2 ArgumentTypes: {“inout单一向量”的单标量}

因此,要从这个代码使用内核对象函数宏指令,你需要提供函数宏指令两个输入参数(除了内核对象),你可以使用一个输出参数:

y =函数宏指令(k, x1, x2)

输入值x1x2对应于引出线c在C函数原型。输出参数y对应的值引出线后的C函数原型C内核执行。

下面是一个稍微复杂一点的例子,显示了一个常量和non-const指针:

空白moreComplicated (const浮针,* pInOut1浮动,浮动* pInOut2)

在MATLAB的对应内核对象的属性:

MaxNumLHSArguments: 2 NumRHSArguments: 3 ArgumentTypes:{“单一向量”“inout单一向量”“inout单一向量”}

您可以使用函数宏指令这段代码的内核(k与语法):

(y1, y2) =函数宏指令(k, x1, x2, x3)

三个输入参数x1,x2,x3,对应于三个参数传递给C函数。输出参数日元y2,对应的值pInOut1pInOut2C内核后执行。

完整的内核工作流程

添加两个数字

本例中添加了两个双打在GPU。你应该安装NVIDIA CUDA工具包,CUDA-capable你的设备的驱动程序。

  1. 铜的代码如下。

    __global__空白add1(双*π,双c) {* pi + = c;}

    该指令__global__表明这是一个内核的入口点。代码使用一个指针发出的结果π,这是一个输入和一个输出。把这段代码在一个文件中test.cu在当前目录中。

  2. 在shell命令行编译铜代码生成PTX文件test.ptx

    nvcc -ptx test.cu
  3. 在MATLAB中创建内核。目前这个PTX文件只有一个条目,这样你不需要指定它。如果你把更多的内核,您将指定add1的条目。

    k = parallel.gpu.CUDAKernel (“test.ptx”,“test.cu”);
  4. 运行内核有两个数字输入。默认情况下,内核上运行一个线程。

    结果=函数宏指令(k, 2、3)
    结果= 5

添加两个向量

这个例子添加两个向量扩展了前一个。为简单起见,假设有完全相同的线程数为元素的向量和只有一个线程阻塞。

  1. 铜的代码从最后一个例子略有不同。输入都是指针,一个是恒定的,因为你没有改变它。每个线程只会在它的线程添加元素的索引。线程索引必须该线程应该增加哪些元素。(这些线程,屏蔽一些值是一种很常见的模式在CUDA编程)。

    __global__空白add2(双* v1, const双* v2) {int idx = threadIdx.x;[idx] v1 + v2 = [idx];}

    将这些代码保存在文件中test.cu

  2. 编译之前使用学校网站

    nvcc -ptx test.cu
  3. 如果这段代码被放在相同的铜文件连同第一个例子的代码,您需要指定入口点名字来区分它。

    k = parallel.gpu.CUDAKernel (“test.ptx”,“test.cu”,“add2”);
  4. 运行内核之前,设置正确的线程数量你想要添加的向量。

    N = 128;k。ThreadBlockSize = N;三机一体= 1 (N, 1,“gpuArray”);in2 = 1 (N, 1“gpuArray”);结果=函数宏指令(k,三机一体,in2);

与铜和PTX文件示例

为例,展示了如何使用CUDA,并提供铜和PTX文件给你尝试,看看说明三种方法GPU计算:了曼德尔勃特集合

另请参阅

|

相关的话题