主要内容

在GPU上对A\b进行基准测试

这个例子着眼于我们如何在GPU上对线性系统的求解进行基准测试。MATLAB®代码求解xA*x = b很简单。最常用的,我们使用矩阵左除法,也称为mldivide或反斜杠操作符(\)来计算x(即,x = A\b).

相关例子:

这个例子中显示的代码可以在这个函数中找到:

函数结果= paralleldemo_gpu_backslash(maxMemory)

为计算选择合适的矩阵大小是很重要的。我们可以通过指定CPU和GPU可用的系统内存量(单位为GB)来实现这一点。默认值仅基于GPU上可用的内存量,您可以指定一个适合您的系统的值。

如果nargin == 0 g = gpuDevice;maxMemory = 0.4*g.AvailableMemory/1024^3;结束

基准测试功能

我们想要基准矩阵左除法(\),而不是CPU和GPU之间传输数据的成本,创建矩阵所需的时间,或其他参数。因此,我们将数据生成与线性系统的求解分离开来,只测量求解后者所需的时间。

函数[A, b] = getData(n, clz) fprintf('创建大小为%d-by-%d.\n的矩阵', n, n);A = rand(n, n, clz) + 100*eye(n, n, clz);B = rand(n, 1, clz);结束函数time = timeSolve(A, b, waitFcn) tic;x = A\b;我们不需要x的值。waitFcn ();等待操作完成。时间= toc;结束

选择问题大小

与许多其他并行算法一样,并行求解线性系统的性能在很大程度上取决于矩阵的大小。如在其他例子中所见,例如基准\ b,比较了不同矩阵大小下算法的性能。

将矩阵大小声明为1024的倍数。maxSizeSingle = floor(√(maxMemory*1024^3/4));maxSizeDouble = floor(√(maxMemory*1024^3/8));Step = 1024;如果maxsize ouble/step >= 10 step = step*floor(maxsize ouble/(5*step));结束size = 1024:step:maxSizeSingle;size = 1024:step: maxsize ouble;

比较性能:千兆次

我们使用每秒浮点运算的数量作为性能的衡量标准,因为这允许我们比较不同矩阵大小下算法的性能。

给定矩阵大小,基准测试函数创建矩阵一个右边是b一次,然后解一个\ b多做几次,以准确测量所需的时间。我们使用HPC挑战赛的浮点运算计数,因此对于一个n × n矩阵,我们将浮点运算计数为2/3*n²+ 3/2*n²

该函数通过句柄传递给'wait'函数。在CPU上,这个函数没有任何作用。在GPU上,这个函数等待所有挂起的操作完成。以这种方式等待可以确保准确的时间。

函数gflops = benchFcn(A, b, waitFcn) numReps = 3;时间= inf;我们求解线性系统几次,计算出十亿次浮点运算。%基于最佳时间。itr = 1:numReps tcurr = timeSolve(A, b, waitFcn);Time = min(tcurr, Time);结束测量调用等待函数引入的开销。Tover = inf;itr = 1:numReps tic;waitFcn ();Tcurr = toc;Tover = min(tcurr, Tover);结束从测量时间中去除开销。不要让时间流逝%变成负数。Time = max(Time - tover, 0);n = size(A, 1);Flop = 2/3*n^3 + 3/2*n^2;Gflops = flop/time/1e9;结束CPU不需要等待:这个函数句柄是一个占位符。函数waitForCpu ()结束在GPU上,为了保证准确的计时,我们需要等待设备%来完成所有挂起的操作。函数waitForGpu(设备)等(设备);结束

执行基准测试

完成所有设置之后,执行基准测试就很简单了。然而,计算可能需要很长时间才能完成,因此我们在完成每个矩阵大小的基准测试时打印一些中间状态信息。我们还在函数中封装了所有矩阵大小的循环,以对单精度和双精度计算进行基准测试。

函数[gflopsCPU, gflopsGPU] = executebenchmark (clz, sizes) fprintf(['以%d不同的%s精度开始基准测试'...'大小从%d-by-%d到%d- %d的矩阵\n'),...长度(尺寸),clz,尺寸(1),尺寸(1),尺寸(end),...大小(结束));gflopsGPU = 0(大小(大小));gflopsCPU = 0(大小(大小));gd = gpuDevice;I = 1:长度(大小)n =大小(I);[A, b] = getData(n, clz);gflopsCPU(i) = benchFcn(A, b, @waitForCpu);流(千兆次CPU: %f\ngflopsCPU(我));A = gpuArray(A);b = gpuArray(b);gflopsGPU(i) = benchFcn(A, b, @() waitForGpu(gd));流(千兆次GPU: %f\ngflopsGPU(我));结束结束

然后以单精度和双精度执行基准测试。

[cpu, gpu] = executebenchmark (“单一”, sizeSingle);结果。sizeSingle = sizeSingle;结果。gflopsSingleCPU = cpu;结果。gflopsSingleGPU = gpu;[cpu, gpu] = executebenchmark (“双”, sizeDouble);结果。size ouble = size ouble;结果。gflopsDoubleCPU = cpu;结果。gflopsDoubleGPU = gpu;
从7个不同的单精度矩阵开始基准测试,其大小从1024 × 1024到19456 × 19456不等。创建大小为1024 * 1024的矩阵。CPU上的Gigaflops: 43.805496 GPU上的Gigaflops: 78.474002创建大小为4096 × 4096的矩阵。Gigaflops on CPU: 96.459635 Gigaflops on GPU: 573.278854创建一个大小为7168 × 7168的矩阵。Gigaflops on CPU: 184.997657 Gigaflops on GPU: 862.755636创建一个大小为10240 × 10240的矩阵。Gigaflops on CPU: 204.404384 Gigaflops on GPU: 978.362901创建一个大小为13312 × 13312的矩阵。Gigaflops on CPU: 218.773070 Gigaflops on GPU: 1107.983667创建大小为16384 × 16384的矩阵。CPU的Gigaflops: 233.529176 GPU的Gigaflops: 1186.423754创建一个大小为19456 × 19456的矩阵。CPU上的Gigaflops: 241.482550 GPU上的Gigaflops: 1199.151846使用5个不同的双精度矩阵启动基准测试,大小从1024 × 1024到13312 × 13312。创建大小为1024 * 1024的矩阵。 Gigaflops on CPU: 34.902918 Gigaflops on GPU: 72.191488 Creating a matrix of size 4096-by-4096. Gigaflops on CPU: 74.458136 Gigaflops on GPU: 365.339897 Creating a matrix of size 7168-by-7168. Gigaflops on CPU: 93.313782 Gigaflops on GPU: 522.514165 Creating a matrix of size 10240-by-10240. Gigaflops on CPU: 104.219804 Gigaflops on GPU: 628.301313 Creating a matrix of size 13312-by-13312. Gigaflops on CPU: 108.826886 Gigaflops on GPU: 681.881032

性能绘制

现在我们可以绘制结果,并比较CPU和GPU上的性能,包括单精度和双精度。

首先,我们看看反斜杠运算符在单精度方面的性能。

图;Ax =轴(“父”图);情节(ax,结果。sizeSingle results.gflopsSingleGPU,“- x”...结果。sizeSingle results.gflopsSingleCPU,“o”网格);传奇(“图形”“CPU”“位置”“西北”);标题(ax,单精度性能的) ylabel (ax,“吉拍”);包含(ax,矩阵大小的);drawnow;

现在,我们看看反斜杠运算符在双精度下的性能。

图;Ax =轴(“父”图);情节(ax,结果。sizeDouble results.gflopsDoubleGPU,“- x”...结果。sizeDouble results.gflopsDoubleCPU,“o”)传说(“图形”“CPU”“位置”“西北”);网格;标题(ax,“双精度性能”) ylabel (ax,“吉拍”);包含(ax,矩阵大小的);drawnow;

最后,我们看看GPU和CPU比较时反斜杠运算符的加速。

speedupDouble = results.gflopsDoubleGPU./results.gflopsDoubleCPU;speedupSingle = results.gflopsSingleGPU./results.gflopsSingleCPU;图;Ax =轴(“父”图);情节(ax,结果。sizeSingle speedupSingle,“v”...结果。sizeDouble speedupDouble,“- *”网格);传奇(单精度的“双精度”“位置”“东南”);标题(ax,GPU运算速度比CPU更快);ylabel (ax,“加速”);包含(ax,矩阵大小的);drawnow;

结束
ans = sizeSingle: [1024 4096 7168 10240 13312 16384 19456] gflopsSingleCPU: [1x7 double] gflopsSingleGPU: [1x7 double] sizeDouble: [1024 4096 7168 10240 13312] gflopsDoubleCPU: [34.9029 74.4581 93.3138 104.2198 108.8269] gflopsDoubleGPU: [72.1915 365.3399 522.5142 628.3013 681.8810]