英语原文共 13 页,剩余内容已隐藏,支付完成后下载完整资料
可移植的C
作者:Keasler, Jeff. Dr. Dobb#39;s Journal; San Mateoensp;Vol.ensp;33,ensp;Iss.ensp;6,ensp; (2008年6月): 40,42-44,46-47.
摘要:
为了说明数组组织如何影响性能,我使用了三个计算面积和体积的示例(源代码清单可以在网上找到):三角形区域,8个软/三角形。2D四边形面积,8个滑块/四边形。三维砖体积,60块/砖(六面体)。这种微妙之处有助于强调算法和数据布局的相互作用如何影响编译器优化的效率,以及内存延迟。一些图中的峰值显示了某些配置的明显性能问题,但是分析器可能无法捕捉到这种效果,因为给定数据结构的使用可能在整个代码中均匀地分布。
批注:充分利用新架构
程序员有两种组织数据数组的基本方法。随着代码从机器到机器和编译器到编译器,每个选择的性能都有很大的不同。
通过隐藏类API背后的数组细节,可以很容易地在中其转换数组和结构相似的实现。并展示了如何将坐标阵列作为性能便携点类实现。Point类实现有两个重要的特性:
*方法内联。方法返回对底层数据的直接引用。总之,这两个特性让几乎所有的编译器都能有效地优化大多数(如果不是全部)的类开销,特别是当在die编译器优化标志中启用了程序间分析时。如果您使用具有上述形式的类,您可以快速地在数组布局之间切换,就像您的端口代码一样。最简单的方法是创建一个带有系统特定布局选择的配置头文件,并在每个阵列类头文件的顶部包含那个配置文件。如果您不像我在这里描述的那样隐藏数组实现,那么当从一种数组布局切换到另一种形式时,您可能会完全重写您的软件。为了说明数组组织如何影响性能,我使用了三个计算面积和体积的示例(源代码清单可以在网上找到):三角形区域,8个小块/三角形;2D四边形面积,8个滑块/四边形;三维砖体积,60块/砖。
我将这些计算应用到成千上万的网格元素中。我在基准测试中包含了足够多的元素,内存占用超过20兆字节,但是我以缓存最优的方式组织元素,因此缓存重用就会发生。
我的基准有两个相互作用的数组类。我使用一个点类来存储坐标,以及一个形状特定的类来存储定义形状的点索引。
我选择的例子有微妙不同的内存布局和内存访问模式,这种微妙之处有助于强调算法和数据布局的相互作用如何影响编译器优化的效率,以及内存延迟。
结果:
图2、3和4分别显示了清单2、3和4的性能。对于图中的每一个小节,都进行了20次运行,并且使用了最少的时间。由于每次运行都是在没有其他用户的“专用”处理器上运行的,所以在20次运行中几乎没有什么差异。表1提供了每个基准的处理器/编译器的详细信息。
在给定的条形图中,所有的结果都与该颜色的最小时间一致。这让您可以测量给定环境下给定数据布局的相对性能。比较不同的条形颜色来确定最快的编译器是行不通的。在解释结果时,你应该选择两个条形颜色,然后比较这些颜色如何在所有四个内存布局中进行交互。例如,在查看图3时,您可以将Core2/pathscale3.0的结果与power5/xlc7.0进行比较,结果会发现,对于一个配置来说,最快的内存布局是另一个配置最慢的。这里的性能差异高达13%。通过使用性能可移植的阵列类,您可以在这两个环境中获得最佳性能。
图4也很有趣。从图上看,最有效的数据安排是将Point类作为单独的数组实现,而砖块连接类则是一组结构体。与此相比,点和砖块都是作为结构体的数组实现的。在Itanium2上使用icpc v10.0编译器的结构类点类的性能下降大约是36%。这是令人惊讶的,因为许多科学应用程序几乎只使用结构类的点类。
此外,这些图表还显示,用相同的编译器编译给定的基准测试,但是在两个不同的架构上给出不同的结果。查看图2,将Core2/PGI6.2-3与opteron/pgi 6.2-3进行比较,结果显示,在使用完全相同的编译器、数据布局和编译器选项时,性能差异高达26%。只有在两台不同的机器上编译时,这个事实才会变得明显。这个例子揭示了灵活的数据结构的一个关键优势。切换数据结构的能力使您能够捕获与数据布局相关的性能问题,而这些问题可能不是通过分析工具来实现的。一些图中的峰值显示了某些配置的明显性能问题,但是分析器可能无法捕捉到这种效果,因为给定数据结构的使用可能在整个代码中均匀地分布。
STL和裸指针
我最初使用STL向量来存储数据的基准测试,但是我很好奇STL的性能与使用裸指针相比如何。清单5(可用在线)使用限制关键字,用指针代替STL向量。
在图5、6和7中,我分别画出了指针时间与三角形、四边形和砖基准的STL时间的比值(小于1的值意味着裸指针的速度更快)。四边形的基准测试结果表明,在使用受限指针而不是STL时,Opteron上的pathscale 3.0编译器的平均速度要快32%。另一方面,在使用STL时,g 编译器在每个基准配置上运行得稍微快一些。由于在使用指针时发生了过于激进的优化,所以我不得不从这个比较中忽略XlC编译器。
类分区
在将阵列的实现隐藏在类API背后之前,您可能需要考虑额外的API层如何影响代码。现在,我已经给出了描述该技术及其性能的确凿事实,我将介绍一些用于组织数组类的潜在指导方针。首先,几乎可以肯定的是,在项目开始时,任何选择的数据分区都会在项目结束时发生变化。记住这一点,您需要对数据进行分区,这样如果您需要重构代码,就会有尽可能少的痛苦。数据组织有两个极端:把你所有的数组都分成一个大的类。将你的数组分成大量的小类,每个类只包含几个数组。第一种选择具有更好的可读性和可重构性。如果您的所有数据成员都使用相同的短助记,那么它就像是为您的数组数据拥有一个名称空间。它更容易重构,因为你可以在类中移动数据,而类API不会改变,所以你的代码不会改变。
第一种选择有一个缺点,即很难实例化对象的多个副本,而不会导致内存和类构建时间的巨大固定开销。例如,如果你在一个使用STL向量实现的类中有800个数组,那么你将会支付实例化所有向量的惩罚,即使你只是为它所包含的一些向量克隆这个类。构建/初始化也可能是一个问题,特别是对于数组的子集。
第二种选择具有极端灵活性的优势。你可以只对几个数组进行分组,这些数组通常在一个类中一起使用,例子是坐标向量或速度向量。当您想要在整个运行过程中构造/销毁大量临时对象时,这是最优的。小的类也更容易调整性能的可移植性。
缺点是可以降低可读性,因为几乎每个变量都有一个不同的名称空间前缀。写这样的代码,或者用方程式来读,并不总是那么有趣。在使用之前将数据提取到本地临时表中可以减轻可读性问题,但这可能会导致代码膨胀,更不用提由于剪切和粘贴代码和输入错误导致的错误。许多小类的另一个缺点是,如果您想要重构代码,比如将一个数组从一个类移动到另一个类,那么这种变化通常需要在整个代码中进行更改。
现在我已经介绍了这两个极端的优点/缺点,我看了第三种选择,即对具有类似“拓扑”特征的数据进行分组。有迹象表明,阵列可能在拓扑学上类似,它们的长度可能是相同的。例如,当在网格上处理物理时,速度分量通常是在坐标中定义的,所以也许坐标和速度应该被封装在同一个类中。
相比之下,粒子数据可能包含坐标,但你不会想要用网格坐标来分组粒子坐标,因为粒子有一个完全不同的函数。粒子可以独立于网格坐标移动,它们很可能会被创建和销毁。
从拓扑学上分组的优势在于,它们通常可以嵌套在层次结构中。例如,一个数组类可以包含数组数据常见的所有节点的网格,而另一个类可以包含额外的数组数据与索引集的一个子集可以用来映射数组中相应指标子集的指数较大的网格来实现继承。
拓扑分组是一个很好的指导方针,但它只是一个指导方针。可能会有一些对性能敏感的数组,它们应该被分割成单独的类,以便更容易地进行缓存调优。
一旦您决定了如何对类进行分组,那么对于具有类似结构的底层实现的类来说,还有另外一个重要的要点,确保那些可能被一起使用的变量位于struct的相邻位置。这大大增加了缓存的命中率,从而提高了您的性能。抵制按字母顺序排列结构成员的冲动,因为这会造成巨大的性能损失。
结论
在不久的将来,性能可移植性可能成为编程的一个必要部分。如果使用跨步向量(也称为数组式布局),一些编译器就只会为x86处理器架构创建良好的SSE代码。与此同时,老式的超纯量机器通常在尽可能多地使用结构型布局时表现最好。如果没有切换内存布局的灵活性,性能几乎肯定会受到代码的影响,而当我们进入未来时,这种情况更有可能发生。
我在这里描述的技术被用于一个大型的多物理项目中,它包含了成千上万行代码。该技术最初被用作重构工具,而不是性能可移植性工具。在某一时刻,该项目能够快速地重构物理代码的流体动力学部分,以达到42%-100%的速度,这取决于所解决的问题和使用的机器。流体力学可以成为许多物理应用程序运行时的主要部分,因此,仅仅通过改变数据结构来将性能提高一倍是令人印象深刻的。性能提升的一部分可能来自于编译器,它识别了可以应用的额外优化(相同的编译器标志),其余的来自不同的缓存延迟特性。
感谢Brian McCandless在侧边栏材料的演示中质疑我,并鼓励我写这篇文章。他的团队在他们的软件中使用了这种技术的变体。
新一代性能可移植性:
为了充分利用多核、NUMA和异构技术,许多代码可能需要重写,特别是在高性能计算(HPC)领域中。为了减轻这种转变对新架构的影响,我正在研究将源-源翻译作为一种可能的救赎。我使用了一个名为ROSE(www.roseCompiler.org)的复杂工具来编写一个小型的C语言扩展,它以一种对用户透明的方式实现本文中的技术。我在文章中提到的所有缺点都消失了,并且出现了新的特性,特别是在多维数组方面。用户创建一个描述结构/数组分组的单一模式文件!在代码中使用的数组名称。然后,编译器可以在编译时使用模式来生成结构或数组。分组可以是分层的,因此可以很容易地捕捉到H组之间的微妙关系。
我计划研究生成快速思维、英特尔的线程构建块或其他后端代码,以补充性能可移植语言扩展。我的希望是,源翻译和类似于矢量的语言扩展可能会让下一代架构的力量被利用最少的精力来编写代码重写。
RapidMind:c 满足多核
作者:Stefanus Du Toit; McCool, Michael. Dr. Dobb#39;s Journal; San Mateoensp;Vol.ensp;32,ensp;Iss.ensp;7,ensp; (Jul 2007): 57-58,60-62.
摘要:
试图利用诸如增加时钟频率和更深层的管道等传统手段来扩大处理器速度,正面临着物理上的限制,从而终结了开发者和用户已经习惯的“免费午餐”。由索尼、东芝和IBM等传统建筑设计、图形处理单元(cpu)和Cell宽带引擎(CeU BE)处理器(www.ddj.com/dept/64bit/197801624)的限制较少,已经展示了巨大的性能改进,采用了大量并行处理处理器架构
全文共9920字,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[14245],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。