《CUDA C编程权威指南》——3.3 并行性的表现

3.3 并行性的表现

为更好地理解线程束执行的本质,将使用不同的执行配置分析下述的sumMatrixOn-GPU2D核函数。使用nvprof配置指标,可以有助于理解为什么有些网格/块的维数组合比其他的组合更好。这些练习会提供网格和块的启发式算法,这是CUDA编程人员必备的技能。

二维矩阵求和的核函数如下所示:

在每个维度,用16 384个元素确定一个大矩阵:

下面的代码段使线程块的维数可以从命令行中进行配置:

从Wrox.com上可以下载sumMatrix.cu,在该文件中可以找到这个示例的完整代码。使用下面的命令编译代码。

在接下来的部分,将使用生成的sumMatrix对块和网格配置执行试验。

3.3.1 用nvprof检测活跃的线程束

首先,需要生成一个参考结果作为性能基准。为此,要先测试一组基础线程块的配置,尤其是大小为(32,32),(32,16),(16,32)和(16,16)的线程块。前面介绍过,sumMatrix接收线程块配置的x维作为它的第一个参数,接收线程块配置的y维作为它的第二个参数。通过用适当的命令行参数调用sumMatrix测试各种线程块配置。

在Tesla M2070上输出以下结果:

比较这些结果可以看到,最慢的性能是第一个线程块配置(32,32)。最快的是第二个线程块配置(32,16)。这样可以推断出,第二种情况比第一种情况有更多的线程块,因此它的并行性更好。这个理论可以用nvprof和achieved_occupancy指标来验证。一个内核的可实现占用率被定义为:每周期内活跃线程束的平均数量与一个SM支持的线程束最大数量的比值。结果总结如下(注意,如果系统中有多个GPU,可以用--devices命令行选项指挥nvprof从特定的设备中获取配置信息):

从结果中可以观察到两件事:

  • 因为第二种情况中的块数比第一种情况的多,所以设备就可以有更多活跃的线程束。其原因可能是第二种情况与第一种情况相比有更高的可实现占用率和更好的性能。
  • 第四种情况有最高的可实现占用率,但它不是最快的,因此,更高的占用率并不一定意味着有更高的性能。肯定有其他因素限制GPU的性能。

3.3.2 用nvprof检测内存操作

在sumMatrix内核(C[idx]=A[idx]+B[idx])中有3个内存操作:两个内存加载和一个内存存储。可以使用nvprof检测这些内存操作的效率。首先,用gld_throughput指标检查内核的内存读取效率,从而得到每个执行配置的差异:

第四种情况中的加载吞吐量最高,第二种情况中的加载吞吐量大约是第四种情况的一半,但第四种情况却比第二种情况慢。所以,更高的加载吞吐量并不一定意味着更高的性能。第4章介绍内存事务在GPU设备上的工作原理时将会具体分析产生这种现象的原因。

接下来,用gld_efficiency指标检测全局加载效率,即被请求的全局加载吞吐量占所需的全局加载吞吐量的比值。它衡量了应用程序的加载操作利用设备内存带宽的程度。结果总结如下:

从上述结果可知,最后两种情况下的加载效率是最前面两种情况的一半。这可以解释为什么最后两种情况下更高的加载吞吐量和可实现占用率没有产生较好的性能。尽管在最后两种情况下正在执行的加载数量(即吞吐量)很多,但是那些加载的有效性(即效率)是较低的。

注意,最后两种情况的共同特征是它们在最内层维数中块的大小是线程束的一半。如前所述,对网格和块启发式算法来说,最内层的维数应该总是线程束大小的倍数。第4章将讨论半个线程束大小的线程块是如何影响性能的。

3.3.3 增大并行性

从前一节可以总结出,一个块的最内层维数(block.x)应该是线程束大小的倍数。这样能极大地提高了加载效率。你可能对以下问题仍然很好奇:

  • 调整block.x会进一步增加加载吞吐量吗
  • 有其他方法可以增大并行性吗

现在已经建立了一个性能基准,可以通过测试sumMatrix使用更大范围的线程配置来回答这些问题:

从这些结果中可以总结出以下规律:

  • 最后一次的执行配置块的大小为(256,8),这是无效的。一个块中线程总数超过了1 024个(这是GPU的硬件限制)。
  • 最好的结果是第四种情况,块大小为(128,2)。
  • 第一种情况中块大小为(64,2),尽管在这种情况下启动的线程块最多,但不是最快的配置。
  • 因为第二种情况中块的配置为(64,4),与最好的情况有相同数量的线程块,这两种情况应该在设备上显示出相同的并行性。因为这种情况相比(128,2)仍然表现较差,所以你可以得出这样的结论:线程块最内层维度的大小对性能起着的关键的作用。这正重复了前一节中总结的结论。
  • 在所有其他情况下,线程块的数量都比最好的情况少。因此,增大并行性仍然是性能优化的一个重要因素。

你可能会想,线程块最少的那些示例应该显示出较低的可实现占用率,线程块最多的那些例子应该显示出较高的可实现占用率。这个理论可以用nvprof检测achieved_occu-pancy指标来验证一下:

从上面的结果可以得到,第一种情况(64,2)在所有例子中可实现占用率最低,但它的线程块是最多的。这种情况在线程块的最大数量上遇到了硬件限制。

第四种情况(128,2)和第七种情况(256,2),拥有最高的性能配置,有几乎相同的可实现占用率。在这两种情况下,通过将block.y设置为1来增大块间并行性,观察性能将如何变化。这使得每个线程块大小减少了,引起了更多的线程块被启动来处理相同数量的数据。这样做会产生以下结果:

到目前为止,这些配置能产生最佳的性能。特别是(256,1)的块配置优于(128,1)。可以使用以下的指令查看可实现占用率、加载吞吐量和加载效率:

结果如下:

值得注意的是,最好的执行配置既不具有最高的可实现占用率,也不具有最高的加载吞吐量。从这些实验中可以推断出,没有一个单独的指标能直接优化性能。我们需要在几个相关的指标间寻找一个恰当的平衡来达到最佳的总体性能。


时间: 2024-10-29 21:33:36

《CUDA C编程权威指南》——3.3 并行性的表现的相关文章

《CUDA C编程权威指南》——3.3节并行性的表现述

3.3 并行性的表现为更好地理解线程束执行的本质,将使用不同的执行配置分析下述的sumMatrixOn-GPU2D核函数.使用nvprof配置指标,可以有助于理解为什么有些网格/块的维数组合比其他的组合更好.这些练习会提供网格和块的启发式算法,这是CUDA编程人员必备的技能.二维矩阵求和的核函数如下所示: 在接下来的部分,将使用生成的sumMatrix对块和网格配置执行试验.3.3.1 用nvprof检测活跃的线程束首先,需要生成一个参考结果作为性能基准.为此,要先测试一组基础线程块的配置,尤其

《CUDA C编程权威指南》——1.2 异构计算

1.2 异构计算 最初,计算机只包含用来运行编程任务的中央处理器(CPU).近年来,高性能计算领域中的主流计算机不断添加了其他处理元素,其中最主要的就是GPU.GPU最初是被设计用来专门处理并行图形计算问题的,随着时间的推移,GPU已经成了更强大且更广义的处理器,在执行大规模并行计算中有着优越的性能和很高的效率. CPU和GPU是两个独立的处理器,它们通过单个计算节点中的PCI-Express总线相连.在这种典型的架构中,GPU指的是离散的设备从同构系统到异构系统的转变是高性能计算史上的一个里程

《CUDA C编程权威指南》——导读

###前 言 欢迎来到用CUDA C进行异构并行编程的奇妙世界! 现代的异构系统正朝一个充满无限计算可能性的未来发展.异构计算正在不断被应用到新的计算领域-从科学到数据库,再到机器学习的方方面面.编程的未来将是异构并行编程的天下! 本书将引领你通过使用CUDA平台.CUDA工具包和CUDA C语言快速上手GPU(图形处理单元)计算.本书中设置的范例与练习也将带你快速了解CUDA的专业知识,助你早日达到专业水平! 目 录 第1章 基于CUDA的异构并行计算 1.1 并行计算 1.1.1 串行编程和

《CUDA C编程权威指南》——1.2节异构计算

1.2 异构计算 最初,计算机只包含用来运行编程任务的中央处理器(CPU).近年来,高性能计算领域中的主流计算机不断添加了其他处理元素,其中最主要的就是GPU.GPU最初是被设计用来专门处理并行图形计算问题的,随着时间的推移,GPU已经成了更强大且更广义的处理器,在执行大规模并行计算中有着优越的性能和很高的效率. CPU和GPU是两个独立的处理器,它们通过单个计算节点中的PCI-Express总线相连.在这种典型的架构中,GPU指的是离散的设备从同构系统到异构系统的转变是高性能计算史上的一个里程

《CUDA C编程权威指南》——3.1节CUDA执行模型概述

3.1 CUDA执行模型概述 一般来说,执行模型会提供一个操作视图,说明如何在特定的计算架构上执行指令.CUDA执行模型揭示了GPU并行架构的抽象视图,使我们能够据此分析线程的并发.在第2章里,已经介绍了CUDA编程模型中两个主要的抽象概念:内存层次结构和线程层次结构.它们能够控制大规模并行GPU.因此,CUDA执行模型能够提供有助于在指令吞吐量和内存访问方面编写高效代码的见解. 在本章会重点介绍指令吞吐量,在第4章和第5章里会介绍更多的关于高效内存访问的内容.3.1.1 GPU架构概述 GPU

《CUDA C编程权威指南》——1.4 使用CUDA C编程难吗

1.4 使用CUDA C编程难吗 CPU编程和GPU编程的主要区别是程序员对GPU架构的熟悉程度.用并行思维进行思考并对GPU架构有了基本的了解,会使你编写规模达到成百上千个核的并行程序,如同写串行程序一样简单. 如果你想编写一个像并行程序一样高效的代码,那么你需要对CPU架构有基本的了解.例如,数据局部性在并行编程中是一个非常重要的概念.数据局部性指的是数据重用,以降低内存访问的延迟.数据局部性有两种基本类型.时间局部性是指在相对较短的时间段内数据和/或资源的重用.空间局部性是指在相对较接近的

《CUDA C编程权威指南》——1.4节使用CUDA C编程难吗

1.4 使用CUDA C编程难吗CPU编程和GPU编程的主要区别是程序员对GPU架构的熟悉程度.用并行思维进行思考并对GPU架构有了基本的了解,会使你编写规模达到成百上千个核的并行程序,如同写串行程序一样简单.如果你想编写一个像并行程序一样高效的代码,那么你需要对CPU架构有基本的了解.例如,数据局部性在并行编程中是一个非常重要的概念.数据局部性指的是数据重用,以降低内存访问的延迟.数据局部性有两种基本类型.时间局部性是指在相对较短的时间段内数据和/或资源的重用.空间局部性是指在相对较接近的存储

《CUDA C编程权威指南》——第3章 CUDA执行模型 3.1 CUDA执行模型概述

第3章 CUDA执行模型 本章内容: 通过配置文件驱动的方法优化内核 理解线程束执行的本质 增大GPU的并行性 掌握网格和线程块的启发式配置 学习多种CUDA的性能指标和事件 了解动态并行与嵌套执行 通过上一章的练习,你已经学会了如何在网格和线程块中组织线程以获得最佳的性能.尽管可以通过反复试验找到最佳的执行配置,但你可能仍然会感到疑惑,为什么选择这样的执行配置会更好.你可能想知道是否有一些选择网格和块配置的准则.本章将会回答这些问题,并从硬件方面深入介绍内核启动配置和性能分析的信息. 3.1

《CUDA C编程权威指南》——3.2节理解线程束执行的本质

3.2 理解线程束执行的本质 启动内核时,从软件的角度你看到了什么?对于你来说,在内核中似乎所有的线程都是并行地运行的.在逻辑上这是正确的,但从硬件的角度来看,不是所有线程在物理上都可以同时并行地执行.本章已经提到了把32个线程划分到一个执行单元中的概念:线程束.现在从硬件的角度来介绍线程束执行,并能够获得指导内核设计的方法.3.2.1 线程束和线程块 线程束是SM中基本的执行单元.当一个线程块的网格被启动后,网格中的线程块分布在SM中.一旦线程块被调度到一个SM上,线程块中的线程会被进一步划分