2008-09-16 10 views
12

अधिकांश सी या सी ++ वातावरण में, एक "डीबग" मोड और "रिलीज" मोड संकलन होता है।
दोनों के बीच अंतर को देखते हुए, आप पाते हैं कि डीबग मोड डीबग प्रतीक जोड़ता है (प्रायः बहुत सारे कंपाइलर्स पर -g विकल्प) लेकिन यह अधिक अनुकूलन को भी अक्षम करता है।
"रिलीज" मोड में, आपके पास आमतौर पर सभी प्रकार के अनुकूलन चालू होते हैं।
अंतर क्यों?डी/सी ++ प्रोग्राम में डीबग मोड में ऑप्टिमाइज़ेशन क्यों बंद हो जाता है?

उत्तर

26

किसी भी अनुकूलन के बिना, आपके कोड के माध्यम से प्रवाह रैखिक है। यदि आप लाइन 5 और सिंगल चरण पर हैं, तो आप 6 लाइन पर कदम उठाते हैं। ऑप्टिमाइज़ेशन के साथ, आप निर्देश पुन: ऑर्डरिंग, लूप अनोलिंग और ऑप्टिमाइज़ेशन के सभी प्रकार प्राप्त कर सकते हैं।
उदाहरण के लिए:


void foo() { 
1: int i; 
2: for(i = 0; i < 2;) 
3: i++; 
4: return; 

इस उदाहरण में, अनुकूलन के बिना, आप कर सकते थे कोड के माध्यम से ही चरण और लाइनों 1, 2, 3, 2, 3, 2, 4

पर अनुकूलन के साथ

मारा, आपको एक निष्पादन पथ मिल सकता है जो दिखता है: 2, 3, 3, 4 या यहां तक ​​कि केवल 4! (समारोह सभी के बाद कुछ भी नहीं करता है ...)

नीचे पंक्ति, ऑप्टिमाइज़ेशन सक्षम के साथ डीबगिंग कोड शाही दर्द हो सकता है! विशेष रूप से यदि आपके पास बड़े कार्य हैं।

ध्यान दें कि अनुकूलन चालू करने से कोड बदल जाता है! कुछ पर्यावरण (सुरक्षा महत्वपूर्ण प्रणालियों) में, यह अस्वीकार्य है और कोड को डीबग किया जा रहा कोड होना चाहिए। उस मामले में अनुकूलन के साथ डीबग करना होगा।

जबकि अनुकूलित और गैर-अनुकूलित कोड कुछ परिस्थितियों में "कार्यात्मक रूप से" समकक्ष होना चाहिए, व्यवहार बदल जाएगा।
यहाँ एक साधारण उदाहरण है:

 
    int* ptr = 0xdeadbeef; // some address to memory-mapped I/O device 
    *ptr = 0; // setup hardware device 
    while(*ptr == 1) { // loop until hardware device is done 
     // do something 
    } 

अनुकूलन बंद के साथ

, इस आसान है, और तुम थोड़े क्या उम्मीद करना जानते हैं। हालांकि, अगर आप पर अनुकूलन कर देते हैं, चीजों की एक जोड़ी हो सकता है:

  • संकलक दूर है, जबकि ब्लॉक का अनुकूलन कर सकते हैं
  • के बजाय तक पहुँचने स्मृति (हम 0 करने के लिए init, यह 1 कभी नहीं हो जाएगा) , सूचक का उपयोग एक register-> नहीं आई/ओ अपडेट
  • स्मृति पहुँच कैश हो सकता है (जरूरी संकलक अनुकूलन संबंधित नहीं) इन सभी मामलों में

में ले जाया जा सकता है, व्यवहार काफी अलग और सबसे होगा शायद गलत

+1

'अस्थिर int * ptr' के बारे में कैसे? IIUC यह अंक 2 और 3 हल करेगा, है ना? हालांकि मुझे 'while' के बारे में निश्चित नहीं है। –

4

डीबग और रिलीज के बीच एक और महत्वपूर्ण अंतर यह है कि स्थानीय चर कैसे संग्रहीत किए जाते हैं। संकल्पनात्मक रूप से स्थानीय चर को फ़ंक्शन स्टैक फ्रेम में स्टोरेज आवंटित किया जाता है। कंपाइलर द्वारा उत्पन्न प्रतीक फ़ाइल स्टैक फ्रेम में चर के ऑफसेट को डीबगर बताती है, इसलिए डीबगर इसे आपको दिखा सकता है। ऐसा करने के लिए स्मृति स्थान पर डीबगर peeks।

हालांकि, इसका मतलब यह है कि हर बार एक स्थानीय चर बदल जाता है, उस स्रोत रेखा के लिए जेनरेट कोड को मूल्य को वापस स्टैक पर सही स्थान पर लिखना होता है। मेमोरी ओवरहेड के कारण यह बहुत अक्षम है।

एक रिलीज में कंपाइलर एक स्थानीय चर को फ़ंक्शन के एक हिस्से के लिए एक रजिस्टर में असाइन कर सकता है।कुछ मामलों में यह इसके लिए स्टैक स्टोरेज असाइन नहीं कर सकता है (जितना अधिक रजिस्टर्स मशीन को करना आसान होता है)।

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

एक और अनुकूलन इनलाइनिंग कार्य करेगा। ऑप्टिमाइज्ड बिल्ड में संकलक foo() को foo() के लिए वास्तविक कोड के साथ कॉल को प्रतिस्थापित कर सकता है, इसका उपयोग इसलिए किया जाता है क्योंकि फ़ंक्शन पर्याप्त छोटा होता है। हालांकि, जब आप foo() पर ब्रेकपॉइंट सेट करने का प्रयास करते हैं तो डीबगर foo() के निर्देशों का पता जानना चाहता है, और अब इसका कोई आसान जवाब नहीं है - foo की हजारों प्रतियां हो सकती हैं () कोड बाइट्स आपके कार्यक्रम पर फैल गया। एक डीबग बिल्ड गारंटी देगा कि ब्रेकपॉइंट डालने के लिए कहीं कहीं है।

2

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

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

1

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

माइक्रोसॉफ्ट में विंडोज डिवीजन में, सभी रिलीज बाइनरी डिबगिंग प्रतीकों और पूर्ण अनुकूलन के साथ बनाई गई हैं। प्रतीकों को अलग पीडीबी फाइलों में संग्रहित किया जाता है और कोड के प्रदर्शन को प्रभावित नहीं करते हैं। वे उत्पाद के साथ जहाज नहीं भेजते हैं, लेकिन उनमें से अधिकतर Microsoft Symbol Server पर उपलब्ध हैं।

3

अनुकूलन कोड एक स्वचालित प्रक्रिया है जो सेमेन्टिक्स को संरक्षित करते समय कोड के रनटाइम प्रदर्शन को बेहतर बनाता है। यह प्रक्रिया इंटरमीडिएट परिणामों को हटा सकती है जो अभिव्यक्ति या फ़ंक्शन मूल्यांकन को पूरा करने के लिए अनावश्यक हैं, लेकिन डिबगिंग के दौरान आपके लिए रुचि हो सकती है। इसी तरह, अनुकूलन स्पष्ट नियंत्रण प्रवाह को बदल सकते हैं ताकि स्रोत कोड में दिखाई देने वाली चीज़ों की तुलना में कुछ अलग क्रम में हो। यह अनावश्यक या अनावश्यक गणना को छोड़ने के लिए किया जाता है। कोड कोड का पुन: उपयोग करना स्रोत कोड लाइन संख्याओं और ऑब्जेक्ट कोड पतों के बीच मैपिंग के साथ गड़बड़ कर सकता है क्योंकि इसे लिखने के बाद नियंत्रण के प्रवाह का पालन करने के लिए इसे डीबगर के लिए कठिन बना दिया जाता है।

unoptimized मोड में डिबगिंग आपको जो कुछ लिखा है उसे देखने की अनुमति देता है जैसा कि आपने इसे ऑप्टिमाइज़र को हटाए या फिर से व्यवस्थित किए बिना लिखा है।

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

1

ऑप्टिमाइज़ेशन के साथ अन्य मुद्दों में इनलाइन फ़ंक्शंस हैं, इस अर्थ में कि आप हमेशा उनके माध्यम से एकल-चरण करेंगे।

जीसीसी के साथ, डीबगिंग और ऑप्टिमाइज़ेशन एक साथ सक्षम होने के साथ, यदि आपको नहीं पता कि आपको क्या उम्मीद करनी है तो आपको लगता है कि कोड गलत व्यवहार कर रहा है और एक ही कथन को कई बार फिर से निष्पादित कर रहा है - यह मेरे कुछ सहयोगियों के साथ हुआ। जीसीसी द्वारा ऑप्टिमाइज़ेशन के साथ दी गई जानकारी को डीबग करने की जानकारी भी वास्तव में खराब गुणवत्ता की तुलना में हो सकती है।

हालांकि, जावा की तरह एक आभासी मशीन द्वारा की मेजबानी की भाषाओं में, अनुकूलन और डिबगिंग रह सकते हैं - यहां तक ​​कि डीबगिंग के दौरान, मूल कोड को JIT संकलन जारी है, और केवल डिबग तरीकों में से कोड स्पष्ट रूप से एक unoptimized संस्करण में बदल जाती है।

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

डिबगिंग प्रतीकों के साथ कोड बड़ा है जिसका अर्थ है कि अधिक कैश मिस, यानी धीमी, जो सर्वर सॉफ़्टवेयर के लिए कोई समस्या हो सकती है।

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

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