【发布时间】:2022-01-11 15:10:11
【问题描述】:
我的问题是,对于串行和 OpenMP,在 Fortran 90 或更高版本中为数组提供初始值的最快方法是什么。我可以试试
(a)A = 0.0;或
(b) 为A(i, j...) = 0.0 执行嵌套循环并调整循环顺序以适应矢量化(第一个参数的最内层)
我不知何故记得,但在谷歌搜索几次后找不到参考,编译器将尝试对 (a) 进行矢量化。这里是串口级别的测试(抱歉代码比较乱,不是面向过程的,一些变量名等取自之前的回复)
Program vectorization_test
Use, Intrinsic :: iso_fortran_env, Only : wp => real64, li => int64
real :: A(20,20,20,20), sum_time
integer :: i,j,k,l,n,m, m_iter
Integer( li ) :: start, finish, rate
m_iter = 10
n = 20
sum_time = 0.0
do m = 1, m_iter
Call System_clock( start, rate )
A= 0.0
Call System_clock( finish, rate )
write(*,*) 'time 1', Real( finish - start, wp ) / rate
sum_time = sum_time + Real( finish - start, wp ) / rate
end do
write(*,*) 'average time', sum_time / m_iter
sum_time = 0.0
do m = 1, m_iter
Call System_clock( start, rate )
do l = 1, n
do k = 1, n
do j = 1, n
do i = 1, n
A(i,j,k,l) = 0.0
end do
end do
end do
end do
Call System_clock( finish, rate )
write(*,*) 'time 2', Real( finish - start, wp ) / rate
sum_time = sum_time + Real( finish - start, wp ) / rate
end do
write(*,*) 'average time 2', sum_time / m_iter
sum_time = 0.0
do m = 1, m_iter
Call System_clock( start, rate )
do l = 1, n
do j = 1, n
do k = 1, n
do i = 1, n
A(i,j,k,l) = 0.0
end do
end do
end do
end do
Call System_clock( finish, rate )
write(*,*) 'time 3', Real( finish - start, wp ) / rate
sum_time = sum_time + Real( finish - start, wp ) / rate
end do
write(*,*) 'average time 3', sum_time / m_iter
sum_time = 0.0
do m = 1, m_iter
Call System_clock( start, rate )
do i = 1, n
do j = 1, n
do k = 1, n
do l = 1, n
A(i,j,k,l) = 0.0
end do
end do
end do
end do
Call System_clock( finish, rate )
write(*,*) 'time 4', Real( finish - start, wp ) / rate
sum_time = sum_time + Real( finish - start, wp ) / rate
end do
write(*,*) 'average time 4', sum_time / m_iter
end program vectorization_test
我在具有 16 GB 内存的笔记本电脑上从 gfortran-11 -o3 获得了 average time 3.76699973E-05, average time 2 5.98790008E-04, average time 3 6.55650045E-04, average time 4 3.10386019E-03。在具有 384 GB 内存的计算中心上,我得到了 average time 4.75034976E-05, average time 2 , 4.47604398E-04, average time 3 4.70327737E-04, average time 4 4.14085982E-04。更大的维度类似趋势。
不确定这是否适用于其他编译器。似乎最里面的循环对于矢量化是最关键的。
所以我的问题是
(1)这个问题有没有关于数组的向量化和初始化的参考;
(2) 如果我使用 OpenMP,我应该对一个变量使用单个循环吗,A(i,:,:,:) = 0.0 之类的?
附:数组的初始化很可能不是瓶颈,所以这个问题更多地属于我的好奇。
【问题讨论】:
-
这取决于很多细节,但如果它测量任何东西,这里相关的是内存带宽。考虑您使用的特定硬件以及您使用的线程数非常重要。任何超线程?
-
非常感谢。只需
i7-5600U CPU在我的旧笔记本电脑上使用 16 GB 内存。我在计算中心的Intel(R) Xeon(R) Gold 6148 CPU上试过一次,ifort在各种维度的数组中几乎为零。 -
笔记本电脑不会针对内存带宽进行优化。但是您想为笔记本电脑还是大型机器优化代码?
-
在这种情况下进行测试和测量。我怀疑是否有任何通用的银弹。
-
拜托上帝没有。如果你依赖它,你的代码就被破坏了。谁知道您可以访问执行此操作的编译器多长时间?谁知道 ifort 会继续支持多久?
标签: fortran openmp vectorization