OpenMP并行实验报告.docx

上传人:b****7 文档编号:11032782 上传时间:2023-02-24 格式:DOCX 页数:19 大小:20.58KB
下载 相关 举报
OpenMP并行实验报告.docx_第1页
第1页 / 共19页
OpenMP并行实验报告.docx_第2页
第2页 / 共19页
OpenMP并行实验报告.docx_第3页
第3页 / 共19页
OpenMP并行实验报告.docx_第4页
第4页 / 共19页
OpenMP并行实验报告.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

OpenMP并行实验报告.docx

《OpenMP并行实验报告.docx》由会员分享,可在线阅读,更多相关《OpenMP并行实验报告.docx(19页珍藏版)》请在冰豆网上搜索。

OpenMP并行实验报告.docx

OpenMP并行实验报告

并行实验报告

一、积分计算圆周率

1.1积分计算圆周率的向量优化

1.1.1串行版本的设计

任务:

理解积分求圆周率的方法,将其用C代码实现。

、、亠"

注意:

理论上,dx越小,求得的圆周率越准确;在计算机中由于表

示的数据是有精度范围的,如果dx太小,积分次数过多,误差积累

导致结果不准确。

以下为串行代码:

#include

#include#defineN10000000doubleget_pi(intdt){

doublepi=0.0;

doubledelta=1.0/dt;inti;

for(i=0;i

}

returnpi*4;

}intmain()

{

intdx;

doublepai;

doublestart,finish;

dx=N;

start二clock();

pai二get_pi(dx);

finish=clock();

printf("%.8lf\n",pai);

printf("%.8lfS\n",(double)(finish-start)/CLOCKS_PER_SEC);return0;

}

时间运行如下:

adnin19adnlni-virtual-maGhIne:

-/Des-ktop$gf匚-03textlt匚adninl@adniinl-vtrtual-macliifte:

-/Desktops-/a.out

3.141592750*G267400OSadninl@adninl-vtctual-riacliifte:

-/Desktops•/a*out

3.14159275

6.624465005adninl@adninl-vtrtual-nachir»e:

-/Desktops•/a*out

3.14159275o*024e28eesadntnlgadninl・¥1「七即31-口日匸111“亡;|

第一次:

time=0.02674000S

第二次:

time=0.02446500S

第三次:

time=0.02402800S

三次平均为:

0.02508S

1.1.2SSE向量优化版本设计

任务:

此部分需要给出单精度和双精度两个优化版本

(1)测试均在划分度为10的7次方下完成。

以下是SSE双精度的代码:

#include

#include

#include

#defineN10000000doubleget_pi(intdt){

doublepi=0.0;

doubledelta=1.0/dt;inti;

for(i=0;i

}

returnpi*4;

}doubleget_pi_sse(size_tdt){

doublepi=0.0;

doubledelta=1.0/dt;

__m128dxmm0,xmm1,xmm2,xmm3,xmm4;xmm0=_mm_set1_pd(1.0);

xmm1=_mm_set1_pd(delta);

xmm2=_mm_set_pd(delta,0.0);xmm4=_mm_setzero_pd();

for(longinti=0;i<=dt-2;i+=2){

xmm3=_mm_set1_pd((double)i*delta);

xmm3=_mm_add_pd(xmm3,xmm2);

xmm3=_mm_mul_pd(xmm3,xmm3);

xmm3=_mm_add_pd(xmm0,xmm3);

xmm3=_mm_div_pd(xmm1,xmm3);

xmm4=_mm_add_pd(xmm4,xmm3);

}--

doubletmp[2]__attribute__((aligned(16)));_mm_store_pd(tmp,xmm4);

pi+=tmp[0]+tmp[1]/*+tmp[2]+tmp[3]*/;

returnpi*4.0;}intmain()

{

intdx;

doublepai;

doublestart,finish;dx=N;

start=clock();pai=get_pi_sse(dx);

finish=clock();

printf("%.8lf\n",pai);

printf("%.8lfS\n",(double)((finish-start)/CLOCKS_PER_SEC));return0;

}

testl-SSE*c

时间运行如下:

adminl^admlnl-vlrtual-machine1«/Desktop$gcc-03adminl@adninl-virtual-machineDesktop$*/a-out

3,14159275

O.O08375O0Sadmtnl@adntnl-vtrtua'L-Fiachtnei~/Desktop$,/a.out3•14159275

0.0074110GS

adntAl@admini-virtuat-machine:

^/Desktop$»/a*out

3.14159275

O.OO82O80OS

adHtnlQadRtnl-vtrtual-Rdchine:

^/Desktops.M-out

3*14159275

O.fl67720OOS

第一次:

time=0.00837500S

第二次:

time=0.00741100S

第三次:

time=0.00772000S

三次平均为:

0.00783S

以下是SSE单精度的代码:

#include

#include

#include

#defineN10000000

floatget_pi_sse(size_tdt){

floatpi=0.0;

floatdelta=1.0/dt;

__m128xmm0,xmm1,xmm2,xmm3,xmm4;xmm0=_mm_set1_ps(1.0);

xmm1=_mm_set1_ps(delta);

xmm2=_mm_set_ps(delta*3,delta*2,delta,0.0);xmm4=_mm_setzero_ps();

for(longinti=0;i<=dt-4;i+=4){

xmm3=_mm_set1_ps((float)i*delta);

xmm3=_mm_add_ps(xmm3,xmm2);

xmm3=_mm_mul_ps(xmm3,xmm3);

xmm3=_mm_add_ps(xmm0,xmm3);

xmm3=_mm_div_ps(xmm1,xmm3);

xmm4=_mm_add_ps(xmm4,xmm3);

}--

floattmp[4]__attribute__((aligned(16)));

_mm_store_ps(tmp,xmm4);

pi+=tmp[0]+tmp[1]+tmp[2]+tmp[3];

returnpi*4.0;

}

intmain()

{

intdx;

floatpai;

doublestart,finish;

dx=N;

start=clock();

pai=get_pi_sse(dx);

finish=clock();

printf("%.8f\n",pai);

printf("%.8lfS\n",(double)((finish-start)/CLOCKS_PER_SEC));return0;

}

时间运行如下:

admtnl@adntnl-vtrtuaL-piachlne:

~/Desktopsgcc-03testl-floa七-SSE*Cadminl@adninl-vtrtual-i,iachine:

~/Desktop$./a*out

3.14564051

0*OO4O6100S

adnxnl@admini-virtual-machine:

-/Desktops-/a.out

B.14584651

O.OO426400S

admtnl®admtnl-vtrtiial-Fiachtne:

~/Deskt叩£*/a.out

3.145G4051

第一次:

time=0.00406100S

第二次:

time=0.00426400S

第三次:

time=0.00437600S

三次平均为:

0.00423S

1.1.3AVX向量优化版本设计

任务:

此部分需要给出单精度和双精度两个优化版本

注意:

(1)测试均在划分度为10的7次方下完成。

(2)在编译时需要加-mavx编译选项,才能启用AVX指令集,否则默认SSE指令集

(3)理论上,向量版本对比SSE版本和串行版本有明显加速,单精度版本速度明显优于双精度,速度接近双精度的两倍。

以下是AVX双精度的代码:

#include

#include

#include

#defineN10000000

/*doubleget_pi(intdt){

doublepi=0.0;

doubledelta=1.0/dt;

inti;

for(i=0;i

doublex=(double)i/dt;

pi+=delta/(1.0+x*x);

}

returnpi*4;

}*/

doubleget_pi_avx(size_tdt){

doublepi=0.0;

doubledelta=1.0/dt;

__m256dymm0,ymm1,ymm2,ymm3,ymm4;ymm0=_mm256_set1_pd(1.0);

ymm1=_mm256_set1_pd(delta);

ymm2=_mm256_set_pd(delta*3,delta*2,delta,0.0);

ymm4=_mm256_setzero_pd();

for(longinti=0;i<=dt-4;i+=4){

ymm3=_mm256_set1_pd((double)i*delta);

ymm3=_mm256_add_pd(ymm3,ymm2);

ymm3=_mm256_mul_pd(ymm3,ymm3);

ymm3=_mm256_add_pd(ymm0,ymm3);

ymm3=_mm256_div_pd(ymm1,ymm3);

ymm4=_mm256_add_pd(ymm4,ymm3);

}

doubletmp[4]__attribute__((aligned(32)));

_mm256_store_pd(tmp,ymm4);

pi+=tmp[0]+tmp[1]+tmp[2]+tmp[3];

returnpi*4.0;

}intmain()

{

intdx;

doublepai;

doublestart,finish;

dx=N;

start=clock();

pai=get_pi_avx(dx);

finish=clock();

printf("%.8lf\n",pai);

printf("%.8lfS\n",(double)((finish-start)/CLOCKS_PER_SEC));return0;

}

时间运行如下:

ad^tnl(aadntftl-virtual-Machtfte:

-/Oesktop$gcc-mavx*03testl-AVX.cadpitnlOadpitnl-vlrtuaL-machlne:

Desktop$*/a.out

3.14159275

adninlQadmini-virtual-machine:

-/Desktops/a.out

3.14159275

0.0065980GS

admtnl^admlnl-virtual-ma匚hlne:

«/Desktop$,/a.out

3.14159275

O.0O67O6QOS

第一次:

time=0.00720200S

第二次:

time=0.00659800S

第三次:

time=0.00670600S

三次平均为:

0.00683S

以下是AVX单精度的代码:

时间运行如下:

adnlnKaadfltnL-vtrtuaL'Wachtne:

/Desktopsgcc*navx-03testl-float-AVX^cadm

/Desktops./a.out

3.1^1173317

0.002342035

adriLnl(3ad»i1.nL-v1.rtkjaL-machtne:

-/0esktop$*/a*out

3.14173317

□dntni^sdHini-virtual-nachine:

-/Dtsktop$,/d*out

3.14173317

U.OO230O&OS

第一次:

time=0.00234200S

第二次:

time=0.00234200S

第三次:

time=0.00230000S

三次平均为:

0.002328S

由以上实验统计得出结论:

AVX-float=0.002328S

AVX-double=0.00683S

SSE-float=0.00423S

SSE-double二0.00783S

基本符合规律:

(以下为速度比较)

AVX-float>AVX-double〜SSE-float>SSE-double>serial

1.2积分计算圆周率的OpenMP优化

1.2.1OpenMP并行化

任务:

在串行代码的基础上进行OpenMP并行优化

注意:

测试在划分度为10的9次方下完成。

参考代码:

#include

#include

#defineN1000000000

doubleget_pi(intdt){

doublepi=0.0;

doubledelta=1.0/dt;

inti;

#pragmaompparallelforreduction(+:

pi)for(i=0;i

doublex=(double)i/dt;pi+=delta/(1.0+x*x);

}

returnpi*4;

}

intmain()

{

intdx;

doublepai;

//doublestart,finish;

dx=N;

doublestart=omp_get_wtime();pai=get_pi(dx);

doublefinish=omp_get_wtime();

printf("%.8lf\n",pai);

printf("%lf\n",finish-start);

return0;

}

运行结果如下图:

**************************Machtne:

-/Desktopsgcc-fopenmp心testi^cadntnl^adntril-virtual-machtne:

-/Desktops./白*out

3.1415眈©5

1.Z54893

adninl@odrtiril'Virtual-Hachtne:

-/Desktops*»out

3.14159265

1.26064SadninHaadnifil-virtual-nachine:

-/Desktop$.fa*out

3.14159265

1.244998

串行结果如下:

ddntnl@adntnl-vtrtuaL-Fiachtne:

-/Desktopsgcc-03textileadmtnl@a-dmtnl-vlrtuaL-machlne:

-/Desktops■丿日•out

3.14159265

2.3297720OS

ddHtnl@admtnl-vtrtud'l-maGhtnQ:

-/Desktops・/a*out

3.14159265

2.334373005adninl@adntnl-vtrtual-nachilne:

-^Desktops./a.out

3.14159265

2.33470196S

提速十分明显

122OpenMP并行化+SIMD向量化

任务:

实现OpenMP线程级和SIMD两级并行

自动向量化代码如下:

#include

#include

#defineN1000000000

doubleget_pi(intdt){

doublepi=0.0;

doubledelta=1.0/dt;

inti;

#pragmaompparallelforsimdreduction(+:

pi)for(i=0;i

doublex=(double)i/dt;pi+=delta/(1.0+x*x);

}

returnpi*4;

}

intmain()

{

intdx;

doublepai;

dx=N;

doublestart=omp_get_wtime();

pai=get_pi(dx);

doublefinish=omp_get_wtime();

printf("%.8lf\n",pai);

printf("%lf\n",finish-start);return0;

}

注意:

自动向量化语句为#pragmaompparallelforsimdfor...

使用编译语句为:

gcc-fopenmp-mavx-O3...

运行结果如下图:

adn^nl@admtnl-vlrtual-nachlne;"/Desktop?

gcc-fopenfip-navx-03test2-si-nd*cadHtnlg^dmtnl-vtrtjaL-ri^chtne:

Desktop^./a*out

3.14159265

6,663686

adri'inltJadri'Lnl-virtual-nachine;-/Desktopg«/a.out

3.14159265

0.633444adninH0admi.nl-vtrtjal-fiachi.ne:

-/iDesktop5^/ri.out

3.14159205

0+640612

从结果看出:

有很明显的提速

手动向量化代码如下:

#include

#include

#include

#defineN1000000000doubleget_pi(intdt){

doublepi=0.0;

doubledelta=1.0/dt;

doubletmp[4]__attribute__((aligned(32)));

__m256dymm0,ymm1,ymm2,ymm3,ymm4;ymm0=_mm256_set1_pd(1.0);

ymm仁_mm256_set1_pd(delta);ymm2=_mm256_set_pd(delta*3,delta*2,delta,0.0);

ymm4=_mm256_setzero_pd();

inti;

#pragmaompparallelshared(ymm0,ymm1,ymm2)private(i,ymm3,tmp){

#pragmaompforreduction(+:

pi)

for(longinti=0;i<=dt-4;i+=4){

ymm3=_mm256_set1_pd((double)i*delta);

ymm3=_mm256_add_pd(ymm3,ymm2);

ymm3=_mm256_mul_pd(ymm3,ymm3);

ymm3=_mm256_add_pd(ymm0,ymm3);

ymm3=_mm256_div_pd(ymm1,ymm3);〃ymm4=_mm256_add_pd(ymm4,ymm3);

_mm256_store_pd(tmp,ymm3);

pi+=tmp[0]+tmp[1]+tmp[2]+tmp[3];

}

}

//doubletmp[4]__attribute__((aligned(32)));

〃_mm256_store_pd(tmp,ymm4);

〃pi+=tmp[0]+tmp[1]+tmp[2]+tmp[3];

returnpi*4.0;

}

intmain()

{

intdx;

doublepai;

dx=N;

doublestart=omp_get_wtime();

pai=get_pi(dx);

doublefinish=omp_get_wtime();

printf("%.8lf\n",pai);

printf("%lf\n",finish-start);

return0;

}

通过对向量化代码的分析,各个向量间的运算是没有任何依赖关系的,可以直接分线程并行运算,但需要注意最后要把各个线程的运算结果累加。

而线程的定义openmp的函数reduction是没有办法直接使用(+:

)进行累加,需要手动完成。

引入数组tmp用于将ymm3向量分割存放,并累加到pi变量,使用

openmp函数reduction(+:

pi)对pi变量进行累加(详见代码

解决的问题:

并行块中如何私有化一个数组:

直接将数组名称写入private()函

数中。

曾经尝试将数组各项都放入private。

函数中,错误如下:

adntnl®adntnl-vtrtual-machlne:

-/Desktop$gcc-fopennp-navx*05test2handxtestz-hand.c:

Infunctionfget_ptJ:

test2-hand.c:

16:

63:

_rexpected*)'before'[‘token

ffpragnacnpparallelshared(ynnerynnl#y)privateCt^ynRS,tnpQI,tnipri](tnp[2]>W[3])

多次尝试后,正确做法如下:

以tmp[4]数组举例:

私有化描述如下:

private(tmp);

运行结果如下图:

adntnl^ad-

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 城乡园林规划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1