主要内容

说明三种方法GPU计算:了曼德尔勃特集合

这个例子展示了如何适应你的MATLAB®代码使用GPU计算了曼德尔勃特集合。

从现有的算法,这个例子展示了如何适应您的代码使用并行计算工具箱™利用GPU硬件在三个方面:

  1. 使用现有的算法,但GPU数据作为输入

  2. 使用arrayfun独立对每个元素执行算法

  3. 使用MATLAB / CUDA接口运行一些现有的CUDA / c++代码

设置

下面的值指定高度放大了曼德尔勃特集合的一部分之间的谷主心形和p / q灯泡了。

1000 x1000电网的部分(X)和虚部(Y)创建这些限制和曼德布洛特算法迭代之间在每个网格的位置。对于这个位置500次迭代足以充分渲染图像。

maxIterations = 500;gridSize = 1000;xlim = [-0.748766713922161, -0.748766707771757];ylim = [0.123640844894862, 0.123640851045266];

在MATLAB了曼德尔勃特集合

下面是一个使用标准的MATLAB实现了曼德尔勃特集合命令在CPU上运行。这是基于提供的代码在克里夫硅藻土“与MATLAB实验”电子书。

这个计算是矢量化,这样每一个位置更新。

%设置t =抽搐();xlim x = linspace (xlim (1), (2), gridSize);ylim y = linspace (ylim (1), (2), gridSize);[xGrid, yGrid] = meshgrid (x, y);z0 = xGrid + 1我* yGrid;数= 1(大小(z0));%计算z = z0;n = 0: maxIterations z z =。* z + z0;在= abs (z) < = 2;数=数+内部;结束数=日志(数);%显示cpuTime = toc (t);无花果= gcf;fig.Position = (200 200 600 600);显示亮度图像(x, y,数);colormap([飞机();flipud(飞机());0 0 0));轴标题(sprintf (' % 1.2 fsecs (GPU) 'cpuTime));

图包含一个坐标轴对象。坐标轴对象标题4.31秒(没有GPU)包含一个类型的对象的形象。

使用gpuArray

当MATLAB遇到GPU数据、计算数据在GPU上执行。类gpuArray提供GPU版本的许多功能,您可以使用它们来创建数据数组,包括linspace,logspace,meshgrid功能需要。类似地,数组初始化直接在GPU上使用函数

与这些变化计算初始化的数据将会在GPU上执行:

%设置t =抽搐();x = gpuArray。linspace(xlim(1), xlim(2), gridSize ); y = gpuArray.linspace( ylim(1), ylim(2), gridSize ); [xGrid,yGrid] = meshgrid( x, y ); z0 = complex( xGrid, yGrid ); count = ones( size(z0),“gpuArray”);%计算z = z0;n = 0: maxIterations z z =。* z + z0;在= abs (z) < = 2;数=数+内部;结束数=日志(数);%显示数=收集(数);%从GPU获取数据naiveGPUTime = toc (t);显示亮度图像轴(x, y,计数)标题(sprintf (' % 1.3 fsecs(天真的GPU) = % 1.1外汇更快,naiveGPUTime cpuTime / naiveGPUTime))

图包含一个坐标轴对象。坐标轴对象与标题快0.262秒(天真的GPU) = 16.4 x包含一个类型的对象的形象。

Element-wise操作

指出该算法操作同样在输入的每一个元素,我们可以把一个helper函数中的代码和调用使用arrayfun。使用GPU数组输入的功能arrayfun被编译成原生GPU的代码。在这种情况下,我们把循环pctdemo_processMandelbrotElement.m:

函数计算= pctdemo_processMandelbrotElement (x0, y0, maxIterations) z0 =复杂(x0, y0);z = z0;数= 1;而(数< = maxIterations) & & (abs (z) < = 2)数=计数+ 1;z = * z + z0;结束数=日志(数);

注意,提前中止引入了因为这个函数过程只有一个元素。对于大多数的看法了曼德尔勃特集合大量的元素很早就停止,这可以节省许多处理。的循环也被取代了循环,因为他们通常更有效率。这个函数没有提及的GPU和不使用任何GPU-specific特性——它是标准的MATLAB代码。

使用arrayfun意味着,而不是成千上万的调用单独GPU-optimized操作(至少6每个迭代),我们打一个电话到GPU并行操作,执行整个计算。这会显著减少开销。

%设置t =抽搐();x = gpuArray。linspace(xlim(1), xlim(2), gridSize ); y = gpuArray.linspace( ylim(1), ylim(2), gridSize ); [xGrid,yGrid] = meshgrid( x, y );%计算数= arrayfun (@pctdemo_processMandelbrotElement,xGrid、yGrid maxIterations);%显示数=收集(数);%从GPU获取数据gpuArrayfunTime = toc (t);显示亮度图像轴(x, y,计数)标题(sprintf (' % 1.3 fsecs (GPU arrayfun) = % 1.1外汇更快的,gpuArrayfunTime cpuTime / gpuArrayfunTime));

图包含一个坐标轴对象。坐标轴对象与标题快0.045秒(GPU arrayfun) = 96.2 x包含一个类型的对象的形象。

使用CUDA

MATLAB实验改进的性能是通过转换C-Mex函数的基本算法。如果你愿意做一些工作在C / c++中,那么您可以使用并行计算工具箱使用MATLAB调用预先写好的CUDA内核数据。你这样做的parallel.gpu.CUDAKernel特性。

CUDA / c++实现手写在元素的处理算法pctdemo_processMandelbrotElement.cu:这个必须手动编译使用nVidia的NVCC编译器生成程序pctdemo_processMandelbrotElement.ptx(.ptx代表“并行线程执行语言”)。

CUDA / c++代码比MATLAB版本更涉及到目前为止我们已经看到,由于缺乏c++的复数。然而,该算法的本质是不变的:

__device__ unsigned int doIterations(双const realPart0,双const imagPart0, unsigned int const maxIters){/ /初始化:z = z0双realPart = realPart0;双imagPart = imagPart0;无符号整型数= 0;/ /循环直到逃脱而((数< = maxIters) & & ((realPart * realPart + imagPart * imagPart) < = 4.0)){+ +计数;/ /更新:z = * z + z0;双const oldRealPart = realPart;realPart = realPart * realPart - imagPart * imagPart + realPart0;imagPart = 2.0 * oldRealPart * imagPart + imagPart0;}返回计数;}

一个GPU线程需要在了曼德尔勃特集合地点,分成块的线程。内核表示多大的线程阻塞,在以下代码中,我们使用这个来计算所需的线程阻塞。这就变成了GridSize

%加载内核cudaFilename =“pctdemo_processMandelbrotElement.cu”;ptxFilename = [“pctdemo_processMandelbrotElement”。parallel.gpu.ptxext);内核= parallel.gpu。CUDAKernel (ptxFilename cudaFilename);%设置t =抽搐();x = gpuArray。linspace(xlim(1), xlim(2), gridSize ); y = gpuArray.linspace( ylim(1), ylim(2), gridSize ); [xGrid,yGrid] = meshgrid( x, y );%确保我们有足够的块覆盖所有的位置numElements =元素个数(xGrid);内核。ThreadBlockSize = (kernel.MaxThreadsPerBlock 1 1);内核。GridSize = [(numElements / kernel.MaxThreadsPerBlock),即:1);%调用内核数= 0(大小(xGrid),“gpuArray”);数=函数宏指令(内核、计数xGrid、yGrid maxIterations, numElements);%显示数=收集(数);%从GPU获取数据gpuCUDAKernelTime = toc (t);显示亮度图像轴(x, y,计数)标题(sprintf (' % 1.3 fsecs (GPU CUDAKernel) = % 1.1外汇更快的,gpuCUDAKernelTime cpuTime / gpuCUDAKernelTime));

图包含一个坐标轴对象。坐标轴对象与标题快0.025秒(GPU CUDAKernel) = 175.9 x包含一个类型的对象的形象。

总结

这个例子展示了三种方法的MATLAB算法可以适应利用GPU硬件:

  1. 将输入数据转换成在GPU上使用gpuArray,使得该算法不变

  2. 使用arrayfun在一个gpuArray输入的每个元素上执行该算法独立输入

  3. 使用parallel.gpu.CUDAKernel一些现有的CUDA / c++代码运行使用MATLAB数据

标题(曼德尔勃特集合在GPU的)

图包含一个坐标轴对象。坐标轴对象与标题GPU上了曼德尔勃特集合包含一个类型的对象的形象。

另请参阅

|

相关的话题