2010-01-25 6 views
9

उदाहरण:कैसे जीसीसी संकलक सुझाव देने के लिए और अधिक संभावित शाखा

if (almost_always_false_condition) { 
     // do something 
} 

वहाँ संकलक कि 99% हालत में झूठी हो जाएगा सुझाव देने के लिए एक रास्ता है। हालत की गणना ~ 60 चक्रों की जांच की जाती है, और इसकी गणना संकलन समय पर संकलित समय पर नहीं की जा सकती है।

(जीसीसी 4.3)

+0

संबंधित: http://stackoverflow.com/questions/1668013/can-likely-unlikely-macros-be-used-in-user-space-code –

उत्तर

10

आप जीसीसी के लिए जो बताते हैं कि एक शर्त कोड प्रवाह की व्यवस्था के लिए एक संकेत के रूप में दिए गए मूल्य की संभावना है चाहते हैं, आप का उपयोग करना चाहिए __builtin_expect():

if (__builtin_expect(almost_always_false_condition,0)) { 
    // do something 
} 

हालांकि , ऐसा लगता है कि आप इस स्थिति का मूल्यांकन करने से बचने के लिए एक रास्ता खोजना चाहते हैं, जो __builtin_expect() नहीं करेगा।

if (__builtin_expect(fastCheckThatIsTrueIfFullConditionIsTrue,0)) { 
    // most of the time, we don't even get to here, so you don't need 
    // to evaluate the condition 
    if (almostAlwaysFalseCondition) { 
     // do something 
    } 
} 

आप हमें क्या हालत है के बारे में और अधिक बता सकते: वहाँ एक तरीका है कि आप जल्दी से हालत का अनुमान लगा सकता है, और केवल पूर्ण जांच कर जब सन्निकटन सच है है?

+0

इस संकेत और उदाहरण के लिए धन्यवाद। स्थिति लॉगिंग के लिए उपयोग की जाती है, जिसे आवश्यक होने पर स्विच किया जा सकता है। मूल्य संकलन समय पर नहीं जाना जाता है (हम दो बंद पर प्रवेश के साथ बाइनरी के संस्करणों और नहीं हो सकता है), "तेजी से जांच" पहले से ही किया जाता है जहां यह संभव है। – Karol

+0

__builltin_expect कोडफ्लो को और अधिक कुशल बनाने के लिए कैसे बदलता है? क्या ऐसे कंपाइलर्स के लिए ऐसा करने का कोई पोर्टेबल तरीका है जिसमें समकक्ष एक्सटेंशन नहीं है? – greatwolf

+0

@ विक्टर टी .: नहीं, ऐसा करने के लिए कोई पोर्टेबल तरीका नहीं है। –

0

दस्तावेज़ीकरण से पता चलता है कि जीसीसी प्रोफ़ाइल संचालित संचालित अनुकूलन करता है (या कर सकता है)। यह ऐसा कुछ नहीं है जिसे मैंने कभी भी जीसीसी के साथ करने की कोशिश की है, इसलिए कोई और सलाह नहीं दे सकती है, Google को मारने के दौरान यह आपके लायक हो सकता है।

3

यदि परिणाम एक ही रन के दौरान भिन्न हो सकता है, तो आप अपनी स्थिति को सस्ते हिस्से और एक महंगी हिस्से में विभाजित करने के लिए बूलियन ऑपरेटर के आलसी मूल्यांकन का उपयोग करने में सक्षम हो सकते हैं, और पहले सस्ते भाग को चला सकते हैं।

if (a == 5 && somethingexpensive()) 
{ 
    ... 
} 

की गणना a == 5 के बाद से somethingexpensive() की तुलना में सस्ता है, और यह लगभग हमेशा है अगर false आप इसे पहले चलाना चाहिए, जो somethingexpensive खंड का मूल्यांकन टाल।

यदि दूसरी ओर परिणाम प्रोग्राम के एक रन के लिए निरंतर है, तो आप इसे स्थिर या वैश्विक चर में गणना के परिणाम को संग्रहीत करके अनुकूलित कर सकते हैं।

static int result = doevalfunctiononlyonce(); 

if (result) 
{ 
    ....  
} 

इस तरह आप एक सरल स्मृति देखने के लिए if की लागत को कम कर दिया।

हालत केवल एक और प्रक्रिया में एक कार्रवाई के जवाब में बदल जाता है, तो आप उस प्रक्रिया से वैश्विक अद्यतन कर सकते हैं:

int condition; 

void appendToList(int a) 
{ 
    list.append(a); 
    if (list.somethingexpensive()) 
    { 
    condition = true; 
    } else 
    { 
    condition = false; 
    } 
} 

void someotherfunction() 
{ 
    // if (list.somethingexpensive()) 
    if (condition) 
    { 
    ... 
    } 
} 

यह उपयोगी है अगर someotherfunction अधिक बार appendtolist समारोह से बहुत सारे कहा जाता है।

2

सबसे पहले, else खंड, या प्रोग्राम में कहीं और कितने चक्र खर्च किए जाते हैं? यदि आप प्रोफाइल करते हैं या stackshots लेते हैं, तो क्या आप उस परीक्षा में कम से कम 10% समय व्यतीत कर रहे हैं? यदि नहीं, तो शायद बड़ी समस्याएं हैं जिन्हें आपको पहले देखना चाहिए।

दूसरा, यदि आप उस परीक्षण में 10% समय व्यतीत कर रहे हैं, तो आपको यह देखना चाहिए कि एल्गोरिदम को 50-50 संभाव्यता के करीब निर्णय बिंदुओं के लिए समायोजित किया जा सकता है या नहीं। एक 50-50 निर्णय बिंदु इसे निष्पादित होने पर 1 बिट जानकारी प्राप्त करता है, जबकि 99-1 निर्णय बिंदु केवल .07 बिट्स के बारे में उत्पन्न होता है। * (यानी यह आपको बहुत कुछ नहीं बताता है, इसलिए यह CPU चक्रों का अक्षम उपयोग है।) इस घटना का एक उदाहरण यह है कि यदि आप द्विआधारी खोज के साथ रैखिक खोज की तुलना करते हैं।

* यदि आपके पास बाइनरी निर्णय बिंदु है और परिणामों की संभावनाएं a और b हैं, बिट्स में सूचना उपज (एंट्रॉपी) -(a*log(a) + b*log(b))/log(2) है।

0

मेरी राय में, इस तरह के अनुकूलन करने का सबसे अच्छा तरीका -fprofile-generate और -fprofile-use विकल्पों का उपयोग करना है। इसके लिए प्रतिनिधि उपयोग मामलों का आधार आवश्यक है कि क्या संभव है और क्या नहीं है, लेकिन इस उद्देश्य के लिए परीक्षणों का उपयोग किया जा सकता है। दूसरी तरफ, कोड बदसूरत, गैर पोर्टेबल निर्देशों से सजाया नहीं गया है।

इन दो विकल्पों के बारे में अधिक जानकारी के लिए https://gcc.gnu.org/onlinedocs/gcc-4.3.6/gcc/Optimize-Options.html#Optimize-Options देखें।

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