【问题标题】:How to vectorize inner loops with omp simd如何使用 omp simd 向量化内部循环
【发布时间】:2014-05-12 03:38:03
【问题描述】:

我有 3 个这样的嵌套循环:

      !$omp parallel do schedule(runtime) private(s1)
      DO  k = 0, z
         !$omp simd collapse( 2 ) reduction( +: s1 )
         DO  i = 0, x
            DO  j =  0, z
               s1 = s1 + array(k,j,i)
            ENDDO
         ENDDO
         sums_l(k) = s1
      ENDDO

但英特尔编译器抱怨“警告 #13379:循环未使用“simd”进行向量化” 这是为什么?我该怎么做呢?

//EDIT3:这是产生错误的代码。它被减少到仍然导致错误的最小值。如果你从字面上删除任何东西,它就会矢量化。

SUBROUTINE simdTest

  IMPLICIT NONE

  INTEGER ::  i, j, k, sr, tn,nzb,nzt,nxl,nxr,nys,nyn
  REAL    ::  s1, s2, s3, s4
  REAL, DIMENSION(:,:,:), ALLOCATABLE :: u,v,pt,rmask,sums_l
  REAL, DIMENSION(:,:), ALLOCATABLE :: usws,vsws,shf

  !$omp parallel do schedule(runtime) private(s1,s2,s3)
  DO  k = nzb, nzt+1
    !$omp simd collapse( 2 ) reduction( +: s1, s2, s3 )
    DO  i = nxl, nxr
       DO  j =  nys, nyn
          s1 = s1 + u(k,j,i)  * rmask(j,i,sr)
          s2 = s2 + v(k,j,i)  * rmask(j,i,sr)
          s3 = s3 + pt(k,j,i) * rmask(j,i,sr)
       ENDDO
    ENDDO
    sums_l(k,1,tn) = s1
    sums_l(k,2,tn) = s2
    sums_l(k,4,tn) = s3
  ENDDO

  !$omp parallel do reduction( +: s1, s2, s3, s4) schedule(runtime)
  DO  i = nxl, nxr
   DO  j =  nys, nyn
      s1 = s1 + usws(j,i) * rmask(j,i,sr)
      s2 = s2 + vsws(j,i) * rmask(j,i,sr)
      s3 = s3 + shf(j,i)  * rmask(j,i,sr)
      s4 = s4 + 0.0
   ENDDO
  ENDDO
  sums_l(nzb,12,tn) = s1
  sums_l(nzb,14,tn) = s2
  sums_l(nzb,16,tn) = s3

END SUBROUTINE

【问题讨论】:

  • 当我更正您的代码(目标 => 结束并行)时,它不会打印此警告。我们需要更多细节。
  • 内部循环中数组的访问步幅不统一。 Fortran 使用以列为主的数组存储,因此array(k,j,i)array(k,j+1,i) 在内存中可能相距甚远。这在没有收集矢量负载(即没有 AVX2)的 CPU 上是不可矢量化的,并且在许多情况下即使支持也非常低效。因此,矢量化器可能会认为成本高于串行实现循环的成本。
  • 好的,我在 Ivy Bridge 上试过了。不过,我也注意到了步伐。
  • 结果是:simd.f90(10): (col. 10) remark: OpenMP SIMD LOOP WAS VECTORIZED 即使是假设的形状虚拟参数。
  • 英特尔的编译器非常聪明。它可以重新排列循环并执行其他技巧,以使代码成为 SIMD-ise。在这种情况下,k 上的循环可以设置为最内层并矢量化。不确定这是 simd 构造的预期效果。你检查过汇编代码吗?

标签: fortran openmp nested-loops simd


【解决方案1】:

在 cmets 中没有更多的地方了:

当我在 Ivy Bridge CPU 上编译它时,我得到了这个。第 15 行的循环在 CPU 上进行矢量化是无利可图的,但请注意它对于 Intel MIC 架构是矢量化的。循环 16 在 CPU 上被向量化,同时删除了目标指令。

矢量化问题的原因在于第一句话“下标太复杂”。

ifort -openmp simd.f90 -warn -O3 -c -vec-report=3 -xHOST -fpp 
ifort: command line remark #10382: option '-xHOST' setting '-xCORE-AVX-I'
simd.f90(17): (col. 33) remark: loop was not vectorized: subscript too complex
simd.f90(15): (col. 5) warning #13379: loop was not vectorized with "simd"
simd.f90(16): (col. 8) remark: LOOP WAS VECTORIZED
simd.f90(13): (col. 3) remark: loop was not vectorized: not inner loop
simd.f90(13): (col. 3) remark: loop was not vectorized: not inner loop
simd.f90(31): (col. 4) remark: LOOP WAS VECTORIZED
simd.f90(30): (col. 3) remark: loop was not vectorized: not inner loop
simd.f90(29): (col. 7) remark: loop was not vectorized: not inner loop
simd.f90(29): (col. 7) remark: BLOCK WAS VECTORIZED
ifort: warning #10362: Environment configuration problem encountered.  Please check for proper MPSS installation and environment setup.
simd.f90(15): (col. 5) remark: *MIC* OpenMP SIMD LOOP WAS VECTORIZED
simd.f90(13): (col. 3) remark: *MIC* loop was not vectorized: not inner loop
simd.f90(13): (col. 3) remark: *MIC* loop was not vectorized: not inner loop
simd.f90(31): (col. 4) remark: *MIC* LOOP WAS VECTORIZED
simd.f90(31): (col. 4) remark: *MIC* PEEL LOOP WAS VECTORIZED
simd.f90(31): (col. 4) remark: *MIC* REMAINDER LOOP WAS VECTORIZED
simd.f90(30): (col. 3) remark: *MIC* loop was not vectorized: not inner loop
simd.f90(29): (col. 7) remark: *MIC* loop was not vectorized: not inner loop

【讨论】:

  • 尝试删除 s4 =... 行并重新编译。循环将被矢量化。所以这里似乎编译器出错了。
  • 我无法确认这一点。但是,如果我从第 28 行开始删除完整的块,那么它确实是矢量化的。如需解释,您可能需要联系英特尔。最好通过官方渠道 - 支持论坛或 Premier 支持网站。
猜你喜欢
  • 1970-01-01
  • 2016-10-04
  • 2018-07-20
  • 2019-09-27
  • 2016-03-20
  • 1970-01-01
  • 2018-12-16
  • 2013-01-18
  • 2023-04-11
相关资源
最近更新 更多