首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >openMP没有改进运行时

openMP没有改进运行时
EN

Stack Overflow用户
提问于 2014-08-07 18:04:24
回答 1查看 397关注 0票数 0

我继承了一段Fortran代码,负责为我们拥有的8核机器并行化它。我有两个版本的代码,我试图使用openMP编译器指令来加快速度。它能在一段代码上工作,但另一段不行,我不知道为什么--它们几乎是一样的!我使用和不带openMP标记运行每段代码,第一个代码显示了速度改进,但没有第二个代码。我希望我能解释清楚.

代码示例1:(显著改进)

代码语言:javascript
复制
    !$OMP PARALLEL DO
    DO IN2=1,NN(2)
        DO IN1=1,NN(1)
            SCATT(IN1,IN2) = DATA((IN2-1)*NN(1)+IN1)/(NN(1)*NN(2))
            UADI(IN1,IN2) = SCATT(IN1,IN2)+1.0
        ENDDO
    ENDDO
    !$OMP END PARALLEL DO

代码示例2:(没有改进)

代码语言:javascript
复制
    !$OMP PARALLEL DO
    DO IN2=1,NN(2)
        DO IN1=1,NN(1)
            SCATTREL = DATA(2*((IN2-1)*NN(1)+IN1)-1))/NN(1)*NN(2))
            SCATTIMG = DATA(2*((IN2-1)*NN(1)+IN1)))/NN(1)*NN(2))
            SCATT(IN1,IN2) = DCOMPLX(SCATREL, SCATIMG)
            UADI(IN1,IN2) = SCATT(IN1,IN2)+1.0
        ENDDO
    ENDDO        
    !$OMP END PARALLEL DO

我认为这可能是内存ovehead之类的问题,并尝试了各种组合,将变量放入shared()和private()子句中,但它们要么导致分段错误,要么使其速度更慢。

我还认为,我在循环中所做的工作可能不够,无法看到改进,但由于在较小的循环中有改进,对我来说没有意义。

有人能为我所能做的就是在第二次比赛中看到真正的提速提供一些启示吗?

关于代码示例1:的提速数据:

平均运行时(对于整个代码,而不仅仅是这段代码)

代码语言:javascript
复制
Without openMP tags: 2m 21.321s 

With openMP tags: 2m 20.640s

平均运行时(仅此片段的配置文件)

代码语言:javascript
复制
Without openMP tags: 6.3s

With openMP tags: 4.75s

关于代码示例2:的提速数据:

平均运行时(对于整个代码,而不仅仅是这段代码)

代码语言:javascript
复制
Without openMP tags: 4m 46.659s

With openMP tags: 4m 49.200s

平均运行时(仅此片段的配置文件)

代码语言:javascript
复制
Without openMP tags: 15.14s

With openMP tags: 46.63s
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-08-07 20:47:59

代码并行运行比串行运行慢的观察告诉我,罪魁祸首很可能是虚假共享

SCATT数组是shared,每个线程都为访问其中的一部分,用于读取和写入。但是,在您的代码中不存在竞争条件,但是写入同一个数组的线程(尽管不同的切片)会使事情变得更慢。

原因是每个线程在缓存中加载数组SCATT的一部分,每当另一个线程在SCATT的这一部分中写入时,这会使以前存储在缓存中的数据无效。尽管由于没有竞争条件(另一个线程更新了SCATT的一个不同的部分),输入数据没有被更改,但处理器得到了缓存无效的信号,从而重新加载了数据(有关详细信息,请参阅上面的链接)。这会导致较高的数据传输开销。

解决方案是使每个片段都私有于给定的线程。在您的例子中,它甚至更简单,因为您根本不需要读取对SCATT的访问。只需替换

代码语言:javascript
复制
SCATT(IN1,IN2) = DCOMPLX(SCATREL, SCATIMG)
UADI(IN1,IN2) = SCATT(IN1,IN2)+1.0

使用

代码语言:javascript
复制
SCATT0 = DCOMPLX(SCATREL, SCATIMG)
UADI(IN1,IN2) = SCATT0+1.0
SCATT(IN1,IN2) = SCATT0

其中SCATT0是一个private变量。

为什么在第一个片段中没有发生这种情况?当然,我怀疑编译器可能已经优化了这个问题。在计算DATA((IN2-1)*NN(1)+IN1)/(NN(1)*NN(2))时,很可能会将其存储在寄存器中,并使用此值而不是SCATT(IN1,IN2)UADI(IN1,IN2) = SCATT(IN1,IN2)+1.0中。

此外,如果您想加快代码的速度,您应该提高循环的效率。并行化的第一条规则是不要这么做!首先优化了串行代码。因此,将代码片段1替换为(您甚至可以在最后一行的workshare中通过)

代码语言:javascript
复制
DATA/(NN(1)*NN(2))
!$OMP PARALLEL DO private(temp)
DO IN2=1,NN(2)
    temp = (IN2-1)*NN(1)
    SCATT(:,IN2) = DATA(temp+1:temp+NN(1))
ENDDO
!$OMP END PARALLEL DO
UADI = SCATT+1.0

您也可以使用代码片段2进行类似的操作。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25189178

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档