लूप अनरोलिंग

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

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

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

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


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

ऑप्टिमाइज़िंग कंपाइलर कभी-कभी स्वचालित रूप से या अनुरोध पर अनरोलिंग का कार्य करेंगे।

नुकसान

 * इंक्रीसेड प्रोग्राम कोड साइज, जो अवांछनीय हो सकता है, विशेष रूप से एम्बेडेड अनुप्रयोगों के लिए। अनुदेश कैश चूक में भी वृद्धि हो सकती है, जो प्रदर्शन पर प्रतिकूल प्रभाव डाल सकती है।
 * जब तक ऑप्टिमाइज़िंग कंपाइलर द्वारा पारदर्शी तरीके से निष्पादित नहीं किया जाता, कोड कंप्यूटर प्रोग्रामिंग में कम पठनीयता#पठनीयता बन सकता है।
 * यदि लूप के मुख्य भाग में कोड में फ़ंक्शन कॉल सम्मिलित हैं, तो अनरोलिंग को इनलाइनिंग के साथ जोड़ना संभव नहीं हो सकता है, क्योंकि कोड साइज में वृद्धि अत्यधिक हो सकती है। इस प्रकार, दोनों अनुकूलन के बीच एक समझौता हो सकता है।
 * अस्थायी चरों को संग्रहीत करने के लिए एकल पुनरावृत्ति में संभावित बढ़े हुए रजिस्टर उपयोग, जो प्रदर्शन को कम कर सकता है, हालांकि बहुत कुछ संभावित अनुकूलन पर निर्भर करेगा।
 * बहुत छोटे और सरल कोड के अलावा, अनियंत्रित लूप जिनमें शाखाएं होती हैं, रिकर्सन से भी धीमी होती हैं।

स्टेटिक/मैन्युअल लूप अनरोलिंग
मैनुअल (या स्थिर) लूप अनरोलिंग में प्रोग्रामर को लूप का विश्लेषण करना और निर्देशों के अनुक्रम में पुनरावृत्तियों की व्याख्या करना सम्मिलित है जो लूप ओवरहेड को कम करेगा। यह डायनामिक अनरोलिंग के विपरीत है जिसे कंपाइलर द्वारा पूरा किया जाता है।

C में सरल मैनुअल उदाहरण
कंप्यूटर प्रोग्राम में एक प्रक्रिया एक संग्रह से 100 वस्तुओं को हटाने की है। यह सामान्यतः a के माध्यम से पूरा किया जाता है -लूप जो फ़ंक्शन डिलीट (आइटम_नंबर) को कॉल करता है। यदि प्रोग्राम के इस भाग को अनुकूलित किया जाना है, और लूप के ओवरहेड को डिलीट (x) फ़ंक्शन की तुलना में महत्वपूर्ण संसाधनों की आवश्यकता है, तो इसे गति देने के लिए अनवाइंडिंग का उपयोग किया जा सकता है।

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

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

प्रारंभिक जटिलता
साधारण मामले में, लूप नियंत्रण केवल एक प्रशासनिक ओवरहेड है जो उत्पादक बयानों को व्यवस्थित करता है। लूप स्वयं वांछित परिणामों में कुछ भी योगदान नहीं देता है, केवल प्रोग्रामर को कोड को सौ बार दोहराने की थकावट से बचाता है जो कि प्रतिकृति उत्पन्न करने वाले प्री-प्रोसेसर, या एक टेक्स्ट एडिटर द्वारा किया जा सकता था। इसी प्रकार, -स्टेटमेंट और अन्य प्रवाह नियंत्रण स्टेटमेंट को कोड प्रतिकृति द्वारा प्रतिस्थापित किया जा सकता है, सिवाय इसके कि कोड ब्लोट का परिणाम हो सकता है। कंप्यूटर प्रोग्राम आसानी से संयोजनों को ट्रैक करते हैं, लेकिन प्रोग्रामर को यह दोहराव उबाऊ लगता है और गलतियाँ करते हैं। विचार करना:

लेकिन निश्चित रूप से, निष्पादित कोड को किसी प्रक्रिया का आह्वान करने की आवश्यकता नहीं है, और इस अगले उदाहरण में गणना में सूचकांक चर सम्मिलित है:

जो, यदि संकलित किया जाए, तो बहुत सारे कोड उत्पन्न कर सकता है (प्रिंट स्टेटमेंट कुख्यात है) लेकिन आगे अनुकूलन संभव है। यह उदाहरण लूप में केवल x(i) और x(i - 1) का संदर्भ देता है (बाद वाला केवल नया मान x(i) विकसित करने के लिए है) इसलिए, यह देखते हुए कि यहां विकसित सरणी x का कोई बाद का संदर्भ नहीं है, इसके उपयोग को एक साधारण चर द्वारा प्रतिस्थापित किया जा सकता है। हालाँकि, इस तरह के परिवर्तन का मतलब एक साधारण चर होगा जिसका मान बदल गया है, जबकि सरणी के साथ रहने पर, कंपाइलर का विश्लेषण यह नोट कर सकता है कि सरणी के मान स्थिर हैं, प्रत्येक पिछले स्थिरांक से प्राप्त होता है, और इसलिए स्थिर मानों को आगे बढ़ाता है ताकि कोड बन जाए प्रिंट 2, 2; प्रिंट 3, 6; प्रिंट 4, 24; ...वगैरह।

सामान्य तौर पर, लूप की सामग्री बड़ी हो सकती है, जिसमें जटिल सरणी अनुक्रमण सम्मिलित होता है। इन मामलों को संभवतः कंपाइलरों को अनियंत्रित करने के लिए अनुकूलित करना सबसे अच्छा है। अंतरतम लूपों की नकल करने से कई संभावित अनुकूलन की अनुमति मिल सकती है, फिर भी केवल एक छोटा सा लाभ मिलता है जब तक कि n बड़ा न हो।

लूप्स को अनियंत्रित करना
निम्नलिखित के समान एक छद्मकोड WHILE लूप पर विचार करें:

इस मामले में, अनरोलिंग तेज़ है क्योंकि ENDWHILE (लूप की शुरुआत में एक छलांग) को 66% कम बार निष्पादित किया जाएगा।

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

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

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

असेंबलर उदाहरण (आईबीएम/360 या जेड/आर्किटेक्चर)
This example is for IBM/360 or Z/Architecture assemblers and assumes a field of 100 bytes (at offset zero) is to be copied from array FROM to array TO&mdash;both having 50 entries with element lengths of 256 bytes each.

इस उदाहरण में, पारंपरिक लूप (50 पुनरावृत्तियों) के साथ लगभग 202 निर्देशों की आवश्यकता होगी, जबकि उपरोक्त गतिशील कोड के लिए केवल 89 निर्देशों (या लगभग 56% की बचत) की आवश्यकता होगी। यदि सरणी में केवल दो प्रविष्टियाँ सम्मिलित होतीं, तो भी यह मूल अनवाउंड लूप के समान ही समय में निष्पादित होती। बाइनरी फ़ाइल साइज में वृद्धि केवल 108 बाइट्स है – भले ही सरणी में हजारों प्रविष्टियाँ हों।

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

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

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

C से एमआईपीएस असेंबली लैंग्वेज लूप अनरोलिंग उदाहरण
निम्नलिखित उदाहरण दो 100-एंट्री वैक्टर A और B प्रकार के डॉट उत्पाद की गणना करेगा. यहां C में कोड है:C:

एमआईपीएस असेंबली लैंग्वेज में कनवर्ट करना
निम्नलिखित एमआईपीएस असेंबली कोड है जो लूप अनरोलिंग को लागू करने से पहले दो 100-एंट्री वैक्टर, A और B के डॉट उत्पाद की गणना करेगा। नीचे दिया गया कोड लूप आरंभीकरण को छोड़ देता है: ध्यान दें कि सरणियों के एक तत्व का साइज (a ) 8 बाइट्स है।
 * प्रारंभिक लूप गिनती ($7) से 100 तक।
 * आरंभिक डॉट उत्पाद ($f10) से 0 करें।
 * आरंभ करें  के आधार पते पर सूचक ($5)।.
 * आरंभ करें  के आधार पते पर सूचक ($6)।.

एमआईपीएस में लूप को अनियंत्रित करना
निम्नलिखित ऊपर जैसा ही है, लेकिन लूप अनरोलिंग को 4 के कारक पर लागू किया गया है। फिर से ध्यान दें कि सरणियों के एक तत्व का साइज (ए) ) 8 बाइट्स है; इस प्रकार प्रत्येक लूप पर 0, 8, 16, 24 विस्थापन और 32 विस्थापन।

यह भी देखें

 * अपने आप को मत दोहराओ
 * डफ का उपकरण
 * निर्देश स्तर समानता
 * सही समय पर संकलन
 * लूप फ़्यूज़न
 * लूप विभाजन
 * समानांतर कंप्यूटिंग

बाहरी संबंध

 * Chapter 7, pages 8 to 10, of Michael Abrash's Graphics Programming Black Book is about loop unrolling, with an example in x86 assembly.
 * Generalized Loop Unrolling, gives a concise introduction.
 * Optimizing subroutines in assembly language Agner Fog's optimizations handbook with the loop unrolling technique (2012).