[英]A simple test case between clang++/g++/gfortran
我在scicomp上遇到了這個問題,涉及計算總和。 在這里,您可以看到c ++和類似的fortran實現。 有趣的是,我看到fortran版本的速度提高了約32%。
我想,我不確定他們的結果,並試圖重振局勢。 這是我運行的(非常微小)不同的代碼:
C ++
#include <iostream>
#include <complex>
#include <cmath>
#include <iomanip>
int main ()
{
const double alpha = 1;
std::cout.precision(16);
std::complex<double> sum = 0;
const std::complex<double> a = std::complex<double>(1,1)/std::sqrt(2.);
for (unsigned int k=1; k<10000000; ++k)
{
sum += std::pow(a, k)*std::pow(k, -alpha);
if (k % 1000000 == 0)
std::cout << k << ' ' << sum << std::endl;
}
return 0;
}
Fortran
implicit none
integer, parameter :: dp = kind(0.d0)
complex(dp), parameter :: i_ = (0, 1)
real(dp) :: alpha = 1
complex(dp) :: s = 0
integer :: k
do k = 1, 10000000
s = s + ((i_+1)/sqrt(2._dp))**k * k**(-alpha)
if (modulo(k, 1000000) == 0) print *, k, s
end do
end
我在Ubuntu 12.04 LTS
計算機上使用gcc 4.6.3
和clang 3.0
編譯了以上代碼,所有代碼均帶有-O3
標志。 這是我的時間安排:
time ./a.out
gfortran
real 0m1.538s
user 0m1.536s
sys 0m0.000s
g ++
real 0m2.225s
user 0m2.228s
sys 0m0.000s
鐺
real 0m1.250s
user 0m1.244s
sys 0m0.004s
有趣的是,我還看到使用gcc
時, fortran
代碼比c++
快32%。 但是,使用clang
,我可以看到c++
代碼實際上以大約19%的速度運行。 這是我的問題:
clang
在這里做得這么好? 是否有用於llvm編譯器的fortran前端? 如果存在,那么由該代碼生成的代碼會更快嗎? 更新:
使用-ffast-math -O3
選項將產生以下結果:
gfortran
real 0m1.515s
user 0m1.512s
sys 0m0.000s
g ++
real 0m1.478s
user 0m1.476s
sys 0m0.000s
鐺
real 0m1.253s
user 0m1.252s
sys 0m0.000s
Npw g++
版本以gfortran
快速運行速度,而clang
運行速度卻快於兩者。 將-fcx-fortran-rules
添加到上述選項不會顯着改變結果
我相信您的問題出在輸出部分。 眾所周知,C ++流( std::cout
)通常效率很低。 盡管不同的編譯器可以對此進行優化,但始終最好使用C printf
函數而不是std::cout
重寫關鍵性能部分。
時間差將與執行pow
所需的時間有關,因為其他代碼相對簡單。 您可以通過分析來檢查。 那么問題是編譯器如何計算冪函數?
我的時間是:對於使用gfortran -O3
的Fortran版本,大約是1.20 s,對於使用g++ -O3 -ffast-math
編譯的C ++版本, g++ -O3 -ffast-math
1.07 s。 請注意, -ffast-math
對於gfortran
無關緊要,因為pow
將從庫中調用,但是對於g++
卻有很大的不同。
就我而言,對於gfortran
,調用的是_gfortran_pow_c8_i4
函數( 源代碼 )。 它們的實現是計算整數冪的常用方法。 另一方面,對於g++
,它是libstdc ++庫中的函數模板,但我不知道它是如何實現的。 顯然,它的編寫/可優化性要好一些。 考慮到它是模板,我不知道該函數在多大程度上被即時編譯。 值得一提的是,使用ifort
編譯的Fortran版本和使用icc
編譯的C ++版本(使用-fast
優化標志)都給出相同的計時,因此我猜它們使用相同的庫函數。
如果我只是用復雜的算術在Fortran中寫一個冪函數(明確地寫出實部和虛部),它的速度-ffast-math
用g++
編譯的C ++版本一樣快(但是-ffast-math
減慢了它的速度,所以我只使用-O3
使用gfortran
):
complex(8) function pow_c8_i4(a, k)
implicit none
integer, intent(in) :: k
complex(8), intent(in) :: a
real(8) :: Re_a, Im_a, Re_pow, Im_pow, tmp
integer :: i
Re_pow = 1.0_8
Im_pow = 0.0_8
Re_a = real(a)
Im_a = aimag(a)
i = k
do while (i.ne.0)
if (iand(i,1).eq.1) then
tmp = Re_pow
Re_pow = Re_pow*Re_a-Im_pow*Im_a
Im_pow = tmp *Im_a+Im_pow*Re_a
end if
i = ishft(i,-1)
tmp = Re_a
Re_a = Re_a**2-Im_a**2
Im_a = 2*tmp*Im_a
end do
pow_c8_i4 = cmplx(Re_pow,Im_pow,8)
end function
以我的經驗,在Fortran實現中使用顯式實部和虛部比較快,盡管使用復雜類型當然很方便。
最后說明:盡管僅是示例,但每次迭代調用冪函數的方式效率極低。 取而代之的是,您當然應該在每次迭代時都乘以a
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.