簡體   English   中英

clang ++ / g ++ / gfortran之間的一個簡單測試案例

[英]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.3clang 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%的速度運行。 這是我的問題:

  1. 為什么g ++生成的代碼比gfortran慢? 由於它們來自同一編譯器家族,這是否意味着(tran)fortran代碼可以簡單地轉換為更快的代碼? fortran vs c ++通常是這種情況嗎?
  2. 為什么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-mathg++編譯的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM