fortran - 如何在 Fortran 中真正实现矢量化?
问题描述
以下所有代码都使用 -O3 -xHost(或 gfortran 中的 -Ofast -march=native)优化。
示例1
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
c(:)=a(:)+b(:)
return
end
上面的代码应该是矢量化的吧?real 是 real 8 类型,它应该在 ram 中占用 64 位。对于 AVX2,它带有 256 位寄存器或其他东西,上面的代码就像在一个时钟周期内做 c(1:4) = a(1:4) + b(1:4) 什么的,而 4 是因为 256/ 64=4。
但是为什么我经常发现实际执行循环更快?参见示例 2,
示例2
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
integer :: i
do i=1,1000
c(i)=a(i)+b(i)
endddo
return
end
我注意到 example1 中的编译器可能会抱怨数组未对齐或其他问题。因此实际上 example2 比 example1 快。但我的意思是原则上 example1 和 2 应该是相同的速度吧?在 example2 中,编译器应该足够聪明,可以相应地对代码进行矢量化。
最后,在下面的代码example3中,是否有任何向量化?
示例3
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
c(:) = exp(a(:)) + log(b(:))
return
end
或稍微复杂的事情,例如 example4 example4
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
c(:) = exp(a(:)) + log(b(:)) + exp(a(:)) * log(b(:))
return
end
我的意思是矢量化仅适用于那些非常基本的操作,例如 op = + - * /
a(:) = b(:) op c(:)
但是,对于更复杂的事情,例如
a(:) = log(b(:) + c(:)*exp(a(:))*ln(b(:)))
那么矢量化可能不起作用?
在许多情况下,使用 do 循环似乎比编写诸如 a(:)=b(:)+c(:) 之类的东西要快。似乎编译器在执行 do 循环时做得非常好或高度优化。
解决方案
推荐阅读
- database - 我应该查询还是应该使用 url 变量?
- ehcache - 在缓存中添加新条目时,磁盘存储放置似乎不是异步的
- mysql - 无法在数据库中创建表
- android - TextView 文本居中对齐
- c# - 如何测试 NetworkClient.Connect 功能?
- c# - 将 DateTime 转换为人类可读的格式(MSFT_MpComputerStatus 类)
- android - 为什么我的应用安装后 Google Pay 停止工作?
- apache-nifi - 在 nifi 中如何获取访问令牌和客户端 ID
- qt - 如何在docker中为qt5应用程序启用中文输入法
- logging - appsettings.json 中不支持日志记录配置全局 LogLevel