主要内容GydF4y2Ba

衡量和提高GPU性能GydF4y2Ba

GPU基准测试入门GydF4y2Ba

您可以在MATLAB中使用各种基准测试GydF4y2Ba®GydF4y2Ba衡量GPU的表现:GydF4y2Ba

  • 用GydF4y2BaGpubench.GydF4y2Ba在MATLAB中央文件交换中进行各种测试,包括内存和单个双精度的内存和计算密集型任务。使用计算卡进行比较显示卡的性能。有关更多信息,请参阅GydF4y2Ba//www.tatmou.com/matlabcentral/fileexchange/34080-gpubench.GydF4y2Ba.GydF4y2Ba

  • 使用GydF4y2Baparalleldemo_gpu_benchGydF4y2Ba脚本GydF4y2Ba测量GPU性能GydF4y2Ba要获取有关您的PCI总线速度的信息,GPU内存读/写和用于双重精密矩阵计算的峰值计算性能。GydF4y2Ba

使用单精度计算提高性能GydF4y2Ba

你可以通过单精度而不是双精度的计算来提高GPU的性能。另一方面,在CPU计算中,当从双精度切换到单精度时,不会得到这种改进。究其原因,大多数GPU卡都是为图形显示而设计的,对单精度性能的要求很高。GydF4y2Ba

在GPU上适用于单精度计算的典型计算示例包括图像处理和机器学习。GydF4y2Ba//www.tatmou.com/content/dam/mathworks/tag-team/objects/d/deep_learning_in_cloud_whitepaper.pdf.GydF4y2Ba.然而,其他类型的计算,如线性代数问题,通常需要双精度处理。GydF4y2Ba

与双精度计算相比,单精度计算的性能提高高达50倍,这取决于GPU卡和核心总数。高端计算卡通常表现出较小的改进。您可以通过使用确定特定GPU的性能改进GydF4y2BaGpubench.GydF4y2Ba, 看GydF4y2Ba//www.tatmou.com/matlabcentral/fileexchange/34080-gpubench.GydF4y2Ba.GydF4y2Ba

综合性能概述NVIDIAGydF4y2Ba®GydF4y2BaGPU卡,看到GydF4y2Bahttps://en.wikipedia.org/wiki/List_of_Nvidia_graphics_processing_unitsGydF4y2Ba.计算单精度和双精度之间的性能提升系数如下:GydF4y2Ba

  • 在上面的Wiki页面上找到GPU。GydF4y2Ba

  • 从表中获取已所述的单个和双重精度性能值。如果没有双精度GFLOPS值,则假设双精度的比率为24-32倍。GydF4y2Ba

  • 通过双重精度GFLOPS值划分规定的单精度GFLOPS值。GydF4y2Ba

笔记GydF4y2Ba

如果您的笔记本电脑中有移动图形卡,可以使用此卡进行GPU计算。但是,笔记本电脑GPU可能比桌面机当量强大,因此性能降低。GydF4y2Ba

用于提高性能的基本工作流程GydF4y2Ba

在MATLAB中进行GPU计算的目的是加快应用程序的速度。本主题讨论了一些基本概念和实践,它们可以帮助你在GPU上获得更好的性能,比如GPU硬件的配置和代码中的最佳实践。本文讨论了实现难度和性能之间的权衡,并描述了在使用gpuArray函数、GydF4y2BaArrayfun.GydF4y2Ba、MEX-files或CUDA内核。最后,介绍了如何在GPU上准确地测量性能。GydF4y2Ba

将MATLAB代码转换为在GPU上运行时,最好从已经执行良好的MATLAB代码开始。虽然GPU和CPU具有不同的性能特征,但是写作Good Matlab代码的一般指南也帮助您为GPU编写好的Matlab代码。第一步几乎总是概括为您的CPU代码。探查器显示在CPU上最多时间的代码线可能是您必须集中注意力的何时代码GPU。GydF4y2Ba

最简单的是使用支持GPUARRAY数据的MATLAB内置函数来开始转换代码。金宝app这些函数取GPUArray输入,在GPU上执行计算,并返回GPUArray输出。找到支持GPUARRAY数据的MATLAB函数的列表金宝appGydF4y2Ba在GPU上运行matlab函数GydF4y2Ba.通常,这些函数支持与在CPU上计算的标准MATLAB函数金宝app相同的参数和数据类型。GydF4y2Ba

如果GPU支持您要使用的所有功能,GPU上的运行代码可以像调用一样简单金宝appGydF4y2BaGPUArray.GydF4y2Ba将输入数据转移到GPU,并调用GydF4y2Ba收集GydF4y2Ba完成后从GPU检索输出数据。在许多情况下,您可能需要将代码矢量化,用Matlab矩阵和矢量操作替换循环的标量操作。虽然矢量化通常是CPU的良好做法,但对于在GPU上实现高性能通常是至关重要的。有关更多信息,请参阅GydF4y2Ba矢量化,提高GPU性能GydF4y2Ba.GydF4y2Ba

提高性能的高级工具GydF4y2Ba

即使在将输入转换为gpuArrays并对代码进行向量化之后,算法中的一些操作也可能不是内置函数,或者速度不够快,无法满足应用程序的需求。在这种情况下,您有三个主要选择:useGydF4y2BaArrayfun.GydF4y2Ba要预编译应用程序的元素,请使用GPU库函数,或写入自定义CUDA内核。GydF4y2Ba

如果您有一个纯粹的元素函数,可以通过调用它来提高其性能GydF4y2BaArrayfun.GydF4y2Ba.这GydF4y2BaArrayfun.GydF4y2Ba函数在GPU上把一个元素的MATLAB函数变成一个定制的CUDA内核,从而减少执行操作的开销。通常,应用程序的一个子集可以与GydF4y2BaArrayfun.GydF4y2Ba即使整个应用程序不能。这个例子GydF4y2Ba使用Arrayfun提高元素-WiseMatlab®功能的性能GydF4y2Ba显示这种方法的基本概念;和这个例子GydF4y2Ba使用GPU Arrayfun进行Monte-Carlo模拟GydF4y2Ba展示如何在仿真中进行金融应用程序。GydF4y2Ba

MATLAB在并行计算工具箱™,图像处理工具箱™,信号处理工具箱™等产品中提供了广泛的GPU功能库。下载188bet金宝搏但是,在Matlab的GPU支持中没有具有直接内置模拟的附加功能的库。金宝app示例包括NVIDIA性能原语库和卷曲库,其包含在MATLAB的CUDA工具包中。如果您需要在其中一个库中调用函数,则可以使用GPU MEX接口来执行此操作。此界面允许您从Matlab GPUArrays将指针提取到设备数据,以便您可以将这些指针传递给GPU功能。您可以将返回的值转换为GPUARRAEDS以返回MATLAB。有关更多信息,请参阅GydF4y2Ba运行包含CUDA代码的MEX函数GydF4y2Ba.GydF4y2Ba

最后,您可以选择为您需要的操作编写自定义CUDA内核。这种内核可以使用Cudakernel对象直接集成到Matlab中。GydF4y2Ba

这个例子GydF4y2Ba说明GPU计算的三种方法:曼德尔布罗特集GydF4y2Ba展示如何使用本节中提到的三种方法来实现简单的计算。此示例从MATLAB代码开始,该代码很容易转换为在GPU上运行,重写用于使用的代码GydF4y2BaArrayfun.GydF4y2Ba对于Element-Wise操作,最后显示如何为同一操作集成自定义CUDA内核。GydF4y2Ba

或者,您可以将CUDA内核写入MEX文件的一部分,并使用MEX文件中的CUDA运行时API调用它。这些方法中的任何一个都可能让您使用GPU的低级功能,例如共享内存和纹理内存,这在MATLAB代码中不可直接可用。有关更多详细信息,请参阅示例GydF4y2Ba使用MEX访问高级CUDA功能GydF4y2Ba.GydF4y2Ba

提高性能的最佳实践GydF4y2Ba

硬件配置GydF4y2Ba

通常,当您的GPU专用于计算时,您可以实现最佳性能。由于对图形的合理尺寸和设备的持续使用,因此使用相同的GPU设备通常不实际使用相同的GPU设备,因此使用相同的GPU设备,并且通过用于图形的系统持续使用设备的内存量。如果可能,请获取用于图形的单独设备。为计算或图形配置设备的详细信息取决于操作系统和驱动程序版本。GydF4y2Ba

在Windows上GydF4y2Ba®GydF4y2Ba系统中,GPU设备有两种模式:WDDM (Windows Display Driver Model)和TCC (Tesla Compute Cluster)模式。为了获得最佳性能,用于计算的任何设备都应该处于TCC模式。更多细节请参考NVIDIA文档。GydF4y2Ba

NVIDIA的最高性能计算设备特斯拉线,在读写GPU内存时支持错误纠正代码(ECC)。金宝appECC的目的是纠正读写动态内存时偶尔出现的正常误码。一种提高性能的技术是关闭ECC以增加可实现的内存带宽。虽然硬件可以以这种方式配置,但MathWorks不推荐这种做法。由于无声错误而造成的潜在的准确性损失可能比性能好处更有害。GydF4y2Ba

MATLAB编码实践GydF4y2Ba

本主题介绍帮助您在GPU上获得更好性能的一般技术。这些技巧也适用于为CPU编写MATLAB代码。GydF4y2Ba

MATLAB阵列中的数据以列 - 主要订单存储。因此,沿着阵列的第一或列维操作是有益的。如果您的数据的一个维度明显长于其他维度,如果您认为第一个维度可能会达到更好的性能。同样,如果您经常沿特定维度操作,通常最好将其作为第一维度。在某些情况下,如果连续操作针对数组的不同维度,则可能有利于在这些操作之间转换或释放阵列。GydF4y2Ba

GPU通过计算许多结果并行地实现高性能。因此,矩阵和高维阵列操作通常比在向量或标量上的操作更好地执行。您可以通过重写循环来实现更好的性能,以利用更高维度操作。修改基于循环的标量代码以使用MATLAB矩阵和矢量操作的过程称为矢量化。有关更多详细信息,请参阅GydF4y2Ba使用向量化GydF4y2Ba.GydF4y2Ba

缺省情况下,MATLAB中的所有操作都在双精度浮点算术中执行。但是,大多数操作支持各种数据类型,包括整数和单精度金宝app浮点。当执行单精度操作时,今天的GPU和CPU通常具有更高的吞吐量,并且单精度浮点数据占据更少的内存。如果您的应用程序的准确性要求允许使用单精度浮点,它可以大大提高MATLAB代码的性能。GydF4y2Ba

GPU位于被称为PCI总线的数据传输机制的末端。虽然这种总线是一种高效的、高带宽的方式来将数据从PC主机内存传输到各种扩展卡,但它仍然比GPU设备或CPU的全局内存的总体带宽要慢得多(更多细节,参见示例)GydF4y2Ba测量GPU性能GydF4y2Ba)。此外,从GPU设备转移到MATLAB主机内存会导致MATLAB等待设备上的所有待处理操作,以便在执行任何其他语句之前完成。这可以显着损害您的应用程序的性能。通常,您应该限制在MATLAB工作区和GPU之间传输数据的次数。如果您可以在应用程序开始时将数据传输到GPU一次,请执行GPU上可以在GPU上的所有计算,然后将结果转换回MATLAB,通常会导致最佳性能。同样,当可能的时,它有助于使用alce在gpu上创建阵列,使用GydF4y2Ba“gpuArray”GydF4y2Ba或者GydF4y2Ba'喜欢'GydF4y2Ba诸如GydF4y2BaZeros.GydF4y2Ba(例如,GydF4y2Baz = zeros(___,'gpuarray')GydF4y2Ba或GydF4y2BaZ = 0 (N,“喜欢”,g)GydF4y2Ba对于现有的GPUArrayGydF4y2BaGGydF4y2Ba)。GydF4y2Ba

测量GPU上的性能GydF4y2Ba

测量GPU上性能的最佳方法是使用GydF4y2Bagputimeit.GydF4y2Ba.这个函数接受不带输入参数的函数句柄作为输入,并返回该函数测量的执行时间。它考虑了诸如重复计时操作以获得更好的分辨率、在测量前执行函数以避免初始化开销、以及减去计时函数的开销等基准测试考虑。同时,GydF4y2Bagputimeit.GydF4y2Ba确保GPU上的所有操作在最终定时之前已经完成。GydF4y2Ba

例如,考虑测量计算计算的时间GydF4y2Ba陆GydF4y2Ba随机矩阵的分解GydF4y2Ba一种GydF4y2Ba大小GydF4y2BaNGydF4y2Ba——- - - - - -GydF4y2BaNGydF4y2Ba.您可以通过定义一个函数来实现这一点GydF4y2Ba陆GydF4y2Ba将函数句柄分解并传递给GydF4y2Bagputimeit.GydF4y2Ba:GydF4y2Ba

a = rand(n,GydF4y2Ba“gpuArray”GydF4y2Ba);fh = @()lu(a);gputimeit(fh,2);GydF4y2Ba%2nd arg表示输出数量GydF4y2Ba

您还可以测量性能GydF4y2BaTic.GydF4y2Ba和GydF4y2BaTOC.GydF4y2Ba.然而,为了在GPU上获得准确的定时,你必须在调用之前等待操作完成GydF4y2BaTOC.GydF4y2Ba.有两种方法可以做到这一点。你可以打电话GydF4y2Ba收集GydF4y2Ba在调用之前对最终的GPU输出进行处理GydF4y2BaTOC.GydF4y2Ba:这迫使所有计算在采用时间测量之前完成。或者,你可以使用GydF4y2Ba等待GydF4y2Ba功能与A.GydF4y2BaGPudevice.GydF4y2Ba对象作为其输入。例如,如果您想测量计算计算的时间GydF4y2Ba陆GydF4y2Ba矩阵的分解GydF4y2Ba一种GydF4y2Ba使用GydF4y2BaTic.GydF4y2Ba那GydF4y2BaTOC.GydF4y2Ba,GydF4y2Ba等待GydF4y2Ba,您可以按如下方式执行以下操作:GydF4y2Ba

gd = gpudevice();Tic();[l,u] = lu(a);等待(GD);tlu = toc();GydF4y2Ba

您还可以使用MATLAB分析器来显示计算时间是如何在您的GPU代码中分布的。注意,为了完成计时测量,分析器独立运行每一行代码,因此它不能解释在正常操作期间可能发生的重叠(异步)执行。为整个算法计时,您应该使用GydF4y2BaTic.GydF4y2Ba和GydF4y2BaTOC.GydF4y2Ba, 或者GydF4y2Bagputimeit.GydF4y2Ba, 如上所述。此外,如果自同步运行,配置文件可能不会为用户定义的MEX函数产生正确的结果。GydF4y2Ba

矢量化,提高GPU性能GydF4y2Ba

此示例显示如何通过在GPU上运行代替CPU的函数以及将计算中运行,以及将计算中运行以及矢量化来提高性能。GydF4y2Ba

考虑一个在矩阵列上执行快速卷积的函数。快速卷积,即信号处理应用程序中的常见操作,将来自时域的每列数据转换为频域,将其乘以滤波器向量的变换,转换回时域,并将结果存储在一个输出矩阵。GydF4y2Ba

函数GydF4y2Bay = FastConfulate(数据,过滤器)[m,n] =大小(数据);GydF4y2Ba%零焊盘过滤器到列的列长度和变换GydF4y2Bafilter_f = fft(过滤器,米);GydF4y2Ba%创建一个与数据相同大小和类的零数组GydF4y2Bay = 0 (m, n,GydF4y2Ba'喜欢'GydF4y2Ba,数据);GydF4y2Ba%转换每列数据列GydF4y2Ba为了GydF4y2Baix = 1:n af = fft(数据(:,ix));y(:,ix)= ifft(af。* filter_f);GydF4y2Ba结尾GydF4y2Ba结尾GydF4y2Ba

在CPU中对特定大小的数据执行此函数,并使用MATLAB测量执行时间GydF4y2Ba时代GydF4y2Ba功能。这GydF4y2Ba时代GydF4y2Ba函数负责常见的基准测试考虑事项,例如对启动和开销的核算。GydF4y2Ba

A =复合(Randn(4096,100),Randn(4096,100));GydF4y2Ba% 数据输入GydF4y2Bab = randn(16,1);GydF4y2Ba%滤波器输入GydF4y2Bac = FastConvolulate(A,B);GydF4y2Ba%计算输出GydF4y2Bactime = timeit(@()fastconvolulate(a,b));GydF4y2Ba%测量CPU时间GydF4y2BaDISP([GydF4y2Ba` CPU执行时间= 'GydF4y2Ba,num2str(立方)]);GydF4y2Ba

在示例机器上,下面的代码显示如下输出:GydF4y2Ba

CPU上的执行时间= 0.019335GydF4y2Ba

现在在GPU上执行此功能。您可以通过将输入数据更改为GPUARRAYS而不是普通MATLAB阵列来轻松实现此操作。这GydF4y2Ba'喜欢'GydF4y2Ba在函数内创建输出时使用的语法可确保GydF4y2BayGydF4y2Ba如果是一个gpuarrayGydF4y2Ba数据GydF4y2Ba是一个gpuarray。GydF4y2Ba

ga = gpuarray(a);GydF4y2Ba%移动数组到GPUGydF4y2Bagb = gpuarray(b);GydF4y2Ba%将过滤器移动到GPUGydF4y2Bagc = fastConvolution (ga、gb);GydF4y2Ba%计算GPUGydF4y2Bagtime = gputimeit(@()fastconvolules(ga,gb));GydF4y2Ba%测量GPU时间GydF4y2Bagerr = max(max(abs(group(gc)-c))));GydF4y2Ba%计算错误GydF4y2BaDISP([GydF4y2Ba'GPU ='执行时间GydF4y2Ba,num2str(gTime)]);DISP([GydF4y2Ba'最大绝对误差='GydF4y2Banum2str (gerr)]);GydF4y2Ba

在同一台机器上,此代码显示输出:GydF4y2Ba

CPU上的执行时间= 0.019335在GPU上的执行时间= 0.027235最大绝对误差= 1.1374E-14GydF4y2Ba

不幸的是,GPU在这个问题上比CPU慢。原因是GydF4y2Ba为了GydF4y2Ba-Loop正在执行长度4096的单个列上的FFT,乘法和逆FFT操作。增加性能的最佳方法是向码矢量化,以便单个MATLAB函数调用执行更多的计算。FFT和IFFT操作易于矢量化:GydF4y2BaFFT(a)GydF4y2Ba计算矩阵的每列的FFTGydF4y2Ba一种GydF4y2Ba.您可以使用MATLAB二进制标量扩展功能一次在矩阵中使用每列执行乘法率乘法GydF4y2BaBSXFUN.GydF4y2Ba.矢量化功能如下所示:GydF4y2Ba

函数GydF4y2BaY = FastConvolules_v2(数据,过滤器)m =大小(数据,1);GydF4y2Ba%零焊盘过滤器到数据的长度和变换GydF4y2Bafilter_f = fft(过滤器,米);GydF4y2Ba%转换输入的每列GydF4y2Ba房颤= fft(数据);GydF4y2Ba%通过滤波器乘以每个列并计算逆变换GydF4y2Bay = ifft(bsxfun(@ times,af,filter_f));GydF4y2Ba结尾GydF4y2Ba

使用矢量化功能执行相同的实验:GydF4y2Ba

A =复合(Randn(4096,100),Randn(4096,100));GydF4y2Ba% 数据输入GydF4y2Bab = randn(16,1);GydF4y2Ba%滤波器输入GydF4y2Bac = fastConvolution_v2 (a, b);GydF4y2Ba%计算输出GydF4y2Bactime = timeit(@()fastconvolules_v2(a,b));GydF4y2Ba%测量CPU时间GydF4y2BaDISP([GydF4y2Ba` CPU执行时间= 'GydF4y2Ba,num2str(立方)]);ga = gpuarray(a);GydF4y2Ba%将数据移动到GPUGydF4y2Bagb = gpuarray(b);GydF4y2Ba%将过滤器移动到GPUGydF4y2Bagc = fastconvolult_v2(ga,gb);GydF4y2Ba%计算GPUGydF4y2Bagtime = gputimeit(@()fastconvolules_v2(ga,gb));GydF4y2Ba%测量GPU时间GydF4y2Bagerr = max(max(abs(group(gc)-c))));GydF4y2Ba%计算错误GydF4y2BaDISP([GydF4y2Ba'GPU ='执行时间GydF4y2Ba,num2str(gTime)]);DISP([GydF4y2Ba'最大绝对误差='GydF4y2Banum2str (gerr)]);GydF4y2Ba
CPU上的执行时间= 0.010393在GPU上的执行时间= 0.0020537最大绝对误差= 1.1374E-14GydF4y2Ba

总之,矢量化代码有助于CPU和GPU版本以更快地运行。但是,矢量化有助于GPU版本多于CPU。改进的CPU版本与原始的速度几乎是速度的两倍;改进的GPU版本比原件快13倍。GPU代码从原始版本中的CPU慢40%,在修订版的版本中速度速度速度速度大约五倍。GydF4y2Ba

故障排除GPUS.GydF4y2Ba

如果您的计算机中只有一个GPU,那么您的显卡可能也充当您的显示卡。在这种情况下,您的GPU可能会受到操作系统(OS)强加的超时。您可以为您的GPU检查这一点,如下所示:GydF4y2Ba

GPudevice.GydF4y2Ba
ans =.GydF4y2Ba
......GydF4y2Ba
KernelexecutionTimeout:1GydF4y2Ba
如果GydF4y2BaKernelexecutionTimeout = 1GydF4y2Ba然后,您的GPU可能会受到操作系统强加的超时,确保操作系统始终能够打印到屏幕上的更新。如果您的GPU计算需要太多时间,那么操作就会被杀死。在这种情况下,您必须重新启动MATLAB以成功恢复GPU计算。GydF4y2Ba

也可以看看GydF4y2Ba

相关的话题GydF4y2Ba