2013-05-19 9 views
8

के बीच एक साधारण परीक्षण केस scicomp पर इस प्रश्न में भाग गया जिसमें एक योग की गणना शामिल है। वहां, आप c++ और इसी तरह के fortran कार्यान्वयन देख सकते हैं। दिलचस्प बात यह है कि मैंने देखा कि फोर्टन संस्करण लगभग 32% तेज था।क्लैंग ++/g ++/gfortran

मैंने सोचा, मुझे उनके नतीजे के बारे में निश्चित नहीं था और स्थिति को पुन: उत्पन्न करने की कोशिश की। यहाँ (बहुत थोड़ा) अलग अलग कोड मैं भाग गया है:

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 

जी ++

real 0m2.225s 
user 0m2.228s 
sys  0m0.000s 

बजना

real 0m1.250s 
user 0m1.244s 
sys  0m0.004s 

दिलचस्प बात यह भी देख सकता है कि fortran कोड c++ से लगभग 32% है जब gcc का उपयोग किया जाता है। clang का उपयोग करते हुए, मैं देख सकता हूं कि c++ कोड वास्तव में लगभग 19% तक तेजी से चलता है। यहां मेरे प्रश्न हैं:

  1. gfortran से g ++ उत्पन्न कोड धीमा क्यों है? चूंकि वे एक ही कंपाइलर परिवार से हैं, इसका मतलब यह है कि (इस) फोर्टन कोड को बस एक तेज कोड में अनुवादित किया जा सकता है? क्या यह आम तौर पर फोर्टन बनाम सी ++ के मामले में होता है?
  2. clang क्यों इतना अच्छा कर रहा है? क्या llvm कंपाइलर के लिए एक फोर्टन फ्रंट एंड है? यदि वहां, क्या उस कोड द्वारा उत्पन्न कोड भी तेज होगा?

अद्यतन:

-ffast-math -O3 विकल्पों का उपयोग निम्न परिणाम उत्पन्न करता है:

gfortran

real 0m1.515s 
user 0m1.512s 
sys  0m0.000s 

जी ++

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 जोड़ने से

+5

संकलन के लिए उपयोग किए गए कंपाइलर विकल्प प्रदान करें। जीसीसी के लिए -फैथ-गणित के रूप में ऐसे विकल्प महत्वपूर्ण रूप से समय को प्रभावित कर सकते हैं। –

+0

@ निकोलेविस्कोव एकमात्र ध्वज जिसे मैं स्पष्ट रूप से उपयोग करता हूं वह सभी कंप्यूटर्स पर '-O3' है। – GradGuy

+0

मेरी मशीन पर: क्लैंग '0.62' (-फैस्ट-गणित '0.60'), जी ++ 4.6' 1.23' (-फैस्ट-गणित '0.78'), जी ++ 4.7' 1.1 9' (-फैस्ट-गणित' 0.76 ') – leemes

उत्तर

1

मुझे विश्वास है कि आपकी समस्या आउटपुट हिस्से में है। यह अच्छी तरह से ज्ञात है कि सी ++ धाराएं (std::cout) अक्सर बहुत अक्षम होती हैं। जबकि विभिन्न कंपाइलर इसे अनुकूलित कर सकते हैं, std::cout के बजाय सी printf फ़ंक्शन का उपयोग करके महत्वपूर्ण प्रदर्शन भागों को फिर से लिखना हमेशा अच्छा विचार है।

+2

मुझे नहीं लगता कि 10 प्रिंटआउट ~ 1.0 एस रेंज में प्रदर्शन को प्रभावित करने जा रहे हैं। – steabert

+0

आप सही हो सकते हैं। मैंने इसे स्वयं परीक्षण नहीं किया, लेकिन यह निश्चित रूप से सोचता है कि किसी को हमेशा देखना चाहिए। – varepsilon

1

समय अंतर अंतर pow निष्पादित करने के समय से संबंधित होगा, क्योंकि अन्य कोड अपेक्षाकृत सरल है। आप प्रोफाइलिंग करके इसे देख सकते हैं। प्रश्न यह है कि संकलक पावर फ़ंक्शन की गणना करने के लिए क्या करता है?

मेरा समय: gfortran -O3 के साथ फोर्ट्रान संस्करण के लिए ~ 1.20 एस, और g++ -O3 -ffast-math के साथ संकलित सी ++ संस्करण के लिए 1.07 एस। ध्यान दें कि -ffast-mathgfortran के लिए कोई फर्क नहीं पड़ता, क्योंकि pow लाइब्रेरी से कॉल किया जाएगा, लेकिन यह g++ के लिए एक बड़ा अंतर बनाता है।

मेरे मामले में, gfortran के लिए, यह _gfortran_pow_c8_i4 फ़ंक्शन है जिसे source code कहा जाता है)। उनका कार्यान्वयन पूर्णांक शक्तियों की गणना करने का सामान्य तरीका है। दूसरी तरफ g++ के साथ, यह libstdC++ लाइब्रेरी से एक फ़ंक्शन टेम्पलेट है, लेकिन मुझे नहीं पता कि यह कैसे कार्यान्वित किया गया है। जाहिर है, यह थोड़ा बेहतर लिखा/अनुकूलन है। मुझे पता नहीं है कि फ्लाई पर फ़ंक्शन को किस हद तक संकलित किया गया है, यह एक टेम्पलेट पर विचार कर रहा है। इसके लायक होने के लिए, फोरट्रान संस्करण ifort और सी ++ संस्करण icc (-fast अनुकूलन ध्वज का उपयोग करके) के साथ संकलित किया गया है, दोनों एक ही समय देते हैं, इसलिए मुझे लगता है कि ये वही लाइब्रेरी फ़ंक्शंस का उपयोग करते हैं।

अगर मैं सिर्फ जटिल गणित के साथ फोरट्रान में एक शक्ति समारोह लिखने (स्पष्ट रूप वास्तविक और काल्पनिक भागों लिखने), यह के रूप में तेजी से है सी ++ संस्करण के साथ g++ (लेकिन फिर -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 

मेरे अनुभव में, का उपयोग कर फोरट्रान कार्यान्वयन में स्पष्ट वास्तविक और काल्पनिक भागों, तेजी से होता है allthough यह पाठ्यक्रम जटिल प्रकार का उपयोग करने की बहुत सुविधाजनक है।

अंतिम नोट: भले ही यह केवल एक उदाहरण है, फिर भी प्रत्येक समारोह में पावर फ़ंक्शन को कॉल करने का तरीका बेहद अक्षम है।इसके बजाए, आपको निश्चित रूप से प्रत्येक पुनरावृत्ति द्वारा a गुणा करना चाहिए।