主题:OpenMP中某段程序的并行时间与串行时不一样
saupt005
[专家分:0] 发布于 2012-03-07 17:15:00
各位老师:
我在学习OpenMP时遇到了一个问题,我想将某个矩阵乘相量的do循环利用OpenMp进行并行化处理,但发现用OpenMP处理后的程序消耗的时间仅比比串行的时候快不到一倍。我将每一块循环分开来分别计算时间,发现每块单裤的循环在OpenMP并行下所消耗的时间比串行时慢了一倍。请问各位老师,这是怎么回事?
我可能说的不是太清楚,程序片段附在了下面,就是说时间差diff1、diff2、diff3、diff4在并行状态下的结果是串行状态时的将近一倍。请问这具体是什么原因造成的?
!cccccccccccccccc------------Subroutine MVP Y=A*X--------------cccccccccccccccc
subroutine MVP(A,X,Y,N)
implicit none
integer i,j,N,k
integer time(2),t1(2),t2(2),t3(2),t4(2),diff,diff1,diff2,diff3,diff4
real :: X(N),Y(N),A(N,N)
Y=0
k=N/4
call system_clock(time(1))
!$OMP parallel
!$OMP sections
!$OMP section
call system_clock(t1(1))
do i=1,k
do j=1,N
Y(i)=Y(i)+A(j,i)*X(j)
enddo
enddo
call system_clock(t1(2))
diff1=t1(2)-t1(1)
!$OMP section
call system_clock(t2(1))
do i=k+1,2*k
do j=1,N
Y(i)=Y(i)+A(j,i)*X(j)
enddo
enddo
call system_clock(t2(2))
diff2=t2(2)-t2(1)
!$OMP section
call system_clock(t3(1))
do i=2*k+1,3*k
do j=1,N
Y(i)=Y(i)+A(j,i)*X(j)
enddo
enddo
call system_clock(t3(2))
diff3=t3(2)-t3(1)
!$OMP section
call system_clock(t4(1))
do i=3*k+1,4*k
do j=1,N
Y(i)=Y(i)+A(j,i)*X(j)
enddo
enddo
call system_clock(t4(2))
diff4=t4(2)-t4(1)
!$OMP end sections
!$OMP end parallel
call system_clock(time(2))
diff=time(2)-time(1)
write(*,*) diff,diff1,diff2,diff3,diff4
return
end
回复列表 (共20个回复)
沙发
yeg001 [专家分:14390] 发布于 2012-03-07 19:30:00
1. 楼主的cpu核心数什么情况, 2核的话不到2倍提升是很合理的.(你有4个section推断可能是4个核心)
2. 不知道你用的是什么编译器, 可不可以帮我做一个测试. 首先把N减少, 例如N=10, 然后在每个section里面加
write(*, *) i
输出i的值, 再贴上来看看.
板凳
saupt005 [专家分:0] 发布于 2012-03-07 19:57:00
哇……大神关注我的问题了!是四核的CPU,内存是12个G的。
3 楼
saupt005 [专家分:0] 发布于 2012-03-07 20:08:00
编译器是IVF2011的,按照您的要求,我将write(*,*)i放到了双重循环的外层循环上,由于是4核的,我另N=12,输出结果如下
7,1,4,10,8,2,5,11,9,3,6,12
4 楼
saupt005 [专家分:0] 发布于 2012-03-07 20:12:00
若将write(*,*)放到内层循环,同时另N=4,则输出结果如下
1 3 1 2 3 4 1 2 3 4 1 2 3 4 2 4
5 楼
yeg001 [专家分:14390] 发布于 2012-03-07 23:14:00
我不是大神, 0_0! 只是看了两本书写过几个并行程序而已.
我第二步是想看看i,j会不会自动分配private属性, 因为之前论坛另一位朋友说循环角标会自动私有属性, 后来想想系统介入的话还是测不出来. 看来只能反编译才知道了, 那个我不懂. 真不好意思,浪费了你的宝贵时间.
说回这个问题, 我觉得最终还是数据竞争的问题. omp开并行区的时候最推荐是用default(none), 之后一个一个变量(并行区域内的)定义属性. 当然我也经常偷懒, 例如default(shared) 然后把所有private变量一个一个列出来. 不妨并行起始句
!$OMP parallel
这样改改看看运算效果:
!$OMP parallel default(shared) private(i,j,t1,t2,t3,t4) &
!$OMP lastprivate(diff1,diff2,diff3,diff4)
这时候N要取得比较大才能抵消线程开关的开销了(上面那个稍微浪费了一部分作时间测试的变量空间).
6 楼
saupt005 [专家分:0] 发布于 2012-03-08 00:51:00
好的,我明天试一试,不管怎么说谢谢您!
7 楼
cgl_lgs [专家分:21040] 发布于 2012-03-08 11:04:00
嫑光说谢谢啊:)也给加个分不是:)
如果计算量过小,线程创建和销毁的开销会变成主要消耗时间的:)
8 楼
saupt005 [专家分:0] 发布于 2012-03-08 11:14:00
已经给分了,呵呵
9 楼
saupt005 [专家分:0] 发布于 2012-03-08 11:16:00
还是没有发现问题……
10 楼
yeg001 [专家分:14390] 发布于 2012-03-08 11:34:00
A数组影响应该不大吧. 计算过程中A数组只是读取没有写入,不存在数据竞争. 反倒是Y有可能内存数据段太近可能造成一定的系统干预.
像我那样改了之后有没有提升的效果?
其实现在这样分割section跟 parrallel do 语句里面的静态分割是一样的. 楼主不妨也比较一下parrallel do的运行时间.
我来回复