我正在尝试使用OpenMP以并行方式优化循环。
DOUBLE PRECISION, INTENT(INOUT) :: X(13541)
INTEGER , INTENT(IN) :: NELEM,NELMAX !NELMAX = 25996
INTEGER , INTENT(IN) :: IKLE(NELMAX)
DOUBLE PRECISION, INTENT(IN) :: W(NELMAX)
!$OMP PARALLEL DO PRIVATE(IELEM) REDUCTION(+:X)
DO IELEM = 1 , NELEM
X(IKLE(IELEM)) = X(IKLE(IELEM)) + W(IELEM)
ENDDO
!$OMP END PARALLEL DO
对于任何不同的I和J,可能是IKLE(I)= IKLE(J)
增加线程数,我发现运行循环需要更长的时间。我使用OMP_GET_WTIME()为作业计时。
1 T 0.21943306922912598
2 T 0.30610203742980957
3 T 0.43688893318176270
4 T 0.53783702850341797
5 T 0.61055016517639160
6 T 0.96715998649597168
7 T 0.89582014083862305
8 T 1.3073339462280273
我认为问题是由数据访问间接引起的,但我不知道如何在OpenMP中处理它
答案 0 :(得分:1)
如果可能是IKLE(I)= IKLE(J)那么你遇到的问题比不规则访问更糟糕,无法有效使用缓存数据,你有一个数据竞赛 - 您的代码中没有保护措施,防止多个线程同时写入同一位置。根据{{1}}的出现频率,您可能会很幸运,并且在实践中从未体验过这场比赛。或者你可能会不走运。无论哪种方式,正如所写,该程序是错误的'un。
FWIW我同意你的怀疑,即访问X
元素的不规则模式是你报告的时间特性的根源,它需要通过缓存进行更多的数据移动。
另外,在我写作的时候,这一行
INTEGER, INTENT(IN) :: NELEM,NELMAX = 25996
也是错误的,尝试初始化例程参数是一个语法错误。
编辑,回应OP的评论:
依赖肯定是另一个问题 - 不是我的思维方式,依赖(通过我认为我称之为数据竞争)会使程序错误,破坏,错误。糟糕的缩放只是一个不便。问题出现在OpenMP版本的程序中,因为两个或更多线程可能会在同一时间尝试更新X
的相同元素。更新不是原子的,在幕后进行的各种操作(将数据读取到寄存器,将值一起添加到两个寄存器中,将数据写入存储器位置,这类事物)可以以任何方式交错,大多数交错都不会像X
那样将值保留在程序的顺序执行中。
您是否会对您所说的数据移动提供一些提示?目前还没有写好。