




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、使用 SIMD 技术提高 C 程序性能作者:张银奎,软件调试和格蠹汇编作者,从事软件开发和研究十余年,对 IA-32 架构、操作系统内核、虚拟技术,尤其对软件调试有较深入的研究。微博ID :dbgger 本文为程序员订阅程序员今天和C+ 同行谈谈如何提高自己的身价。编程语言只是工具,要把工具用到最合适的地方,扬其长且避其短,打造出有价值的软件产品,那么使用这工具的人自然身价就高了。C+ 语言的优势 C+ 语言有哪些优势呢?当然有很多,不然早消亡了。但泛泛地说“有很多”没意义。到底有哪些呢?不同人可能有不同的回答。同一个人在不同时间也可能回答不同。这里我们不妨听听 C+ 之父 Bjarne St
2、roustrup先生如何说。 在前不久举办的“ 2016 C+ 及系统软件技术大会”上,Bjarne 先生做了题为 What C+ is and what it will become的主题演讲。他很深刻地阐释了到底什么是C+ ,解说了 C+ 语言的根本特征和优势。有一页讲稿的题目叫“C+ in two lines”(用两行话来描述 C+ ),可谓画龙点睛之笔。这两行是什么呢?第一行是“ Direct map to hardware”,第二行是o“Zeroverhead abstraction”。粗浅翻译一下,就是“直接映射到硬件”和“0负担抽象”。“直接映射到硬件”是说C+ 语言和硬件之间直
3、接对应, C+ 的语句可以直接对应到CPU 指令, C+的数据类型也可以直接对应到CPU 支持的数据类型。也就是说, C+ 语言的代码和数据可以很直接地翻译到CPU 支持的指令和数据,不需要做这样那样的转换。概言之,就是效率很高。单纯从效率来讲,最直接的语言当然要属汇编,但汇编语言的问题是缺乏高级抽象,代码难以组织。所以Bjarne 先生的第二行是“0负担抽象”,我想这一行又包含两层意思,第一层意思是 C+ 是有抽象的,第二层意思是支持抽象的负担为 0。在今天的软件大生产时代,即使是比较小型的软件项目,使用抽象也是必须的。今天流行的编程语言几乎无不支持抽象,不论 Java 还是 C# 、F#
4、。虽然都支持抽象,但有些语言为了抽象付出的代价很大,资源消耗多,运行速度慢,也就是额外开销高。而C+ 是 0 负担抽象, 0 额外开销。 Bjarne 先生一定也知道Java 的流行,一定也听见过关于 C+ 和 Java 孰是孰非的争论。说 C+ 是 0 额外开销略微有些夸张,但相对其他额外开销高的语言来说,相当于是 0 了。不这样说的话,说抽象负担远远低于其他语言,岂不啰嗦?一代宗师此言一出,言简意赅,料也无人敢出来说半个不是。图 1 C+ 之父 Bjarne 先生在介绍 C+ 的根本优势这两行话简单有力,一个是效率高,一个是负担小,加起来一起托出 C+ 的核心优势:锐利无比,性能一流。怀着
5、虔诚的心,我一边聆听 Bjarne 先生论述上面两行话, 一边用手机拍下了这个历史瞬间。地点是上海浦东外高桥的喜来登酒店,时间是 2016 年 10 月 28 日上午 10 点 12 分。大师的话值得反复体味,每个 C+ 程序员都应该牢记。在做设计时,我们应该用这两句话来检查自己的设计,是否大道至简,能否发挥硬件的性能。编写和检查代码时,我们更应该想起这两句话,把杂乱的逻辑理顺,把冗余的代码删掉,反复优化每行代码,把硬件的性能发挥到极致。不然的话,怎么对得起 C+ 语言,怎么对得起 Bjarne 先生?图 2 C+ 之父 Bjarne先生希望加入到 C+17 中的语言特征有人说,硬件太强大了,
6、写代码时不需要那么在意性能问题。这话真是放屁,每一位有责任心的 C+ 程序员都应该站出来痛斥这样的言论。在 Bjarne 先生介绍 C+ 的未来发展时,他谈到了最希望加入到 C+17 中的语言特征。 在这个包含十项内容的列表中,第 8 项是 SIMD 向量和并行化算法。刚好与我为准备的讲题不谋而合。 SIMD 是 Single Instruction , Multiple Data 的缩写意为单指令多数据。 我是在 Intel 工作期间听说这个技术的,好多年前了,什么场合已经记不清,但仍记得当时眼前一亮,仿佛看到一束霞光,心中赞叹这种做法太美妙了。SIMD 思想的最大特色和魅力是简单自然人法地
7、,地法天,天法道,道法自然。为什么如此说呢?因为SIMD 思想的应用实例在我们的生活中随处可见,其出现年代或许可以追溯到原始社会。我喜欢吃面包,因此以面包作坊为例。假设某作坊要做1000 个面包,每个面包要经过成型、入炉、烘烤、取出等步骤。如果每次只操作一个面包,那么大多数基本动作都要重复1000 次。但如果使用一个图3 所示的简单模具,上面有四个“包厢(面包之厢,姑且称此名)”,那么便可以一次操作四个面包。这样一来,很多操作便都是成批的了,一次成型四个,向烤箱里放时,一次四个,拿出来时,又是一次四个,于是很多操作的重复次数便从 1000 次下降到了 250 ,生产效率大大提高。图 3 SIM
8、D 思想源于生活走进生活,其实有很多类似例子,我小时候看过用黄泥做土坯的劳动场面, 一个称为坯模子的木框,上面有多个格子,每个格子对应一块土坯。如果到工厂里看一下,那么就更多了。很多工序都在使用SIMD 思想,成批地生产。劳动激发智慧,软件同行们应该好好向现实社会学习。SIMD 在计算机领域应用也有很多年了,目前比较普遍地认为著名的 ILLIAC IV 大型机是 SIMD 思想的在现代计算机中的最早实现。ILLIAC IV由美国 Illinois 大学设计,宝来公司( Burroughs)建造,项目从1965年开始,经历六年时间耗资四千万美元完成,安装在美国国家航空航天局(NASA),服役多年
9、,直到1981年才停机退役。源于ILLIAC IV使用手册的图4 既描述了ILLIAC IV的核心部件,又阐释了它的工作原理。图中的PE是Processor Element的缩写,即处理器单元,其功能和命名都与我们今天所说的Execution Unit(EU )( GPU内的基本执行单元) 非常类似。 PEM 是 Processing ElementMemory ,即处理单元记忆体,用来存放要计算的数据和计算结果。图 4 ILLIAC IV工作原理ILLIAC IV有 64 个 PE(处理器单元),可以同时做64 个计算。图中演示的便是把数组B 和数组 C 相加,结果放到数组A,一次便完成64
10、 个元素。在 ILLIAC IV手册里,还可以看到一些有趣的插图,比如图5 这幅卡通画非常形象地描绘了ILLIAC IV可以成批处理数据的能力,工作人员用大叉子把文件一大摞一大摞地投给ILLIAC IV的大嘴。 ILLIAC IV的众多计算单元排成一行在等待“喂食”IA。 CPU 上 SIMD 实现刚才介绍了 SIMD 的思想以及最早的实现, 接下来先总览 Intel 架构(简称 IA)上的 SIMD实现,然后再给出实例。很多人不知道SIMD 是什么,但知道 MMX 。MMX 是 MultiMedia eXtensions的缩写,意思是多媒体扩展。 1997 年推出的基于P5 架构的奔腾处理器
11、是包含 MMX 技术的第一款 IA CPU 。从硬件角度来看, MMX 技术包含 8 个 64 位的寄存器,称为 MM0-MM7 ,可以对 8 个单字节整数,或者 4 个字,或者 2 个双字做各种组合操作。MMX 仅支持整数类型,不支持浮点数。1999 年随同奔腾II处理器推出的 SSE (Streaming SIMD Extensions )技术弥补了 MMX 不支持浮点数的不足, 并对 MMX 做了很多改进,包括把寄存器的宽度扩展为128 位,并且不再复用x87 寄存器,并引入了 70 条新的指令。 2008 年公布的 AVX( AdvancedVector Extensions )进一步
12、把寄存器的宽度扩展为256 位,并且革新了指令格式,支持三目运算符。2011 年发布的Sandy Bridge 处理器包含了AVX 技术。图 5 描述 ILLIAC IV强大并行处理能力的卡通画图6 IA CPU 上的 SIMD 实现“天河二号”是由国防科学技术大学研制的超级计算机系统,峰值计算速度可以达到每秒5.49亿亿次、持续计算速度每秒3.39亿亿次。在 2014 年 11月 17 日公布的全球超级计算机500强榜单中, “天河二号”名列冠军。天河二号是个庞大的系统,由数以万计的计算节点组成,据说每个节点包含两颗Xeon处理器和三块Xeon Phi协处理计算卡。Xeon Phi具有强大的
13、并行计算能力,其核心技术便是名为AVX-512的SIMD技术。 AVX-512 是对 AVX 的再扩展,寄存器的宽度扩展为 512 位,数量也加大一倍,从 16 个提高到 32 个。至此我们已经介绍了 SIMD 的思想、历史以及在 X86 架构 CPU 的实现,接下来将通过一个具体的图像处理实例来介绍如何把SIMD 技术应用到C+ 项目里,探讨难易不同的多种方案、以及如何衡量所取得的性能提升。在C+ 程序中使用SIMD技术图 7 列出了使用SIMD 技术的多种方法,我们先按从上至下的顺序简要介绍每一种,然后重点介绍汇编语言方法。图 7 使用 SIMD 技术的多种方法第一种方法是使用著名的IPP
14、 库, IPP 的全称是Intel Integrated PerformancePrimitives , 是英特尔公司开发的一套跨平台软件函数库,提供了非常广泛的功能,包括各种常用的图形图像、音视频处理函数。因为其中的很多函数都已经使用SIMD 技术做了优化,所以使用这个库是使用SIMD 技术的一个快捷途径。通过链接 可以访问 IPP 的官方介绍,了解更多信息。第二种方法是使用编译器的自动向量化( Auto-vectorization )支持。比如图 8 是在Visual Studio (C+ )中通过项目属性对话框启用自动向量化的截图。图8 在 Visual Studio中启用自动向量化支持
15、经笔者分析,这样启用后编译好的程序中确实使用了一些SIMD 指令,比如图 9 右侧蓝色加亮那一行使用的便是SSE2中的 cvtsi2sd 指令,它可以将源操作数中的有符号双字整数转换成目标操作数中的双精度浮点值。图 9 观察编译器自动向量化产生的SIMD 指令如果使用GCC 编译器,那么可以使用类似这样的命令行来编译:如果希望看到编译器所采取的向量化动作,那么可以增加-ftree-vectorizer-verbose=1,于是可以类似图10 的输出信息。 图 10 使用 GCC 的自动向量化支持使用GDB 的反汇编功能,可以很容易地观察到GCC 产生的 SIMD 指令,如图 11 所示。图 1
16、1 GCC 的自动向量化功能产生的汇编指令第三种方法是使用编译器指示符( compiler directive),比如,如果使用英特尔的C/C+编译器( ICC )编译如下代码, 那么 ICC 便会对 #pragma simd指示符下面的for 循环做向量化,并给出类似下面这样的输出信息: remark: SIMD LOOP WAS VECTORIZED.第四种方法是使用Cilk技术。Cilk一词源于发音相近的Silk一词,蕴含的意思是要把并行编程做的像丝绸一样美丽。Cilk技术最早由 MIT 开发,第一版本于 1994 年发布。后来开发者创建了一个名叫 Cilk Arts 的公司,推出改进的
17、私有版本。 2009 年,英特尔收购了 Cilk Arts ,将 Cilk 技术整合进英特尔编译器中。 2012 年后, Cilk 再次成为开源项目, GCC 中便有支持(需要 4.8 或者更高版本) 。感兴趣的朋友可以从网站了解更多信息和下载有关工具及示例代码。第五种方法是使用编译器的内建函数( intrinsic ),举例来说,下面这个循环来自我们要详细讨论的图像二值化程序的C+代码。如果使用Visual C+编译器的SIMDintrinsic进行改写,那么新的代码如清单1 所示。清单1 通过 intrinsic 使用 SIMD 技术第六种方法
18、是直接使用汇编语言编写汇编函数,然后再从 C+ 代码中调用汇编函数,稍后会详细介绍。比较图 7 中的六种方法,灵活度和可控性由上至下越来越高,但是使用的难度基本也是越来越大。编写和调试供 SIMD 汇编函数有两种方法可以在C+ 项目中使用汇编代码,一种是通过_asm 这样的指示符号把汇编代码嵌入在C+函数中,另一种是把汇编代码放在单独的以.asm结尾的文件中。前一种方法因为不支持64 位,所以基本过时了。在使用后一种方法时, 首先要在项目的Solution Explorer树形控件上右击希望加入汇编文件的项目,然后选择BuildDependencies Build Customizations
19、 调出图 6 所示的对话框,然后选中 masm 行。详细讨论如何编写汇编代码超出了本文的范围,这里只能管中窥豹,介绍与上面讨论的for 循环(清单 1 上方)对应的一段汇编指令(引自现代x86 汇编语言程序设计一书) ,如清单 2 所示。清单 2对灰度图像进行二值化处理的 SSE2 汇编程序片段对于长久没有写过悉汇编代码的同行,理解清单2 中的代码可能有些困难,特别是其中的 SIMD 指令。下面将以笔者惯用的调试方法来帮助大家理解在调试器里看SIMD 。在清单 2 的第一行指令处设置断点(与在 C+ 代码中设置断点方法相同) ,触发程序调用这个汇编函数,断点命中后,单步走过这条指令。简单说,这
20、条指令就是把 edx 指向的 ITD 结构体的 Threshold 字段赋给 EAX 寄存器。打开汇编窗口,编译后的指令为:这意味着, Threshold 字段在结构体中的偏移是 0xC 。Ctrl + Alt + A 调出 Visual Studio 的命令窗口,观察内存和寄存器的值,可以印证:看来,这条指令的作用就是把二值化的阈值加载到 EAX 寄存器。接下来一条指令比较简单, movd xmm1,eax ,就是把常规寄存器 EAX 中存放的阈值传递给 SSE 的 SSE 寄存器 XMM1 。 Visual Studio 的寄存器窗口默认不显示 SIMD 的寄存器,但是可以通过快捷菜单很容
21、易解决这个问题,点击右键,调出图12 所示的快捷菜单,选中SSE 即可。图 12 配置显示 SSE 寄存器选中SSE 后,单步执行,再观察寄存器窗口, 可以看到 XMM1 的值如下: 接下来的两条指令是要把已经在 XMM1 最低字节中的阈值 ( 0x98 )散列( shuffle )到其他字节中。 两条指令中的 p 代表 packed ,即组合数,是 SIMD 中的常见术语, pshufb 是 Packed ShuffleBytes 的缩写,它根据第二个操作数指定的控制掩码对第一个操作数执行散列操作,产生一个组合数。描述起来比较拗口,单步执行这两条指令后看一下效果大家就明白了:有趣吧。接下来的这条指令(movdqa xmm2,xmmword ptrPixelScale )是把
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 新能源行业政策与投资机会分析
- 城市智能化发展可行性研究
- 有关春节安全通知范文汇编九篇
- “建筑电气工程施工质量验收规范”解读知到智慧树答案
- 汉字书法课件楷书颂
- 水粉画基础知识培训课件意义
- 土方工程施工质量控制方案
- 视觉形式法则均衡探索视觉平衡艺术与设计原理19课件
- 水稻的一生教学课件
- 学生宿舍楼生活污水处理与回用方案
- 资产减值准备管理办法模版
- GB/T 42268-2022乙烯-丙烯-二烯烃橡胶(EPDM)评价方法
- 装饰员工薪资工资表
- 医务人员之间的沟通技巧
- GB/T 20671.7-2006非金属垫片材料分类体系及试验方法第7部分:非金属垫片材料拉伸强度试验方法
- GB/T 10781.1-2006浓香型白酒
- 轴孔用YX型密封圈规格尺寸
- 肾上腺疾病外科治疗
- 第9章探放水钻机及相关设备的安全使用.
- 人教版三年级下册体育与健康教案(全册教学设计)
- 交通部农村公路建设标准指导意见
评论
0/150
提交评论