2009-07-13 33 views
9

यहाँ कुछ कोड है (पूरा कार्यक्रम सवाल में बाद में इस प्रकार):अनुकूलन

template <typename T> 
T fizzbuzz(T n) { 
    T count(0); 
    #if CONST 
     const T div(3); 
    #else 
     T div(3); 
    #endif 
    for (T i(0); i <= n; ++i) { 
     if (i % div == T(0)) count += i; 
    } 
    return count; 
} 

अब, अगर मैं int के साथ इस टेम्पलेट फ़ंक्शन को कॉल करें, तो मैं के अनुसार 6 प्रदर्शन अंतर का एक पहलू मिल क्या मैं cONST या नहीं परिभाषित:

$ gcc --version 
gcc (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125) 

$ make -B wrappedint CPPFLAGS="-O3 -Wall -Werror -DWRAP=0 -DCONST=0" && 
time ./wrappedint 
g++ -O3 -Wall -Werror -DWRAP=0 -DCONST=0 wrappedint.cpp -o wrappedi 
nt 
484573652 

real 0m2.543s 
user 0m2.059s 
sys  0m0.046s 

$ make -B wrappedint CPPFLAGS="-O3 -Wall -Werror -DWRAP=0 -DCONST=1" && 
time ./wrappedint 
g++ -O3 -Wall -Werror -DWRAP=0 -DCONST=1 wrappedint.cpp -o wrappedi 
nt 
484573652 

real 0m0.655s 
user 0m0.327s 
sys  0m0.046s 

disassembly की जांच से पता चलता तेज (स्थिरांक) मामले में, सापेक्ष धीमी गति से (गैर स्थिरांक) मामले में एक गुणा और पाली प्रकार बात में बदल दिया गया, जबकि यहका उपयोग कर रहा है 0।

भी बदतर है, अगर मैं एक कक्षा में मेरी पूर्णांक रैप करने के लिए प्रयास करते हैं, तो अनुकूलन है कि क्या मैं स्थिरांक या नहीं का उपयोग नहीं होता है। कोड हमेशा idivl का उपयोग करता है और धीमी गति से चलाता है:

#include <iostream> 

struct WrappedInt { 
    int v; 
    explicit WrappedInt(const int &val) : v(val) {} 
    bool operator<=(const WrappedInt &rhs) const { return v <= rhs.v; } 
    bool operator==(const WrappedInt &rhs) const { return v == rhs.v; } 
    WrappedInt &operator++() { ++v; return *this; } 
    WrappedInt &operator+=(const WrappedInt &rhs) { v += rhs.v; return *this; } 
    WrappedInt operator%(const WrappedInt &rhs) const 
     { return WrappedInt(v%rhs.v); } 
}; 

std::ostream &operator<<(std::ostream &s, WrappedInt w) { 
    return s << w.v; 
} 

template <typename T> 
T fizzbuzz(T n) { 
    T count(0); 
    #if CONST 
     const T div(3); 
    #else 
     T div(3); 
    #endif 
    for (T i(0); i <= n; ++i) { 
     if (i % div == T(0)) count += i; 
    } 
    return count; 
} 

int main() { 
    #if WRAP 
     WrappedInt w(123456789); 
     std::cout << fizzbuzz(w) << "\n"; 
    #else 
     std::cout << fizzbuzz<int>(123456789) << "\n"; 
    #endif 
} 

मेरे प्रश्न हैं:

1) वहाँ सी ++ ही, या जीसीसी के अनुकूलन है, जो बताते हैं कि ऐसा क्यों होता की एक सरल सिद्धांत है, या यह सिर्फ एक है "विभिन्न हेरिस्टिक्स रन के मामले में, यह वह कोड है जिसे आप प्राप्त करते हैं"?

2) क्या कंपाइलर को यह एहसास करने का कोई तरीका है कि मेरे स्थानीय रूप से घोषित और कभी-संदर्भित कॉन्स्ट रैपप्डआईंट को संकलन-समय का मूल्य मान माना जा सकता है? मैं चाहता हूं कि यह चीज़ टेम्पलेट्स में int के लिए एक सीधी प्रतिस्थापन हो।

3) वहाँ एक पूर्णांक ऐसा है कि संकलक जब अनुकूलन के रैपिंग त्यागने कर सकते हैं लपेटकर का एक ज्ञात तरीका है? लक्ष्य यह है कि WrappedInt नीति-आधारित टेम्पलेट होगा। लेकिन अगर इंट पर अनिवार्य रूप से मनमाना 6x गति दंड में "डू-कुछ नहीं" नीति परिणाम होता है, तो मैं उस परिस्थिति को विशेष रूप से बंद कर रहा हूं और सीधे int का उपयोग कर रहा हूं।

+0

मामले में यह किसी भी भ्रम का कारण बनता - मैं शायद अपने समारोह "सीटी" नाम दिया जाना चाहिए था जब मैं "|| मैं% 5" ;-) –

उत्तर

6

मैं अनुमान लगा रहा हूं कि आप केवल पुराने पुराने जीसीसी संस्करण को चला रहे हैं। मेरे मशीन पर सबसे पुराना कंपाइलर है - जीसीसी-4.1।2, दोनों गैर-कॉन्स और रैप संस्करणों के साथ तेज़ तरीका करता है (और केवल -O1 पर ऐसा करता है)।

+0

यह अच्छी खबर है, धन्यवाद। –

+0

कोई विशेष कारण आपने 4 वर्षों में अपग्रेड नहीं किया है? –

+0

साइगविन 3.4 पर डिफ़ॉल्ट है। मुझे लगता है कि वे अभी भी साइगविन स्वयं या कुछ बनाने के लिए इसका उपयोग कर रहे हैं। इसमें एक जीसीसी -4 पैकेज है, हालांकि, मैं कोशिश करूँगा। 12 महीने के रूप में उतना बुरा नहीं है कि सिगविन के gnupg के संस्करण में एक महत्वपूर्ण सुरक्षा दोष तय अपस्ट्रीम था। –

1

अपने fizzbuzz फ़ंक्शन में const T के साथ अपने WrappedInt क्लास में const int v को संयोजित करने का प्रयास करें और देखें कि संकलक इसे अनुकूलित कर सकता है या नहीं। एक संकलन समय निरंतर -

const int घोषित करने से आप एक विशेष मामला बना लिया है। संकलक जानता है कि मूल्य क्या है, और इसे उस मूल्य से अधिक भारी अनुकूलित कर सकता है जो प्रोग्राम के चलाने के दौरान संभवतः बदल सकता है।

+0

दुर्भाग्य से 'WrappedInt' दो ऑपरेटरों जो संशोधित' v' है हटा दिया। लेकिन एक नई कक्षा शुरू करने के साथ, 'लपेटा गया कॉन्स्टिंट' उनके साथ हटा दिया गया, एक उपयुक्त 'ऑपरेटर%' जोड़कर, और 'div' को 'const' लपेटा गया कॉन्स्टिंट 'बनाना, अनुकूलन को ट्रिगर नहीं करता है। यह धीमा चलता है। –

+0

और मैं समझता हूं कि "कॉन्स इंट" विशेष है। हालांकि, यहां तक ​​कि जब गैर-कॉन्स, संकलक एक रजिस्टर में मूल्य खींच रहा है, और रजिस्टर लूप में कभी संशोधित नहीं होता है। इसलिए मैं उम्मीद कर रहा था कि (ए) कि कुछ डीएफए इसे देखने की अनुमति देंगे कि एक स्थानीय int जिसे कभी संशोधित नहीं किया जाता है और कोई संदर्भ नहीं लिया जाता है, उतना ही अच्छा होता है, और इसे उपचार देता है, और/या (बी) कि एक स्थिर एक int युक्त संरचना एक 'const int' के रूप में बस के रूप में है। –

+0

तो मुझे लगता है कि सवाल बन जाता है, "क्या कोई मजबूत कारण है कि न तो (ए) और न ही (बी) होता है, या यह है कि जीसीसी इसे प्रबंधित नहीं करता है?" –

0

क्या इंटेल को लपेटने का कोई ज्ञात तरीका है कि संकलक अनुकूलन करते समय रैपिंग को त्याग सकते हैं?

मूल्य से WrappedInt पास करने का प्रयास करें। फिर WrappedInt एस रजिस्टरों में पारित किया जा सकता है। पास-बाय-कॉन्स्ट-रेफरेंस कभी-कभी जीसीसी को बहस के लिए स्टैक पर वापस गिरने के लिए मजबूर करता है।

int बनाम const int मंदी के बारे में, मैं केवल अनुमान लगा सकता हूं कि जीसीसी एलियासिंग के चेहरे में इसे सुरक्षित रखने की कोशिश कर रहा है। असल में, यदि यह साबित नहीं कर सकता कि div किसी अन्य, अधिक सुलभ चर के लिए उपनाम नहीं है, तो यह इसे स्थिर में नहीं बदल सकता है। यदि आप इसे स्थिरांक घोषित करते हैं, तो जीसीसी मानता है कि यह उपनाम नहीं है और रूपांतरण को निरंतर निष्पादित करता है। idivl के अलावा, आपको const मामले के लिए तत्काल मानों का उपयोग करने के विपरीत, फ़ंक्शन में प्रवेश करते समय एक मेमोरी फ़ेच भी देखना चाहिए।

+0

दोनों लिपटे और गैर-कॉन्स int मामलों में, div को "movl $ 3,% edi'" के साथ आरंभ किया गया है और कभी भी स्मृति को छूता नहीं है। और मूल्य से गुजरने के लिए WrappedInt (साथ ही साथ कन्स्ट्रक्टर) के सभी ऑपरेटरों को बदलना अनुकूलन को सक्षम नहीं करता है। –

0

गति में अंतर संकलक के कारण होता है यह नहीं जानता कि "div" मूल्य बदल जाएगा या नहीं। जब यह गैर-कॉन्स होता है, तो यह इसे एक चर के रूप में पारित कर रहा है। यह कुछ भी हो सकता है, और इसलिए संकलक एक ऐसे निर्देश का उपयोग करेगा जो दो चर - idivl को विभाजित करता है। जब आप कहते हैं कि यह स्थिरांक है, संकलक यह वास्तव में इलाज के लिए नि: शुल्क है, जैसे कि आपके द्वारा लिखे गए था:

 
if (i % 3 == 0) 

मैं हैरान तरह का है कि यह बिटवाइज़ और (&) का उपयोग नहीं किया है।

WrappedInt को अनुकूलित नहीं किया जा रहा है क्योंकि, यह एक int नहीं है। इसकी एक कक्षा है।

कुछ ऐसा जो आप कर सकते हैं वह है wrappedInt में fizzbuzz शामिल है।

+1

केवल दो की शक्तियों का मॉड्यूल और का उपयोग करके व्यक्त किया जा सकता है। –

संबंधित मुद्दे