OpenMP并行实验报告.docx

上传人:b****8 文档编号:29975290 上传时间:2023-08-03 格式:DOCX 页数:19 大小:350.50KB
下载 相关 举报
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

#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;

}

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;

}

时间运行如下:

第一次:

time=0.02674000S

第二次:

time=0.02446500S

第三次:

time=0.02402800S

三次平均为:

0.02508S

1.1.2SSE向量优化版本设计

任务:

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

注意:

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

以下是SSE双精度的代码:

#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_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;

}

时间运行如下:

第一次:

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;

}

时间运行如下:

第一次:

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;

}

时间运行如下:

第一次:

time=0.00720200S

第二次:

time=0.00659800S

第三次:

time=0.00670600S

三次平均为:

0.00683S

以下是AVX单精度的代码:

时间运行如下:

第一次:

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;

}

运行结果如下图:

 

串行结果如下:

提速十分明显。

1.2.2OpenMP并行化+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...

运行结果如下图:

从结果看出:

有很明显的提速。

手动向量化代码如下:

#include

#include

#include

#defineN1000000000

doubleget_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);

ymm1=_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()函数中,错误如下:

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

以tmp[4]数组举例:

私有化描述如下:

private(tmp);

运行结果如下图:

手动化结果明显优于自动化结果。

手动化的修改更符合编写的程序本身。

二、矩阵-矩阵相乘的openmp优化

2.1编写一个“矩阵-向量”或“矩阵-矩阵”相乘的OpenMP并行程序,或其他矩阵运算相关程序。

矩阵的验证均在1024*1024规模下完成

矩阵-矩阵相乘的openmp代码和串行代码如下:

#include

#include

#include

#defineN1024

#definen4

inta[N][N];

intb[N][N];

intc[N][N];

intd[N][N];

intmain()

{

inti,j,k;

for(i=0;i

for(j=0;j

a[i][j]=1;

b[i][j]=1;

c[i][j]=0;

d[i][j]=0;

}

}

doublestart1=clock();

for(i=0;i

for(j=0;j

for(k=0;k

d[i][j]+=a[i][k]*b[k][j];

}

}

doublefinish1=clock();

omp_set_num_threads(n);

//printf("thread_num:

%d\n",omp_get_thread_num());

doublestart=omp_get_wtime();

#pragmaompparallelshared(a,b,c)private(i,j,k)

{

#pragmaompforschedule(dynamic)

for(i=0;i

for(j=0;j

for(k=0;k

c[i][j]+=a[i][k]*b[k][j];

}

}

}

doublefinish=omp_get_wtime();

//打印c

/*for(i=0;i

for(j=0;j

printf("%d",c[i][j]);

}

printf("\n");

}

printf("\n");

//打印d

for(i=0;i

for(j=0;j

printf("%d",c[i][j]);

}

printf("\n");

}*/

printf("PARALLELTIME=%lfs\n",finish-start);

printf("UNPARALLELTIME=%.8lfS\n",(double)(finish1-start1)/CLOCKS_PER_SEC);

return0;

}

运行结果如下图:

由结果可以看出OPENMP优化后的速度有明显的提升。

提升速度接近一倍。

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

当前位置:首页 > 工程科技 > 交通运输

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

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