【发布时间】: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