2010-06-16 14 views
7

कोड जो मैंने देखा है (दिखाए गए सभी उपयोगों का उपयोग):क्या कंपाइलर आंतरिक लूप से बचने का अनुकूलन करेगा?

bool done = false; 
for(int i = 0; i < big; i++) 
{ 
    ... 
    for(int j = 0; j < wow; j++) 
    { 
    ... 
    if(foo(i,j)) 
    { 
     done = true; 
     break; 
    } 
    ... 
    } 
    if(done) break; 
    ... 
} 

कोई भी कंपाइलर्स इसे इस रूप में परिवर्तित करेगा:

for(int i = 0; i < big; i++) 
{ 
    ... 
    for(int j = 0; j < wow; j++) 
    { 
    ... 
    if(foo(i,j)) 
     goto __done; // same as a labeled break if we had it 
    ... 
    } 
    ... 
} 
__done:; 

नोट: जबकि मुझे अधिकतर दिलचस्पी है if(done)break; मृत कोड के रूप में बाईपास और हटा दिया जाता है, मुझे यह भी रूचि है कि यह और done पूरी तरह से हटा दिया जाता है।

+3

वैसे, आपको किसी भी प्रतीक को परिभाषित नहीं करना चाहिए जो दो अंडरस्कोर से शुरू होता है; ऐसे प्रतीक आरक्षित हैं। –

+8

प्रतीक ऑप्टिमाइज़ेशन पास का परिणाम होगा, e.i. संकलक द्वारा उत्पन्न किया गया। मैंने उस नाम का उपयोग किया * क्योंकि * यह एक आरक्षित/आंतरिक नाम इंगित करता है। – BCS

+0

और सवाल: यह एक समारोह में क्यों नहीं फंस गया है?आप तब 'वापसी' का उपयोग कर सकते हैं;) –

उत्तर

14

जाहिर है यह संकलक पर निर्भर करता है। जब आप अनिश्चित हैं तो करने के लिए सबसे अच्छी बात यह है कि कंपाइलर के असेंबली आउटपुट को देखने के लिए (सभी लोकप्रिय कंपाइलर्स के लिए एक स्विच है)। यहां तक ​​कि यदि आप असेंबली से परिचित नहीं हैं, तो आप कम से कम अनुकूलित संस्करण के साथ डीबग संस्करण की तुलना कर सकते हैं।

कहा जा रहा है कि, यह कुछ स्थितियों में से एक है जहां goto कोई बुरा विचार नहीं है। आंतरिक लूप से बाहर निकलने के लिए इसका इस्तेमाल करने के लिए स्वतंत्र महसूस करें।

संपादित

बस VS2010 में निम्नलिखित की कोशिश की और यह वास्तव में बाहरी सशर्त का अनुकूलन करता है:

bool done = false; 
for(int i = 0; i < 10; i++) 
{ 
    for(int j = 0; j < 10; j++) 
    { 
     if(i == 7 && j == 3) 
     { 
      done = true; 
      break; 
     } 
    } 
    if(done) break; 
} 
return 0; 
+16

+1 पढ़ने के लिए दिलचस्प रहा है। बहुत से लोगों ने इस तथ्य को खो दिया है कि गेटोस, ब्रेक, फ़ंक्शंस से कई रिटर्न पॉइंट, और ऐसी अन्य चीजें, कोड को समझने में कठोर होने पर खराब होती हैं ._ ऐसी चीजों का न्यायसंगत उपयोग ठीक है। – paxdiablo

+1

यह सुनिश्चित करने के लिए बोल्ड किया गया कि कोई भी इसे याद नहीं करता :) – Cogwheel

+0

याहू, एक गोटो वहां वैध है। ओटीओएच एक लेबल ब्रेक भी बेहतर होता है और यदि यह मुझे कोड समीक्षा में बचाव करने से बचाता है, तो मैं कंपाइलर के साथ कुछ जादू कर रहा हूं। – BCS

7

जीएनयू संकलक सिर्फ इतना है कि, जीसीसी अनुकूलन स्तर -O1 के साथ शुरू (मैं उपयोग कर रहा हूँ करता है x86_64 पर 4.5.1)

call _Z3fooii // al = foo(i,j) 
testb %al, %al 
jne .L14 
... 

जहां .L14 लेबल वास्तव में रखा जहां __done रखा है:

एक बेहतर सवाल यह हो सकता है: कौन सा आधुनिक कंपाइलर इस अनुकूलन को निष्पादित नहीं करता है?

+1

एसएनसी - कम से कम, हमारे पास संस्करण नहीं है। – Crashworks

1

मैं साथ जीसीसी 4.2.1 की कोशिश की है निम्नलिखित:

// Prevent optimizing out calls to foo and loop unrolling: 
extern int big, wow; 
bool foo(int,int); 

void 
bar() 
{ 
    int done = false; 
    for(int i = 0; i < big; i++) 
    { 
     for(int j = 0; j < wow; j++) 
     { 
      if(foo(i,j)) 
      { 
       done = true; 
       break; 
      } 
     } 
     if(done) 
      break; 
    } 
} 

... और यह -O3 साथ postamble के लिए सीधे के माध्यम से गिर जाता है:

33: e8 fc ff ff ff   call 34 <bar()+0x34> ; call to foo* 
    38: 84 c0     test %al,%al 
    3a: 74 e5     je  21 <bar()+0x21> ; next loop iteration 
    3c: 83 c4 10    add $0x10,%esp 
    3f: 5b      pop %ebx 
    40: 5e      pop %esi 
    41: 5d      pop %ebp 
    42: c3      ret 

*** यह एक से है अनलिंक ऑब्जेक्ट फ़ाइल, call 34 वास्तव में foo पर कॉल है।

+1

तो '3 ए' शाखाओं को सीधे '42' पर अंतिम अंत तक? – BCS

+0

@ एलबीएस, 0x3a शाखाएं लूप की शुरुआत में यदि एलएल शून्य है (foo झूठी लौटाई गई है), अन्यथा यह अभी भी पोस्टमबल (पॉप सहेजे गए रजिस्टर्स, पिछले स्टैक फ्रेम को पुनर्स्थापित करता है) 3 सी, 3 एफ, .. –

4

मैं snarky होने की कोशिश नहीं कर रहा हूँ, लेकिन ... क्या इससे कोई फर्क पड़ता है? आम तौर पर, मुझे लगता है कि कंपेलरों को उनके काम में जाने देना सबसे अच्छा है, और यह काम "सर्वश्रेष्ठ" (नोट करें कि आपकी आवश्यकताओं के आधार पर "सर्वोत्तम" भिन्न हो सकता है) आपके स्रोत कोड दिए गए संकलित कोड। आपके कोड में किसी भी प्रदर्शन विचारों को एक प्रोफाइलर और एल्गोरिदमिक जटिलता के अच्छे कामकाजी ज्ञान के साथ पहचाना जाना चाहिए।

यदि आप केवल उत्सुक हैं, तो इस टिप्पणी को अनदेखा करें। लेकिन अगर आपका इरादा किसी भी तरह से आपके कोड को अनुकूलित करना है, तो मुझे लगता है कि बहुत अच्छे रास्ते हैं।

+1

तक बहुत सारे कंपाइलर्स उस काम को बहुत अच्छी तरह से नहीं करते हैं - कम से कम, साथ ही साथ हम मानते हैं कि वे करते हैं। – Crashworks

+0

@ क्रैशवर्क्स, किसी विशेष कंपाइलर को माइक्रो-ऑप्टिमाइज़ करने में समस्या यह है कि यह कंपाइलर-विशिष्ट है। यदि आप सक्रिय रूप से इसे कुछ नए अनुकूलन करने से रोकते हैं तो आपका कोड महत्वपूर्ण कंपाइलर के बाद के संस्करणों को वापस ले सकता है। ऑप्टिमाइज़ करना बेहतर है जहां आप जानते हैं कि कंपाइलर भाषा की बाधाओं (अत्यधिक ऑब्जेक्ट कॉपीिंग, एलियासिंग इत्यादि) के कारण ऑप्टिमाइज़ नहीं कर सकता है। उस स्पर्शरेखा पर, यह जानना मुश्किल है कि कौन से अनुकूलन नहीं किए गए हैं क्योंकि संकलक की कमी है, और कौन सा, क्योंकि भाषा की कल्पना इसकी अनुमति नहीं देती है। –

+2

मैं कुछ हद तक सहमत हूं, क्रैश, लेकिन मुझे अभी भी लगता है कि मूल रूप से महत्वपूर्ण क्या है एल्गोरिदमिक जटिलता को समझना। दुनिया में सबसे अच्छा कंपाइलर कुछ कमजोर रैखिक खोज, या खराब स्ट्रिंग कॉन्सटेनेशन कोड को ठीक नहीं कर सकता है। मुझे ब्लैक बॉक्स के रूप में कंपाइलर्स के बारे में सोचने के लिए और अधिक उत्पादक लगता है क्योंकि यह हमें उन चीजों के लिए जवाबदेही लेने के लिए मजबूर करता है जिन पर हमारा अधिक नियंत्रण होता है: हमारा अपना कोड। – kidjan

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