英特尔多核平台编程优化大赛报告

本文详细介绍了在英特尔多核平台上进行编程优化的经验与技巧,通过实例探讨了如何利用编译器优化选项和汇编语言提升程序性能,为开发者提供实用的多核并行计算解决方案。
摘要由CSDN通过智能技术生成
 该文档从word中直接粘贴,少了图片。
 在写该文档时比较匆忙,其中有很多打错的字,还请见凉。
 如果发现该文档有相关内容有错误,还望指出。
 
 
 
 
 
 
英特尔多核平台编程优化大赛报告
 
 
 
 
 
 
 
 
 
代码优化前所需时间: 4.765
代码优化后所需时间: 0.25 秒(保留小数点后 7 位精度)
 
 

 
 
 
 
 
 
 
前言
本次优化使用的CPU是Intel Xeon 5130 主频为2.0GHz 同Intel酷睿2一样是基于Core Microarchitecture 的双核处理器。本次优化在Intel的工具帮助下主要针对Core Microarchitecture 系列处理器进行优化。但是由于未知原因,Intel VTune Analyzers并不能在该系统下正常工作。所以,所有使用Intel VTune Analyzers的测试均使用另外一个奔腾D 820的系统测试。
第一章主要介绍了程序的串行优化。其中有关于Intel编译器使用,以及Intel Math Kernel Library使用,Intel VTune Analyzers使用的介绍。在借助Intel工具的帮助下,结合Intel Core Microarchitectured的特性。设计出了针对L1 Cache进行优化的,高效率的串行代码。程序的执行时间从优化前的4.765秒达到了优化后的0.765秒。
第二章主要介绍了程序的并行化。首先讨论了2种并行算法的优缺点。然后选择了适合本程序的并行算法进行优化。并且在最后分析了并行化时的性能瓶颈。通过并行化,程序达到了0.437秒。
第三章主要介绍了程序的汇编优化。首先介绍了计算的数学理论。然后介绍了汇编代码的编写。最后进行了性能分析。通过该步优化程序在保留小数点后7位精度的前提下达到了0.312秒的好成绩。并且在Intel酷睿2 E6600 上测试达到了0.25秒。
附录A 说明了本次报告的目录结构和优化方法。
附录B 列出了进行本次竞赛所参考的文献。
 

目录
一、串行优化.... 4
1.1 代码的基本修改和优化.... 4
1.2 基于Intel编译器的优化.... 4
1.3 使用Intel VTune Analyzers进行性能分析.... 8
1.3.1 Intel VTune Analyzers概述... 8
1.3.2 基于SAMPLING方式的分析... 9
1.3.3 对于本次程序的分析... 9
1.4 优化computePot函数.... 10
1.5 使用Intel Math Kernel Library. 11
1.6 根据Cache大小优化Intel Math Kernel Library调用.... 12
1.7 优化updatePositions函数.... 13
1.8 其他优化以及性能分析.... 14
二、并行优化.... 17
2.1 并行优化概述.... 17
2.2 优化方案一.... 17
2.3 优化方案二.... 17
2.4 并行实现.... 18
2.5 性能分析.... 20
三、汇编级优化.... 23
3.1 优化目标.... 23
3.2 数学理论.... 23
3.3 汇编码实现.... 25
3.4 性能分析.... 28
3.5 总结.... 29
附录A 目录结构和编译方法.... 30
附录B 参考文献.... 30
 

 
1.1 代码的基本修改和优化
首先根据主办方的要求把代码的输出精度改为小数点后7位。

if (i%10 == 0) printf("%5d: Potential: %20.7f/n", i, pot);

在进行任何优化前代码的执行时间是4.765秒。
接着把项目转换成使用Intel C++ Compiler,代码的执行时间是4.531秒。
然后执行最基本的优化,把代码中的pow函数优化成乘法。代码如下:

distx = (r[0][j] - r[0][i])*(r[0][j] - r[0][i]);
disty = (r[1][j] - r[1][i])*(r[1][j] - r[1][i]);
distz = (r[2][j] - r[2][i])*(r[2][j] - r[2][i]);

执行时间依然为4.531秒。说明Intel编译器已经将pow函数优化掉了。
1.2 基于Intel编译器的优化
这里介绍本程序中基于Intel编译器优化技术。其中有些优化参数是可以确定的,有些优化参数需要在程序的不同阶段反复调试以确定最优方案,而有些优化技术是在后面的优化中使用的。
编译器优化级别
Intel的编译器共有如下一些主要的优化级别:
u        /O1:实现最基本的优化
u        /O2:基于代码速度实现常规优化,这个也是默认的优化级别
u        /O3:在/O2的基础上实现进一步的优化,包括Cache预读,标量转换等等,但是在某些情况下反而会减慢代码的执行速度。
u        /Ox:实现最大化的优化,包括自动内联函数的确定,全局优化,使用EBP作为通用寄存器等。
u        /fast:等同于 /O3, /Qipo, /Qprec-div-, and /QxP 。
通过测试,目前选用/O3 ,但是随着代码的更改,需要重新测试,选择合适的优化级别。
针对特定处理器进行优化
Intel的编译器一共支持如下3种针对特定处理器的优化:
u        /G:使用这个优化选项,Intel将针对特定的CPU进行优化,但是其代码依然可以在所有的CPU上执行。
u        /Qx:使用这个优化选项,Intel将针对特定的CPU进行优化,并且产生的代码无法使用在不兼容的CPU上。
u        /Qax:使用这个优化选项,Intel将针对特定的CPU进行优化,并且产生多份代码,在运行时根据CPU类型自动选择最优的代码。
由于本程序只需要运行在基于Core Microarchitecture 的处理器上,而无需考虑兼容性。所以本程序选择/Qx选项。并且针对运行时的酷睿2处理器,选择/QxT。但是在进行VTune测试时,由于测试平台为奔腾D 820,所以暂时使用/QxP的参数。
使用IPO
使用/Qipo可以启用Intel编译器的过程间优化(Interprocedural Optimizations)。通过过程间优化,编译器可以通过使用寄存器优化函数调用、内联函数展开、过程间常数传递、跨多文件优化等方式进一步优化程序。
此外,Intel编译器支持多文件的过程间优化,而由于本程序只有一个文件,所以并不需要使用。
但是IPO优化却会对本程序的调试带来极大的麻烦。所以本程序开发时不使用IPO优化,只有在最后的版本中才尝试使用IPO优化能否提高效率。
使用GPO
Intel编译器支持GPO(Profile-Guided Optimization)。GPO由一下三步组成。
第一步:使用 /Qprof-gen 编译程序,产生能记录运行细节的特殊程序。
第二步:运行第一步产生的程序,生成动态信息文件 (.dyn) 。
第三步,使用 /Qprof-use ,结合动态信息文件重新编译程序,产生更优化的程序。
通过使用 GPO , Intel 编译器可以更详细得了解程序的运行情况,从而根据实际情况产生更优化的代码。比如优化条件跳转,使得 CPU 分支预测的能力更准确,又如决定哪些函数需要内联,哪些不要内联等。
此外,基于 GPO 还有很多的工具方便用户开发程序。比如Code-Coverage Tool可以进行代码覆盖测试。
由于GPO收集的信息和特定的程序有关,而本程序一直在修改。所以本程序只在每个版本的最后部分使用GPO进行优化。
循环展开
循环展开(Loop Unrolling)通过在把循环语句中的内容展开从而使执行的代码速度更快。循环展开可以提高代码的并行程度,减少条件转移次数从而提高速度。另外,对于Pentium 4处理器,其分支预测功能可以精确得预测出16次迭代以内的循环,所以,如果能把循环展开到迭代次数在16次以内,对于特定的CPU可以提高分支预测准确度。
但是循环展开必须有一个度,并不是展开层数越多越好,展开层数多了,可能反而影响代码的执行速度。所以通常的做法是让编译器自己决定循环展开的层数。
Intel编译器对于循环展开有如下选项:
u        /Qunrolln:执行循环展开n层。
u        /Qunroll:让Intel编译器自己决定循环展开的层数。
此外Intel编译器还提供在了程序中使用编译制导语句规定某个特定循环的展开次数。如下例指示for循环展开n层。

#pragma unroll(n)
for(i=0;i<10000;i++){……}

所以本程序使用/Qunroll参数,让Intel编译器自己决定使用循环展开的层数。但是在程序的最终优化时,如果发现Intel编译器的循环展开并不是最优的,则通过在特定循环前加上编译制导语句,使用最佳的循环展开层数。
浮点计算优化
Intel编译器提供了很多基于浮点数的优化参数,有提供精度的,也有提高速度的。对于本程序,主要使用如下优化参数。
u        /fp: fast或/fp: fast=1:这两个参数的等价的,同时也是默认的参数。他告诉编译器进行快速浮点计算优化。
u        /fp: fast=2:这个参数比/fp: fast=1提供更高的优化级别,同时也可能带来更大的精度损失。
本程序使用/fp: fast=2优化,但是如果发生精度问题,可以考虑使用/fp: fast=1。
自动并行化
Intel的编译器支持自动并行化(Auto-parallelization)。通过/Qparallel可以打开编译器的自动并行化,编译器会在分析了用户的串行程序后,自动选择可以并行的部分进行并行化。自动并行化的有点是方便,不需要用户懂得专业知识,不需要更改原来的串行程序。但是缺点也是显而易见的,由于编译器并不知道用户的程序逻辑,所以无法很好得进行并行化。在对本程序试用/Qparallel后发现,效果并不好。所以本程序不只用/Qparallel进行自动并行化。
使用OpenMP 并行化
OpenMP是一种通用的并行程序设计语言,其通过在源代码中添加编译制导语句,提示编译器如何进行程序的并行化。OpenMP具有书写方便,不需要改变源代码结构等多种优点。Intel的编译器支持OpenMP。本次程序并不打算使用OpenMP进行并行化,而打算使用Windows Thread。但是由于本程序需要使用到Intel Math Kernel Library,而Intel Math Kernel Library中的代码支持OpenMP并行化。所以有必要使用一些基本的OpenMP设置函数。
需要使用OpenMP,需要在编译时加上/Qopenmp选项。并且在源代码中包含” omp.h”文件。
OpenMP提供了函数omp_set_num_threads(nthreads)设置OpenMP使用的线程数,由于其设置会影响到Intel Math Kernel Library,所以将其设置成1,禁止Intel Math Kernel Library的自动并行化。
向量化
Intel的编译器支持向量化(Vectorization)。可以把循环计算部分使用MMX,SSE,SSE2,SSE3,SSSE3等指令进行向量化,从而大大提高计算速度。这也是本程序串行化时的主要优化点。前面提到的针对处理器的/QaxT优化选项已经打开了向量化。将代码向量化还有许多需要注意的地方,具体的注意点和方法将在后面具体的代码中说明。这里先给出一些对向量化有用的编译制导语句以及选项。
u        /Qrestrict选项:当Intel编译器遇到循环中使用指针时,由于多个指针可能指向同一个地址,所以其无法保证指针指向内容的唯一性。故Intel编译器无法确定循环内数据是否存在依赖性。这是可以通过使用/Qrestrict选项与restrict关键字,指示某个指针指向内容的唯一性。从而能解决数据依赖性不确定的问题。
u        #pragma vector编译制导语句:该编译制导语句一共包含3个。#pragma vector always用于指示编译器忽略其他因素,进行向量化。#pragma vector aligned用于指示编译器进行向量化时使用对齐的数据读写方式。#pragma vector unaligne
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值