OpenMP 不适用于间接访问数组

OpenMP not work with an array access indirect

我正在尝试使用 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 中处理它

如果 有可能 IKLE(I)=IKLE(J) 那么你有一个比不规则访问更糟糕的问题破坏了有效使用缓存数据的任何希望,你有一个数据竞争 -- 您的代码没有针对多个线程写入同一位置的保护措施'simultaneously'。根据 IKLE(I)=IKLE(J) 出现的频率,您可能会很幸运,而永远不会在练习中体验比赛。或者你可能会倒霉。无论哪种方式,如所写,程序都是错误的。

FWIW 我同意你的怀疑,即对 X 元素的不规则访问模式是你所报告的时序异常的根源,它需要通过缓存进行更多的数据移动。

另外,在我写作的时候,这一行

  INTEGER, INTENT(IN) :: NELEM,NELMAX = 25996

也是错误的,尝试初始化例程参数是语法错误。

编辑,回应 OP 的评论:

依赖肯定是另一个问题 -- 不是我的思维方式,依赖(我认为你的意思是我所说的数据竞争)使程序错误的,破碎的,错误的。缩放比例不佳只是一种不便。问题出现在程序的 OpenMP 版本中,因为两个或更多线程可能会尝试在大约同时更新 X 的相同元素。更新不是原子的,在幕后进行的各种操作(将数据读取到寄存器,将两个寄存器中的值加在一起,将数据写入内存位置,诸如此类)可以以任何方式交错,并且大多数这些交错不会像在程序的顺序执行中那样将值留在 X 中。

你说的数据移动能给点提示吗?暂时不会,我写的够多了