इनलाइन विस्तार

From Vigyanwiki

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

इनलाइनिंग एक महत्वपूर्ण अनुकूलन है, लेकिन इसका प्रदर्शन पर जटिल प्रभाव पड़ता है।[1] अंगूठे के एक नियम के रूप में, कुछ इनलाइनिंग अंतरिक्ष की बहुत कम लागत पर गति में सुधार करेगी, लेकिन इनलाइनिंग की अधिकता गति को नुकसान पहुंचाएगी, क्योंकि इनलाइन कोड बहुत अधिक निर्देश कैश का उपभोग करता है, और महत्वपूर्ण स्थान भी खर्च करता है। 1980 और 1990 के दशक से इनलाइनिंग पर मामूली अकादमिक साहित्य का एक सर्वेक्षण पीटन जोन्स एंड मार्लो 1999 में दिया गया है।[2]


समीक्षा

इनलाइन विस्तार मैक्रो विस्तार के समान है क्योंकि संकलक प्रत्येक स्थान पर फ़ंक्शन की एक नई प्रति रखता है जिसे इसे कहा जाता है। इनलाइन फ़ंक्शंस सामान्य फ़ंक्शंस की तुलना में कुछ तेज़ी से चलते हैं क्योंकि फ़ंक्शन-कॉलिंग-ओवरहेड सुरक्षित रखे जाते हैं, हालाँकि, मेमोरी पेनल्टी होती है। यदि किसी फ़ंक्शन को 10 बार इनलाइन किया जाता है, तो कोड में डाले गए फ़ंक्शन की 10 प्रतियां होंगी। इसलिए छोटे कार्यों के लिए इनलाइनिंग सबसे अच्छा है जिन्हें प्रायः इनलाइन कहा जाता है। C++ में वर्ग के सदस्य कार्य, यदि वर्ग परिभाषा के भीतर परिभाषित किए गए हैं, तो डिफ़ॉल्ट रूप से इनलाइन होते हैं (इनलाइन कीवर्ड का उपयोग करने की कोई आवश्यकता नहीं है); अन्यथा, कीवर्ड की आवश्यकता है। संकलक किसी फ़ंक्शन को इनलाइन करने के प्रोग्रामर के प्रयास को अनदेखा कर सकता है, मुख्यतः यदि यह विशेष रूप से बड़ा है।

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

इनलाइन फ़ंक्शंस के बिना, कंपाइलर यह तय करता है कि कौन से फ़ंक्शंस इनलाइन करें। प्रोग्रामर का बहुत कम या कोई नियंत्रण नहीं होता है कि कौन से कार्य इनलाइन हैं और कौन से नहीं हैं। प्रोग्रामर को इस डिग्री का नियंत्रण देने से इनलाइन कार्यों को चुनने में एप्लिकेशन-विशिष्ट ज्ञान के उपयोग की अनुमति मिलती है।

सामान्यतः, जब किसी फ़ंक्शन का आह्वान किया जाता है, तो नियंत्रण प्रवाह को इसकी परिभाषा में एक शाखा (कंप्यूटर विज्ञान) या कॉल निर्देश द्वारा स्थानांतरित किया जाता है। इनलाइनिंग के साथ, शाखा या कॉल निर्देश के बिना, फ़ंक्शन के लिए सीधे कोड के माध्यम से नियंत्रण गिरता है।

कंपाइलर सामान्यतः इनलाइनिंग के साथ स्टेटमेंट (कंप्यूटर साइंस) को लागू करते हैं। लूप की स्थिति और लूप बॉडी को आलसी मूल्यांकन की आवश्यकता होती है। यह विशेषता तब पूरी होती है जब लूप की स्थिति और लूप बॉडी की गणना करने वाला कोड इनलाइन होता है। प्रदर्शन के विचार इनलाइन बयानों का एक और कारण हैं।

कार्यात्मक प्रोग्रामिंग भाषाओं के संदर्भ में, इनलाइन विस्तार सामान्यतः लैम्ब्डा कैलकुल |बीटा-कमी परिवर्तन के बाद होता है।

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

प्रदर्शन पर प्रभाव

इस अनुकूलन का सीधा प्रभाव समय के प्रदर्शन में सुधार करना है (कॉल ओवरहेड को समाप्त करके), अनियंत्रित जगह के उपयोग की कीमत पर[lower-alpha 1] (कोड दोहराव के कारण फ़ंक्शन बॉडी) साधारण प्रकरणों को छोड़कर, फ़ंक्शन बॉडी को डुप्लिकेट करने के कारण कोड विस्तार हावी है,[lower-alpha 2] और इस प्रकार इनलाइन विस्तार का सीधा प्रभाव स्थान की कीमत पर समय में सुधार करना है।

हालांकि, इनलाइन विस्तार का प्राथमिक लाभ फ़ंक्शन बॉडी के आकार में वृद्धि के कारण आगे के अनुकूलन और बेहतर शेड्यूलिंग की अनुमति देना है, क्योंकि बड़े कार्यों पर बेहतर अनुकूलन संभव है।[3] मेमोरी सिस्टम (मुख्य रूप से निर्देश कैश) के प्रदर्शन पर कई प्रभावों के कारण गति पर इनलाइन विस्तार का अंतिम प्रभाव जटिल है, जो आधुनिक प्रोसेसर पर प्रदर्शन पर हावी है: विशिष्ट प्रोग्राम और कैश के आधार पर, विशेष कार्यों को इनलाइन करना प्रदर्शन को बढ़ा या घटा सकता है। .[1] इनलाइनिंग का प्रभाव प्रोग्रामिंग लैंग्वेज और प्रोग्राम के अनुसार अलग-अलग डिग्री के एब्सट्रैक्शन के कारण भिन्न होता है। C और फोरट्रान जैसी निचले स्तर की अनिवार्य भाषाओं में यह सामान्यतः कोड आकार पर मामूली प्रभाव के साथ 10-20% की गति को बढ़ावा देता है, जबकि अधिक सार भाषाओं में यह काफी अधिक महत्वपूर्ण हो सकता है, परतों की संख्या को हटाने के कारण, स्व (प्रोग्रामिंग लैंग्वेज) होने के चरम उदाहरण के साथ, जहां एक कंपाइलर ने इनलाइनिंग द्वारा 4 से 55 के सुधार कारक देखे।[2] समारोह कॉल को समाप्त करने के प्रत्यक्ष लाभ हैं:

  • यह कॉलिंग फ़ंक्शन और कैली दोनों में फ़ंक्शन कॉल के लिए आवश्यक निर्देशों को समाप्त करता है: स्टैक या रजिस्टरों में तर्कों को रखकर, फ़ंक्शन स्वयं कॉल करता है, फ़ंक्शन प्रस्तावना, फिर फ़ंक्शन उपसंहार, वापसी कथन, और फिर वापसी मूल्य वापस प्राप्त करना, और स्टैक से तर्कों को हटाना और रजिस्टरों को बहाल करना (यदि आवश्यक हो)।
  • तर्क पारित करने के लिए रजिस्टरों की आवश्यकता नहीं होने के कारण, यह रिसाव दर्ज करें को कम करता है।
  • संदर्भ द्वारा कॉल का उपयोग करते समय (या पते से कॉल करें, या साझा करके कॉल करें) संदर्भों को पारित करने की आवश्यकता को समाप्त करता है और फिर उन्हें हटा देता है।

हालाँकि, इनलाइनिंग का प्राथमिक लाभ इसके द्वारा अनुमत अतिरिक्त अनुकूलन है। अंतरप्रक्रियात्मक अनुकूलन (IPO) की आवश्यकता के बिना फ़ंक्शन सीमाओं को पार करने वाले ऑप्टिमाइज़ेशन: एक बार इनलाइनिंग का प्रदर्शन किया गया है, बढ़े हुए फ़ंक्शन बॉडी पर अतिरिक्त इंट्राप्रोसेडुरल ऑप्टिमाइज़ेशन (वैश्विक ऑप्टिमाइज़ेशन) संभव हो जाते हैं। उदाहरण के लिए:

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

इन्हें इनलाइनिंग के बिना किया जा सकता है, लेकिन इसके लिए काफी अधिक जटिल कंपाइलर और लिंकर की आवश्यकता होती है (यदि कॉलर और कैली अलग-अलग संकलन इकाइयों में हैं)।

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

मेमोरी सिस्टम के लिए इनलाइनिंग का एक और लाभ है:

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

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

कोड विस्तार (दोहराव के कारण) निर्देश कैश प्रदर्शन को नुकसान पहुंचाने के कारण इनलाइनिंग भी प्रदर्शन पर लागत लगाती है।[6] यह सबसे महत्वपूर्ण है अगर, विस्तार से पहले, प्रोग्राम का कार्य का संग्रह (या कोड का एक हॉट सेक्शन) मेमोरी पदानुक्रम (जैसे, एल 1 कैश) के एक स्तर में फिट होता है, लेकिन विस्तार के बाद यह अब फिट नहीं होता है, जिसके परिणामस्वरूप बार-बार कैश उस स्तर पर चूक जाता है। पदानुक्रम के विभिन्न स्तरों पर प्रदर्शन में महत्वपूर्ण अंतर के कारण, यह प्रदर्शन को काफी नुकसान पहुँचाता है। उच्चतम स्तर पर इसके परिणामस्वरूप पृष्ठ दोष बढ़ सकते हैं, थ्रैशिंग (कंप्यूटर विज्ञान) के कारण विपत्तिपूर्ण प्रदर्शन गिरावट, या प्रोग्राम बिल्कुल भी चलने में विफल हो सकता है। यह अंतिम आम डेस्कटॉप और सर्वर अनुप्रयोगों में दुर्लभ है, जहां उपलब्ध मेमोरी के सापेक्ष कोड का आकार छोटा है, लेकिन एम्बेडेड सिस्टम जैसे संसाधन-विवश वातावरण के लिए एक समस्या हो सकती है। इस समस्या को कम करने का एक तरीका है कि कार्यों को एक छोटे गर्म इनलाइन पथ (तेज़ पथ), और एक बड़े ठंडे गैर-इनलाइन पथ (धीमे पथ) में विभाजित किया जाए।[6]

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

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


संकलक समर्थन

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

सामान्यतः, कंपाइलर डेवलपर्स उपरोक्त प्रदर्शन के मुद्दों को ध्यान में रखते हैं, और अपने कंपाइलर्स में heuristics को सम्मिलित करते हैं जो ज्यादातर प्रकरणों में प्रदर्शन को बेहतर बनाने के स्थान पर इनलाइन करने के लिए कौन से कार्यों को चुनते हैं।

कार्यान्वयन

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

लिंकर (कंप्यूटिंग) फ़ंक्शन इनलाइनिंग भी कर सकता है। जब एक लिंकर इनलाइन कार्य करता है, तो यह उन कार्यों को इनलाइन कर सकता है जिनके स्रोत उपलब्ध नहीं हैं, जैसे लाइब्रेरी फ़ंक्शंस (लिंक-समय अनुकूलन देखें)। एक रन-टाइम सिस्टम इनलाइन कार्य भी कर सकता है। रन टाइम (प्रोग्राम जीवनचक्र चरण) | रन-टाइम इनलाइनिंग डायनेमिक प्रोफाइलिंग जानकारी का उपयोग बेहतर निर्णय लेने के लिए कर सकती है कि कौन से कार्यों को इनलाइन करना है, जैसा कि जावा हॉटस्पॉट कंपाइलर में है।[9] सी (प्रोग्रामिंग भाषा) में स्रोत स्तर पर हाथ से निष्पादित इनलाइन विस्तार का एक सरल उदाहरण यहां दिया गया है:

int pred(int x)
{
    if (x == 0)
        return 0;
    else
        return x - 1;
}

Before inlining:

int func(int y) 
{
    return pred(y) + pred(0) + pred(y+1);
}

After inlining:

int func(int y) 
{
    int tmp;
    if (y   == 0) tmp  = 0; else tmp  = y - 1;       /* (1) */
    if (0   == 0) tmp += 0; else tmp += 0 - 1;       /* (2) */
    if (y+1 == 0) tmp += 0; else tmp += (y + 1) - 1; /* (3) */
    return tmp;
}

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

असेंबली मैक्रो विस्तार द्वारा इनलाइनिंग

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

MOVE FROM=array1,TO=array2,इनलाइन=NO

अनुमान

इनलाइनिंग के लिए विभिन्न अनुमानों की एक श्रृंखला का पता लगाया गया है। सामान्यतः, एक इनलाइनिंग एल्गोरिदम का एक निश्चित कोड बजट होता है (प्रोग्राम आकार में अनुमत वृद्धि) और उस बजट को पार किए बिना सबसे मूल्यवान कॉलसाइट्स को इनलाइन करना है। इस अर्थ में, कई इनलाइनिंग एल्गोरिदम सामान्यतः नैपसैक समस्या के बाद तैयार किए जाते हैं।[10] यह तय करने के लिए कि कौन सी कॉलसाइट्स अधिक मूल्यवान हैं, एक इनलाइनिंग एल्गोरिदम को उनके लाभ का अनुमान लगाना चाहिए- अर्थात। निष्पादन समय में अपेक्षित कमी। सामान्यतः, इनलाइनर लाभों का अनुमान लगाने के लिए विभिन्न कोड पथों के निष्पादन की आवृत्ति के बारे में प्रोफाइलिंग जानकारी का उपयोग करते हैं।[11] प्रोफाइलिंग जानकारी के अलावा, नए जस्ट-इन-टाइम कंपाइलर कई और उन्नत ह्यूरिस्टिक्स लागू करते हैं, जैसे:[4]

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

लाभ

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

  • tmp += 0 e> कथन (2) और (3) चिह्नित पंक्तियों में कुछ नहीं करते हैं। कंपाइलर उन्हें हटा सकता है।
  • स्थिति 0 == 0 सदैव सत्य होता है, इसलिए संकलक (2) चिह्नित रेखा को परिणाम के साथ बदल सकता है, tmp += 0 (जो कुछ नहीं करता)।
  • कंपाइलर स्थिति को फिर से लिख सकता है y+1 == 0 को y == -1.
  • कंपाइलर अभिव्यक्ति को कम कर सकता है (y + 1) - 1 को y.
  • भाव y और y+1 दोनों शून्य के बराबर नहीं हो सकते। यह संकलक को एक परीक्षण को समाप्त करने देता है।
  • जैसे बयानों में if (y == 0) return y का मान है y बॉडी में जाना जाता है, और इनलाइन किया जा सकता है।

नया कार्य ऐसा दिखता है:

int func(int y) 
{
    if (y == 0)
        return 0;
    if (y == -1)
        return -2;
    return 2*y - 1;
}

सीमाएं

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

मैक्रोज़ के साथ तुलना

परंपरागत रूप से, C (प्रोग्रामिंग लैंग्वेज) जैसी भाषाओं में, इनलाइन विस्तार को पैरामिट्रीकृत मैक्रोज़ का उपयोग करके स्रोत स्तर पर पूरा किया गया था। वास्तविक इनलाइन फ़ंक्शंस का उपयोग, जैसा कि C99 में उपलब्ध है, इस दृष्टिकोण पर कई लाभ प्रदान करता है:

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

कई संकलक कुछ पुनरावर्तन (कंप्यूटर विज्ञान) का विस्तार भी कर सकते हैं;[13] पुनरावर्ती मैक्रोज़ सामान्यतः अवैध होते हैं।

सी ++ के डिजाइनर बज़्ने स्ट्रॉस्ट्रुप, इस बात पर जोर देना पसंद करते हैं कि जहां भी संभव हो मैक्रोज़ से बचा जाना चाहिए, और इनलाइन कार्यों के व्यापक उपयोग की वकालत करता है।

चयन के तरीके

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

भाषा समर्थन

जावा (प्रोग्रामिंग भाषा) और कार्यात्मक भाषाओं सहित कई भाषाएं इनलाइन कार्यों के लिए भाषा निर्माण प्रदान नहीं करती हैं, लेकिन उनके संकलक या दुभाषिए प्रायः आक्रामक इनलाइन विस्तार करते हैं।[4]अन्य भाषाएं स्पष्ट संकेत के लिए निर्माण प्रदान करती हैं, सामान्यतः कंपाइलर डायरेक्टिव (प्रोग्रामिंग) (प्रागमस) के रूप में।

Ada प्रोग्रामिंग भाषा में, इनलाइन फ़ंक्शंस के लिए एक प्राग्मा उपलब्ध है।

सामान्य लिस्प में कार्यों को इसके द्वारा इनलाइन के रूप में परिभाषित किया जा सकता है इनलाइन घोषणा इस प्रकार है:[14]

 (declaim (inline dispatch))
 (defun dispatch (x)
   (funcall
     (get (car x) 'dispatch) x))

हास्केल (प्रोग्रामिंग भाषा) कंपाइलर ग्लासगो हास्केल कंपाइलर उन कार्यों या मूल्यों को इनलाइन करने का प्रयास करता है जो काफी छोटे हैं लेकिन इनलाइनिंग को स्पष्ट रूप से एक भाषा प्राग्मा का उपयोग करके नोट किया जा सकता है:[15]

key_function :: Int -> String -> (Bool, Double)
{-# INLINE key_function #-}

सी और सी ++

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

यह भी देखें

टिप्पणियाँ

  1. Space usage is "number of instructions", and is both runtime space usage and the binary file size.
  2. Code size actually shrinks for very short functions, where the call overhead is larger than the body of the function, or single-use functions, where no duplication occurs.


संदर्भ

  1. 1.0 1.1 Chen et al. 1993.
  2. Chen et al. 1993, 3.4 Function inline expansion, p. 14.
  3. 4.0 4.1 4.2 [1] Prokopec et al., An Optimization Driven Incremental Inline Substitution Algorithm for Just-In-Time Compilers, CGO'19 publication about the inliner used in the Graal compiler for the JVM
  4. Chen et al. 1993, 3.4 Function inline expansion, p. 19–20.
  5. 6.0 6.1 Benjamin Poulain (August 8, 2013). "Unusual speed boost: size matters".
  6. See for example the Adaptive Optimization System Archived 2011-08-09 at the Wayback Machine in the Jikes RVM for Java.
  7. Chen et al. 1993, 3.4 Function inline expansion, p. 24–26.
  8. [2] Description of the inliner used in the Graal JIT compiler for Java
  9. [3] Scheifler, An Analysis of Inline Substitution for a Structured Programming Language
  10. [4] Matthew Arnold, Stephen Fink, Vivek Sarkar, and Peter F. Sweeney, A Comparative Study of Static and Profile-based Heuristics for Inlining
  11. Peyton Jones & Marlow 1999, 4. Ensuring Termination, pp. 6–9.
  12. Inlining Semantics for Subroutines which are Recursive" by Henry G. Baker
  13. Declaration INLINE, NOTINLINE at the Common Lisp HyperSpec
  14. 7.13.5.1. INLINE pragma Chapter 7. GHC Language Features


बाहरी संबंध