回 帖 发 新 帖 刷新版面

主题:OpenMP中某段程序的并行时间与串行时不一样

各位老师:
    我在学习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个回复)

沙发

1. 楼主的cpu核心数什么情况, 2核的话不到2倍提升是很合理的.(你有4个section推断可能是4个核心)

2. 不知道你用的是什么编译器, 可不可以帮我做一个测试. 首先把N减少, 例如N=10, 然后在每个section里面加
write(*, *) i
输出i的值, 再贴上来看看.

板凳

哇……大神关注我的问题了!是四核的CPU,内存是12个G的。

3 楼

编译器是IVF2011的,按照您的要求,我将write(*,*)i放到了双重循环的外层循环上,由于是4核的,我另N=12,输出结果如下
7,1,4,10,8,2,5,11,9,3,6,12

4 楼

若将write(*,*)放到内层循环,同时另N=4,则输出结果如下
1 3 1 2 3 4 1 2 3 4 1 2 3 4 2 4

5 楼

我不是大神, 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 楼

好的,我明天试一试,不管怎么说谢谢您!

7 楼

嫑光说谢谢啊:)也给加个分不是:)

如果计算量过小,线程创建和销毁的开销会变成主要消耗时间的:)

8 楼

已经给分了,呵呵

9 楼

还是没有发现问题……

10 楼

A数组影响应该不大吧. 计算过程中A数组只是读取没有写入,不存在数据竞争. 反倒是Y有可能内存数据段太近可能造成一定的系统干预.

像我那样改了之后有没有提升的效果?

其实现在这样分割section跟 parrallel do 语句里面的静态分割是一样的. 楼主不妨也比较一下parrallel do的运行时间.

我来回复

您尚未登录,请登录后再回复。点此登录或注册