首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Fortran的向量化和

Fortran的向量化和
EN

Stack Overflow用户
提问于 2015-08-27 18:48:32
回答 2查看 1K关注 0票数 7

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

我知道有些指令可以矢量化,而另一些指令则不能,所以我想确保:

sum(A(i1:i2,ir))

同样,这一行占用了运行时的大约50%,因为我是在一个非常大的矩阵上这样做的。我可以给出更多关于我为什么要这样做的信息,但只需说明这是必要的,尽管我可以在必要时重构内存(例如,如果可以将其向量化,我可以以sum(A(ir,i1:i2))的形式进行求和。

这条线是矢量化的吗?我怎么知道?如果没有向量化,如何强制矢量化?

编辑:多亏了这些评论,我现在意识到我可以通过-ftree-vectorizer-verbose检查这个求和的向量化,并看到这不是矢量化。我已将守则重组如下:

代码语言:javascript
复制
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%的速度增长,因为矢量化。问题仍然存在:为什么sum(A(i1:i2,ir))不矢量化,我如何才能得到一个简单的sum来矢量化?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-08-28 15:48:34

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

我玩过的两个代码片段是:

代码语言:javascript
复制
tsum = 0.0d0
tvec(1:n) = A(i1:i2, ir)
do ii = 1,n
    tsum = tsum + tvec(ii)
enddo

代码语言:javascript
复制
tsum = sum(A(i1:i2,ir))

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

代码语言:javascript
复制
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))矢量化为

代码语言:javascript
复制
 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-math-optimizations进行比较时,显示出大约70%的加速比。(请注意,每次只运行一次--在发布之前,我们将对多次运行执行真正的基准测试)。

不过,我确实受了点小伤。当我使用-f选项时,我的值略有变化。没有它们,我的变量(v1v2)的错误是:

代码语言:javascript
复制
v1 ... 5.60663e-15     9.71445e-17     1.05471e-15
v2 ... 5.11674e-14     1.79301e-14     2.58127e-15

但是,对于优化,错误是:

代码语言:javascript
复制
v1 ... 7.11931e-15     5.39846e-15     3.33067e-16
v2 ... 1.97273e-13     6.98608e-14     2.17742e-14

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

票数 1
EN

Stack Overflow用户

发布于 2015-08-28 23:07:35

您的显式循环版本仍然按照与矢量化版本不同的顺序添加FP。向量版本使用4个累加器,每个累加器每4个数组元素。

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

代码语言:javascript
复制
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添加单元。Skylake每个时钟可以做两个FP加法,用latency=4。以前的Intel CPU每个时钟做一个,用latency=3。所以在Skylake上,你需要8个矢量累加器来饱和FP单元。当然,它们必须是256 b矢量,因为AVX指令的速度是SSE矢量指令的两倍。

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32257244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档