क्या अनुकूलन स्तर -O3 जी ++ में खतरनाक है?


232

मैंने विभिन्न स्रोतों (हालांकि ज्यादातर मेरे एक सहयोगी से) से सुना है, कि -O3जी ++ में अनुकूलन स्तर के साथ संकलन करना किसी तरह 'खतरनाक' है, और जब तक आवश्यक नहीं साबित किया जाना चाहिए, तब तक सामान्य रूप से बचा जाना चाहिए।

क्या यह सच है, और यदि हां, तो क्यों? क्या मुझे बस चिपके रहना चाहिए -O2?


38
यदि आप अपरिभाषित व्यवहार पर भरोसा कर रहे हैं तो यह केवल खतरनाक है। और तब भी मुझे आश्चर्य होगा अगर यह अनुकूलन स्तर था जिसने कुछ गड़बड़ कर दी।
सेठ कार्नेगी

5
कंपाइलर अभी भी एक प्रोग्राम का उत्पादन करने के लिए विवश है जो "ऐसा व्यवहार करता है" जैसे कि यह आपके कोड को बिल्कुल संकलित करता है। मुझे नहीं पता कि -O3इसे विशेष रूप से छोटी गाड़ी माना जाता है? मुझे लगता है कि शायद यह अपरिभाषित व्यवहार को "बदतर" बना सकता है क्योंकि यह कुछ मान्यताओं के आधार पर अजीब और अद्भुत चीजें कर सकता है, लेकिन यह आपकी खुद की गलती होगी। तो आम तौर पर, मैं कहूंगा कि यह ठीक है।
BoBTFish

5
यह सच है कि उच्च अनुकूलन स्तर कंपाइलर कीड़े के लिए अधिक प्रवण हैं। मैंने खुद कुछ मामलों को मारा है, लेकिन सामान्य तौर पर वे अभी भी बहुत दुर्लभ हैं।
रहस्यपूर्ण

21
-O2चालू होता है -fstrict-aliasing, और यदि आपका कोड बच जाता है , तो शायद यह अन्य अनुकूलन से बच जाएगा, क्योंकि यह एक ऐसा है जो लोगों को गलत हो जाता है। उस ने कहा, -fpredictive-commoningकेवल में है -O3और सक्षम करने से आपके कोड में बग्स को सक्षम किया जा सकता है, जो कि संगामिति के बारे में गलत धारणाओं के कारण होता है। आपका कोड जितना कम गलत है, उतना कम खतरनाक अनुकूलन है ;-)
स्टीव जेसोप

6
@PlasmaHH, मुझे नहीं लगता कि "ज़ोरदार" का एक अच्छा वर्णन है -Ofast, यह उदाहरण के लिए NaNs के IEEE- अनुरूप हैंडलिंग को बंद कर देता है
जोनाथन

जवाबों:


223

Gcc (2.8 इत्यादि) के शुरुआती दिनों में और egcs के समय में, और 2.96-O3 को कभी-कभी काफी छोटा कर दिया जाता था। लेकिन यह एक दशक पहले खत्म हो चुका है, और -ओ 3 अन्य स्तरों के अनुकूलन (बगियापन) से बहुत अलग नहीं है।

हालांकि यह उन मामलों को प्रकट करने के लिए है जहां लोग नियमों पर और अधिक सख्ती से भरोसा करने के कारण अपरिभाषित व्यवहार पर भरोसा करते हैं, और विशेष रूप से कोने के मामलों में, भाषा का।

एक व्यक्तिगत नोट के रूप में, मैं -O3 के साथ कई वर्षों से वित्तीय क्षेत्र में उत्पादन सॉफ्टवेयर चला रहा हूं और अभी तक एक बग का सामना नहीं किया है जो कि -O2 का उपयोग करने पर नहीं होता।

लोकप्रिय मांग से, यहाँ एक अतिरिक्त:

-O3 और विशेष रूप से अतिरिक्त झंडे जैसे -funroll-loops (-O3 द्वारा सक्षम नहीं) कभी-कभी अधिक मशीन कोड उत्पन्न हो सकता है। कुछ परिस्थितियों में (उदाहरण के लिए, छोटे L1 इंस्ट्रक्शन कैश के साथ सीपीयू पर) यह सभी कोड के कारण मंदी का कारण बन सकता है जैसे कि कुछ आंतरिक लूप अब एल 1 आई में फिटिंग नहीं करते हैं। आमतौर पर जीसीसी इतना कोड न उत्पन्न करने के लिए काफी कोशिश करता है, लेकिन चूंकि यह आमतौर पर सामान्य मामले का अनुकूलन करता है, इसलिए ऐसा हो सकता है। विकल्प विशेष रूप से इसके लिए प्रवण होते हैं (जैसे लूप अनरोलिंग) आम तौर पर -O3 में शामिल नहीं होते हैं और उन्हें मैनपेज के अनुसार चिह्नित किया जाता है। जैसे कि आम तौर पर तेज कोड उत्पन्न करने के लिए -O3 का उपयोग करना एक अच्छा विचार है, और जब उचित हो तो केवल -O2 या -O (जो कोड आकार के लिए ऑप्टिमाइज़ करने की कोशिश करता है) में वापस आते हैं (उदाहरण के लिए जब कोई प्रोफाइलर L1I मिस करता है)।

यदि आप अनुकूलन को चरम में लेना चाहते हैं, तो आप कुछ अनुकूलन के साथ जुड़े लागतों को - सीआरएम के माध्यम से जीसीसी में ट्विक कर सकते हैं। इसके अतिरिक्त ध्यान दें कि gcc में अब इन कार्यों के लिए अनुकूलन सेटिंग्स को नियंत्रित करने वाले कार्यों में विशेषताएँ डालने की क्षमता है, इसलिए जब आप पाते हैं कि आपको एक फ़ंक्शन में -O3 के साथ समस्या है (या बस उस फ़ंक्शन के लिए विशेष झंडे आज़माना चाहते हैं), आपको O2 के साथ संपूर्ण फ़ाइल या संपूर्ण प्रोजेक्ट संकलित करने की आवश्यकता नहीं है।

ऐसा लगता है कि ओट का उपयोग करते समय ध्यान रखा जाना चाहिए, जो बताता है:

-Ofast सभी -O3 अनुकूलन को सक्षम करता है। यह उन अनुकूलन को भी सक्षम करता है जो सभी मानक अनुपालन कार्यक्रमों के लिए मान्य नहीं हैं।

जो मुझे निष्कर्ष निकालता है कि -O3 पूरी तरह से मानकों का अनुपालन करने का इरादा है।


2
मैं बस इसके विपरीत कुछ का उपयोग करता हूं। मैं हमेशा -O2 या -O2 का उपयोग करता हूं (कभी-कभी O2 एक छोटा निष्पादन योग्य बनाता है) .. प्रोफाइलिंग के बाद मैं कोड के कुछ हिस्सों पर O3 का उपयोग करता हूं जो अधिक निष्पादन समय लेता है और अकेले ही 20% तक अधिक गति दे सकता है।
कॉफिडेवलपर्स

3
मैं गति के लिए ऐसा करता हूं। O3 अधिकांश बार चीजों को धीमा कर देता है। पता नहीं क्यों, मुझे संदेह है कि यह निर्देश कैश को प्रदूषित करता है।
कॉफिडेवलपर्स

4
@DarioOO मुझे ऐसा लगता है कि "कोड ब्लोट" की दलील देना एक लोकप्रिय बात है, लेकिन मैं इसे कभी भी बेंचमार्क के साथ नहीं देखता। यह वास्तुकला पर बहुत कुछ निर्भर करता है, लेकिन हर बार जब मैं प्रकाशित बेंचमार्क (जैसे phoronix.com/… ) देखता हूं तो यह O3 के अधिकांश मामलों में तेजी से दिखाई देता है। मैंने देखा है कि कोड ब्लोट वास्तव में एक मुद्दा था, यह साबित करने के लिए प्रोफाइलिंग और सावधान विश्लेषण की आवश्यकता है, और यह आमतौर पर केवल उन लोगों के लिए होता है जो एक चरम तरीके से टेम्पलेट्स को गले लगाते हैं।
Nir Friedman

1
@NirFriedman: जब कंपाइलर की इनलाइन लागत मॉडल में कीड़े हो, या जब आप अपने द्वारा चलाए जा रहे लक्ष्य से बिलकुल अलग लक्ष्य के लिए अनुकूलन करते हैं, तो यह एक समस्या हो जाती है। अंतःक्रियात्मक रूप से यह सभी अनुकूलन स्तरों पर लागू होता है ...
प्लाज्माएचएच

1
@PlasmaHH: सामान्य मामले के लिए उपयोग करना- cmov समस्या को ठीक करना मुश्किल होगा। आमतौर पर आपने केवल अपने डेटा को सॉर्ट नहीं किया है, इसलिए जब gcc यह तय करने की कोशिश कर रहा है कि कोई शाखा प्रेडिक्टेबल है या नहीं, स्टैटिक एनालिसिस के लिए std::sortफंक्शन्स की तलाश में मदद की संभावना नहीं है। कुछ का उपयोग करते हुए की तरह stackoverflow.com/questions/109710/... मदद मिलेगी, या हो सकता है स्रोत लिखने हल कर सत्ता का लाभ लेने के: स्कैन जब तक आप देख> = 128, तो संक्षेप शुरू करते हैं। फूला हुआ कोड के रूप में, हाँ, मैं इसे रिपोर्ट करने के लिए चारों ओर जाने का इरादा रखता हूं। : पी
पीटर कॉर्ड्स

42

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

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


10
"ज्यादातर हमेशा"? इसे "50-50" करें, और हमारे पास एक सौदा होगा ;-)।
नहीं-बग्स हरे

12

-O3 विकल्प अधिक महंगे ऑप्टिमाइज़ेशन को चालू करता है, जैसे कि फ़ंक्शन इनलाइनिंग, निचले स्तरों के सभी ऑप्टिमाइज़ेशन '-O2' और '-O1' के अलावा। '-O3' अनुकूलन स्तर परिणामी निष्पादन की गति को बढ़ा सकता है, लेकिन इसके आकार को भी बढ़ा सकता है। कुछ परिस्थितियों में जहां ये अनुकूलन अनुकूल नहीं हैं, यह विकल्प वास्तव में एक कार्यक्रम को धीमा कर सकता है।


3
मैं समझता हूं कि कुछ "स्पष्ट अनुकूलन" एक कार्यक्रम को धीमा कर सकते हैं, लेकिन क्या आपके पास एक स्रोत है जो दावा करता है कि जीसीसी -ओ 3 ने एक कार्यक्रम धीमा कर दिया है?
मूविंग डक

1
@MooDDuck: जब मैं एक स्रोत का हवाला नहीं दे सकता, तो मुझे याद है कि ऐसे पुराने एएमडी प्रोसेसर के साथ इस तरह का मामला चल रहा था जिसमें काफी छोटा L1I कैश (~ 10k निर्देश) था। मुझे यकीन है कि Google के पास दिलचस्पी के लिए अधिक है, लेकिन विशेष रूप से लूप अनरोलिंग जैसे विकल्प ओ 3 का हिस्सा नहीं हैं, और वे आकार बहुत बढ़ाते हैं। -ओ वह है जब आप निष्पादन योग्य को सबसे छोटा बनाना चाहते हैं। भी -O2 कोड आकार बढ़ा सकते हैं। विभिन्न अनुकूलन स्तरों के परिणाम के साथ खेलने के लिए एक अच्छा उपकरण gcc एक्सप्लोरर है।
प्लाज़्मा एचएच

@PlasmaHH: वास्तव में, एक छोटे कैश आकार कुछ एक संकलक पेंच कर सकता है, अच्छी बात है। यह वास्तव में अच्छा उदाहरण है। कृपया इसे उत्तर में रखें।
मिंग डक

1
@PlasmaHH पेंटियम III में 16KB कोड कैश था। एएमडी के K6 और इसके बाद के संस्करण में वास्तव में 32KB निर्देश कैश था। P4 की शुरुआत लगभग 96KB मूल्य के साथ हुई। कोर I7 में वास्तव में 32KB L1 कोड कैश है। निर्देश डिकोडर आजकल मजबूत हैं, इसलिए आपका एल 3 लगभग किसी भी लूप के लिए वापस गिरने के लिए पर्याप्त है।
doug65536

1
आप किसी भी समय एक लूप में एक फ़ंक्शन कहा जाता है, जब आप एक बहुत बड़ा प्रदर्शन बढ़ाते हैं, तो यह लूप से पहले फ़ंक्शन के बाहर महत्वपूर्ण सामान्य सबप्रेसेशन उन्मूलन और अनावश्यक पुनर्गणना का उत्थान कर सकता है।
doug65536

8

हाँ, O3 बगियर है। मैं एक कंपाइलर डेवलपर हूं और मैंने अपने स्वयं के सॉफ़्टवेयर का निर्माण करते समय ओ 3 जी बग्गी सिमडी विधानसभा निर्देशों के कारण स्पष्ट और स्पष्ट जीसीसी बग की पहचान की है। मैंने जो देखा है, ओ 2 के साथ सबसे अधिक उत्पादन सॉफ्टवेयर जहाज हैं जिसका अर्थ है ओ 3 को कम ध्यान देना चाहिए।

इसे इस तरह से सोचें: O3 O2 के शीर्ष पर अधिक परिवर्तन जोड़ता है, जो O1 के शीर्ष पर अधिक परिवर्तन जोड़ता है। सांख्यिकीय रूप से बोलना, अधिक परिवर्तनों का अर्थ है अधिक बग। यह किसी भी संकलक के लिए सच है।


3

हाल ही में मैंने अनुकूलन के साथ एक समस्या का अनुभव किया g++। समस्या पीसीआई कार्ड से संबंधित थी, जहां रजिस्टरों (कमांड और डेटा के लिए) एक मेमोरी एड्रेस द्वारा रिप्रेजेंट किए गए थे। मेरे ड्राइवर ने एप्लिकेशन के भीतर एक पॉइंटर को भौतिक पते को मैप किया और इसे तथाकथित प्रक्रिया को दिया, जिसने इस तरह से काम किया:

unsigned int * pciMemory;
askDriverForMapping( & pciMemory );
...
pciMemory[ 0 ] = someCommandIdx;
pciMemory[ 0 ] = someCommandLength;
for ( int i = 0; i < sizeof( someCommand ); i++ )
    pciMemory[ 0 ] = someCommand[ i ];

कार्ड अपेक्षित रूप से कार्य नहीं करता था। जब मैंने विधानसभा को देखा तो मैं समझ गया कि संकलक ने ही लिखा someCommand[ the last ]है pciMemory, पूर्ववर्ती सभी लेखन को छोड़ दिया है।

निष्कर्ष में: अनुकूलन के साथ सटीक और चौकस रहें।


38
लेकिन यहाँ मुद्दा यह है कि आपके कार्यक्रम में बस अपरिभाषित व्यवहार है; आशावादी ने कुछ भी गलत नहीं किया। विशेष रूप से आपको घोषित करने की आवश्यकता हैpciMemory के रूप में volatile
कोनराड रुडोल्फ

11
यह वास्तव में यूबी नहीं है, लेकिन संकलक सभी को छोड़ देने के अपने अधिकार के भीतर है, लेकिन अंतिम लिखते हैं pciMemoryक्योंकि अन्य सभी लिखों का कोई प्रभाव नहीं है। आशावादी के लिए यह भयानक है क्योंकि यह कई बेकार और समय लेने वाले निर्देशों को हटा सकता है।
कोनराड रुडोल्फ

4
मुझे यह मानक (10+ वर्षों के बाद) में मिला) - एक मेमोरी-मैप्ड इनपुट / आउटपुट पोर्ट के अनुरूप एक वस्तु का वर्णन करने के लिए एक वाष्पशील घोषणा का उपयोग किया जा सकता है या एक अतुल्यकालिक रूप से बाधित फ़ंक्शन द्वारा एक्सेस की गई वस्तु। घोषित की गई वस्तुओं पर कार्रवाई एक 'कार्यान्वयन के द्वारा' अनुकूलित 'नहीं होगी या अभिव्यक्ति के मूल्यांकन के लिए नियमों द्वारा अनुमत को छोड़कर पुन: व्यवस्थित की जाएगी।
बोरिसबीन

2
@borisbn कुछ ऑफ-टॉपिक है लेकिन आप कैसे जानते हैं कि आपके डिवाइस ने नया कमांड भेजने से पहले कमांड ले ली है?
user877329

3
@ user877329 मैंने इसे डिवाइस के बिहेवियर द्वारा देखा, लेकिन यह एक शानदार खोज थी
बोरिसबैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.