Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran中的矢量化和_Fortran_Sse_Gfortran_Simd_Avx - Fatal编程技术网

Fortran中的矢量化和

Fortran中的矢量化和,fortran,sse,gfortran,simd,avx,Fortran,Sse,Gfortran,Simd,Avx,我正在使用gfortran和-mavx编译我的Fortran代码,并且已经验证了一些指令是通过objdump矢量化的,但是我没有得到我期望的速度改进,所以我想确保以下参数是矢量化的(这条指令约占运行时的50%) 我知道有些指令可以矢量化,而有些指令不能矢量化,因此我想确保: sum(A(i1:i2,ir)) 同样,这一行占用了大约50%的运行时间,因为我是在一个非常大的矩阵上进行这项工作的。我可以提供更多关于我为什么这样做的信息,但足以说明这是必要的,尽管我可以在必要时重新构造内存(例如,我可以

我正在使用
gfortran
-mavx
编译我的
Fortran
代码,并且已经验证了一些指令是通过
objdump
矢量化的,但是我没有得到我期望的速度改进,所以我想确保以下参数是矢量化的(这条指令约占运行时的50%)

我知道有些指令可以矢量化,而有些指令不能矢量化,因此我想确保:

sum(A(i1:i2,ir))

同样,这一行占用了大约50%的运行时间,因为我是在一个非常大的矩阵上进行这项工作的。我可以提供更多关于我为什么这样做的信息,但足以说明这是必要的,尽管我可以在必要时重新构造内存(例如,我可以按
sum(a(ir,i1:i2))进行求和
如果可以改为矢量化

这条线是矢量化的吗?我怎么知道?如果它不是矢量化的,我怎么强制矢量化

编辑:多亏了这些评论,我现在意识到我可以通过
-ftree vectorizer verbose
检查此总和的矢量化,并发现这不是矢量化。我已按如下方式重新构造代码:

tsum = 0.0d0
tn = i2 - i1 + 1
tvec(1:tn) = A(i1:i2, ir)
do ii = 1,tn
    tsum = tsum + tvec(ii)
enddo

当我打开
-funsafe math optimizations
时,这只矢量化,但我确实看到矢量化又提高了70%的速度。问题仍然存在:
为什么求和(A(i1:i2,ir))
不矢量化,如何获得简单的
求和
进行矢量化?

事实证明,除非我包含
-ffast math
-funsafe math优化,否则我无法使用矢量化

我使用的两个代码片段是:

tsum = 0.0d0
tvec(1:n) = A(i1:i2, ir)
do ii = 1,n
    tsum = tsum + tvec(ii)
enddo

下面是我使用不同编译选项运行第一个代码段的次数:

10.62 sec ... None
10.35 sec ... -mtune=native -mavx
 7.44 sec ... -mtune-native -mavx -ffast-math
 7.49 sec ... -mtune-native -mavx -funsafe-math-optimizations
最后,通过这些相同的优化,我能够向量化
tsum=sum(A(i1:i2,ir))
以获得

 7.96 sec ... None
 8.41 sec ... -mtune=native -mavx
 5.06 sec ... -mtune=native -mavx -ffast-math
 4.97 sec ... -mtune=native -mavx -funsafe-math-optimizations
当我们将
sum
-mtune=native-mavx
-mtune=native-mavx-funsafe数学优化
进行比较时,它显示了约70%的加速(注意,这些优化每次只运行一次-在发布之前,我们将对多次运行进行真正的基准测试)

不过,我确实受到了一些影响。当我使用
-f
选项时,我的值会略有变化。如果没有这些选项,我的变量(
v1
v2
)的错误如下:

但通过优化,错误是:

v1 ... 7.11931e-15     5.39846e-15     3.33067e-16
v2 ... 1.97273e-13     6.98608e-14     2.17742e-14

这表明确实发生了一些不同的事情。

您的显式循环版本仍然以不同于矢量化版本的顺序执行FP添加。矢量版本使用4个累加器,每个累加器获得第4个数组元素

您可以编写源代码以匹配向量版本的功能:

tsum0 = 0.0d0
tsum1 = 0.0d0
tsum2 = 0.0d0
tsum3 = 0.0d0
tn = i2 - i1 + 1
tvec(1:tn) = A(i1:i2, ir)
do ii = 1,tn,4   ! count by 4
    tsum0 = tsum0 + tvec(ii)
    tsum1 = tsum1 + tvec(ii+1)
    tsum2 = tsum2 + tvec(ii+2)
    tsum3 = tsum3 + tvec(ii+3)
enddo

tsum = (tsum0 + tsum1) + (tsum2 + tsum3)
这可能在没有
-ffast math
的情况下进行矢量化

FP add具有多周期延迟,但每个时钟吞吐量只有一个或两个,因此需要asm使用多个向量累加器使FP add单元饱和.Skylake可以对每个时钟进行两次FP加法,延迟为4。以前的Intel CPU对每个时钟进行一次FP加法,延迟为3。因此在Skylake上,需要8个向量累加器对FP单元进行饱和。当然,它们必须是256b向量,因为AVX指令的速度与SSE向量指令一样快,但所做的工作是SSE向量指令的两倍

用8*8累加器变量编写源代码是荒谬的,因此我想您需要
-ffast math
,或者一个OpenMP pragma,告诉编译器不同的操作顺序是可以的


显式展开源代码意味着您必须处理不是向量宽度*展开倍数的循环计数。如果您对某些内容进行限制,它可以帮助编译器避免生成多个版本的循环或额外的循环设置/清理代码。

不太重复,但:Fortran以列主方式访问数组,即您r当前版本比sum(A(ir,i1:i2))快得多。
。当前版本访问一个连续的内存块。关于您的编辑:非常有趣。我本来希望总和是矢量化的。您是否使用sum vs loop进行过实际的基准测试?是否使用过优化开关?更新:?OpenMP 4“simd”子句和缩减?您还可以尝试使用
-fopt info
来获取更多信息(这在
man-gcc
中有说明)。我想,有某种形式的循环展开。嗯,我想优化的不安全性的一个来源可能来自重新安排操作顺序。我不认为机器精度方面的错误是致命的。如果tn不是4的倍数,那么循环会遗漏一些还是走得太远?@Laurbert515:是的,一个或另一个。如果我知道Fortran,我可以告诉你是哪一个。:P这是我最后一段描述的问题:展开导致需要清理代码来处理奇数次迭代。让编译器通过使用
-ffast math
或OpenMP来解决这一问题将节省大量调试(或者至少花点时间思考一下,确保一开始不会引入bug。)
v1 ... 7.11931e-15     5.39846e-15     3.33067e-16
v2 ... 1.97273e-13     6.98608e-14     2.17742e-14
tsum0 = 0.0d0
tsum1 = 0.0d0
tsum2 = 0.0d0
tsum3 = 0.0d0
tn = i2 - i1 + 1
tvec(1:tn) = A(i1:i2, ir)
do ii = 1,tn,4   ! count by 4
    tsum0 = tsum0 + tvec(ii)
    tsum1 = tsum1 + tvec(ii+1)
    tsum2 = tsum2 + tvec(ii+2)
    tsum3 = tsum3 + tvec(ii+3)
enddo

tsum = (tsum0 + tsum1) + (tsum2 + tsum3)