回 帖 发 新 帖 刷新版面

主题:OpenMP并行后,比原来的程序慢了100倍,这是什么原因?

使用简单的程序做OpenMP测试,发现OpenMP并行后的程序比原来程序慢了100倍以上
    这个程序串行的时候在服务器上只需要运行7.45秒,而使用OpenMP并行之后时间用了10分钟
    我的服务器是一个8核的IBM刀片服务器,编译器是intel的ifort 10.1.018,原程序intel编译器给做了矢量优化LOOP WAS VECTORIZED,进行OpenMP并行后,同时进行了OpenMP优化和矢量优化(不知道有没有冲突)。
    使用的编译选项是
    ifort -openmp -pg -o a.out FirstTest.F90 (OpenMP优化的选项)
    ifort -pg -o a.out FirstTest.F90 (未优化的选项)
      具体程序如下:
        n=500000000
    area=0

    !$OMP PARALLEL PRIVATE(x,myid,nthreads,i,j)
      !$ myid = OMP_GET_THREAD_NUM()
      !$ nthreads = OMP_GET_NUM_THREADS();
    !$OMP DO
    do j=0,n
    do i=0,n
        x=i+j+0.5
        area = 4.0/(1.0+x*x*x*x)
    end do
    end do
    !$OMP END DO
    !$OMP END PARALLEL
    这是什么原因导致的呢?因为之前给程序做OpenMP并行效果不好,所以写了个程序对服务器做测试,得到了这个很奇怪的结果

回复列表 (共18个回复)

沙发

把PRIVATE子句中的j去了呢?另:您可以看看内存是不是并行后暴涨,导致程序开始使用虚存了?

板凳

cgl_lgs兄, PRIVATE中的j不能去掉, 那样会计算出错的. 问题应该是在于area, 他默认是共享的. 线程越多造成的数据竞争约厉害. 如果仅仅是测试不妨吧area放到private.

3 楼

这个程序没啥意义了……
反正x和area都等于最后一个值
直接等价于两个赋值语句,比循环快多了

4 楼

[quote]cgl_lgs兄, PRIVATE中的j不能去掉, 那样会计算出错的. 问题应该是在于area, 他默认是共享的. 线程越多造成的数据竞争约厉害. 如果仅仅是测试不妨吧area放到private.[/quote]喔~~~确实忽略了area,不过我记得并行DO的循环变量好像是不用写的啊。

5 楼

嗯,的确是数据竞争的问题,把area加入private以后,速度就迅速提高了。还有一个问题,如果把area换成数组,每个线程写入数组的不同部分,这样可以解决数组竞争问题么?

6 楼

一般来讲, 改成数组就不存在明显的数据竞争, 只要数组不要太小.
因为一般cpu读入数据的时候是先把内存的数据读入缓冲, 而且一般会吧这个数据附近的一些读入缓冲, 如果数组比较小, 几个cpu读入到缓冲的数据有交叉部分, 硬件就需要做一个同步.(某本书上是的大意这么说的)

7 楼

[quote]这个程序没啥意义了……
反正x和area都等于最后一个值
直接等价于两个赋值语句,比循环快多了[/quote]
看代码楼主是做测试吧. 刚接触omp都喜欢测试的. 我当年也是.

8 楼

那假如OpenMP分为了8个线程,我把area定义成一个area(8)的数组,每个线程都只负责写入自己的那一部分area(myid),那读入内存的时候,也会将临近的数据读入(线程3把area(2)与area(4)也读入了),仍然会产生冲突,是这样么?

9 楼

那个严格来讲不叫数据竞争, 硬件会做一个动作, 或者这个动作很快并不感受到有多大的性能损失. 我只是说遇到那种情况有办法绕过去更好而已.
可能我上面的表达上右边偏差了.

10 楼

[quote]一般来讲, 改成数组就不存在明显的数据竞争, 只要数组不要太小.
因为一般cpu读入数据的时候是先把内存的数据读入缓冲, 而且一般会吧这个数据附近的一些读入缓冲, 如果数组比较小, 几个cpu读入到缓冲的数据有交叉部分, 硬件就需要做一个同步.(某本书上是的大意这么说的)[/quote]
刚才到网上搜了一下,这个叫CPU Cache的“乒乓效应”:

处理器交换的最小单元是 cache 行,或称 cache 块。在多核体系中,对于不共享 cache 的架构来说,两个独立的 cache 在需要读取同一 cache 行时,会共享该 cache 行,如果在其中一个 cache 中,该 cache 行被写入,而在另一个 cache 中该 cache 行被读取,那么即使读写的地址不相交,也需要在这两个 cache 之间移动数据,这就被称为 cache 伪共享,导致执行核必须在存储总线上来回传递这个 cache 行,这种现象被称为“乒乓效应”。

同样地,当两个线程写入同一个 cache 的不同部分时,也会互相竞争该 cache 行,也就是写后写的问题。
在 X86 机器上,某些处理器的一个 cache 行是64字节,具体可以参看 Intel 的参考手册。

我来回复

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