स्वचालित वैश्वीकरण

From alpha
Jump to navigation Jump to search

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

हालाँकि, अधिकांश प्रोग्रामिंग भाषाओं में आमतौर पर लूप लिखे जाते हैं जो क्रमिक रूप से कई संख्याओं के जोड़ को निष्पादित करते हैं। यहाँ ऐसे लूप का उदाहरण दिया गया है, जिसे C (प्रोग्रामिंग लैंग्वेज) में लिखा गया है: <वाक्यविन्यास प्रकाश लैंग = सी> के लिए (i = 0; i <n; i++)

   सी [i] = ए [i] + बी [i];

</वाक्यविन्यास हाइलाइट>

एक वेक्टरिंग संकलक ऐसे लूप को वेक्टर ऑपरेशंस के सीक्वेंस में बदल देता है। ये वेक्टर ऑपरेशन सरणियों से तत्वों के ब्लॉक पर अतिरिक्त कार्य करते हैं a, b और c. कंप्यूटर विज्ञान में स्वचालित वैश्वीकरण एक प्रमुख शोध विषय है।[citation needed]


पृष्ठभूमि

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

लूप वेक्टराइजेशन ऑपरेंड के प्रत्येक जोड़े को एक प्रोसेसिंग यूनिट असाइन करके प्रक्रियात्मक लूप को बदल देता है। प्रोग्राम अपना अधिकांश समय ऐसे लूपों के भीतर व्यतीत करते हैं। इसलिए, वैश्वीकरण उन्हें विशेष रूप से बड़े डेटा सेट पर महत्वपूर्ण रूप से गति प्रदान कर सकता है। इंटेल के MMX (इंस्ट्रक्शन सेट), स्ट्रीमिंग SIMD एक्सटेंशन्स, और उन्नत वेक्टर एक्सटेंशन, Power ISA के Altivec में और एआरएम होल्डिंग्स के ARM NEON, ARMv8-A SVE और SVE2 इंस्ट्रक्शन सेट में लूप वैश्वीकरण लागू किया गया है।

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

गारंटी

स्वत: वैश्वीकरण, किसी भी लूप अनुकूलन या अन्य संकलन-समय ऑप्टिमाइज़ेशन की तरह, प्रोग्राम व्यवहार को सटीक रूप से संरक्षित करना चाहिए।

डेटा निर्भरता

गलत परिणामों को रोकने के लिए निष्पादन के दौरान सभी निर्भरताओं का सम्मान किया जाना चाहिए।

सामान्य तौर पर, लूप इनवेरिएंट डिपेंडेंसी और लूप डिपेंडेंस एनालिसिस # क्लासिफिकेशन को आसानी से वेक्टर किया जा सकता है, और लेक्सिकली बैकवर्ड डिपेंडेंसी को लेक्सिकली फॉरवर्ड डिपेंडेंसी में तब्दील किया जा सकता है। हालाँकि, इन परिवर्तनों को सुरक्षित रूप से किया जाना चाहिए, ताकि यह सुनिश्चित किया जा सके कि सभी कथनों के बीच निर्भरता मूल के लिए सही बनी रहे।

वेक्टरकृत निर्देशों से स्वतंत्र रूप से चक्रीय निर्भरताओं को संसाधित किया जाना चाहिए।

डेटा परिशुद्धता

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

जब तक IEEE-754 अनुपालन बंद नहीं किया जाता है, तैरनेवाला स्थल सटीकता को भी रखा जाना चाहिए, जिस स्थिति में संचालन तेज़ होगा लेकिन परिणाम थोड़े भिन्न हो सकते हैं। बड़े बदलाव, यहां तक ​​कि IEEE-754 को अनदेखा करना आमतौर पर प्रोग्रामर की त्रुटि को दर्शाता है।

सिद्धांत

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

निर्भरता ग्राफ का निर्माण

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

निर्भरता ग्राफ में सभी स्थानीय निर्भरताएँ होती हैं जिनकी दूरी वेक्टर आकार से अधिक नहीं होती है। इसलिए, यदि वेक्टर रजिस्टर 128 बिट्स है, और सरणी प्रकार 32 बिट्स है, तो वेक्टर का आकार 128/32 = 4 है। अन्य सभी गैर-चक्रीय निर्भरताओं को वैश्वीकरण को अमान्य नहीं करना चाहिए, क्योंकि इसमें कोई समवर्ती पहुंच नहीं होगी वही वेक्टर निर्देश।

मान लीजिए वेक्टर आकार 4 इंच के समान है:

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (i = 0; i <128; i++) {

   एक [i] = एक [i-16]; // 16> 4, अनदेखा करना सुरक्षित है
   ए [आई] = ए [आई -1]; // 1 <4, निर्भरता ग्राफ पर रहता है

} </वाक्यविन्यास हाइलाइट>

क्लस्टरिंग

ग्राफ़ का उपयोग करते हुए, ऑप्टिमाइज़र दृढ़ता से जुड़े घटकों (एससीसी) को क्लस्टर कर सकता है और बाकी हिस्सों से अलग-अलग सदिश योग्य बयानों को अलग कर सकता है।

उदाहरण के लिए, एक लूप के अंदर तीन स्टेटमेंट ग्रुप वाले एक प्रोग्राम फ़्रैगमेंट पर विचार करें: (SCC1+SCC2), SCC3 और SCC4, उस क्रम में, जिसमें केवल दूसरे समूह (SCC3) को वेक्टराइज़ किया जा सकता है। अंतिम कार्यक्रम में तीन लूप होंगे, प्रत्येक समूह के लिए एक, केवल मध्य एक सदिश के साथ। ऑप्टिमाइज़र स्टेटमेंट निष्पादन आदेश का उल्लंघन किए बिना पहले के साथ अंतिम में शामिल नहीं हो सकता है, जो आवश्यक गारंटी को अमान्य कर देगा।

मुहावरों का पता लगाना

विशिष्ट मुहावरों के आधार पर कुछ गैर-स्पष्ट निर्भरताओं को और अनुकूलित किया जा सकता है।

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

<वाक्यविन्यास प्रकाश लैंग = सी> ए [i] = ए [i] + ए [i + 1]; </वाक्यविन्यास हाइलाइट>

चर उन्मूलन द्वारा स्केलर्स द्वारा आत्म-निर्भरता को सदिश बनाया जा सकता है।

सामान्य ढांचा

लूप वैश्वीकरण के लिए सामान्य रूपरेखा को चार चरणों में विभाजित किया गया है:

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

रन-टाइम बनाम कंपाइल-टाइम

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

यह रन-टाइम चेक प्रस्तावना चरण में किया जाता है और यदि संभव हो तो प्रवाह को सदिश निर्देशों के लिए निर्देशित करता है, अन्यथा मानक प्रसंस्करण पर निर्भर करता है, जो कि रजिस्टरों या स्केलर चर पर पारित किए जा रहे चर पर निर्भर करता है।

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

<वाक्यविन्यास प्रकाश लैंग = सी> int [128]; इंट बी [128]; // इनिशियलाइज़ बी

के लिए (i = 0; i<128; i++)

   ए [i] = बी [i] + 5;

</वाक्यविन्यास हाइलाइट>

दूसरी ओर, नीचे दिए गए कोड में मेमोरी पोजीशन के बारे में कोई जानकारी नहीं है, क्योंकि संदर्भ सूचक (कंप्यूटर प्रोग्रामिंग) हैं और जिस मेमोरी को वे इंगित करते हैं वह ओवरलैप हो सकती है।

<वाक्यविन्यास प्रकाश लैंग = सी> शून्य गणना (इंट * ए, इंट * बी) {

   int मैं;
   के लिए (i = 0; i <128; i++, a++, b++)
       *ए = *बी + 5;

} </वाक्यविन्यास हाइलाइट>

a और b दोनों के स्मृति पता पर एक त्वरित रन-टाइम चेक, साथ ही लूप पुनरावृत्ति स्थान (128) यह बताने के लिए पर्याप्त है कि सरणियाँ ओवरलैप होती हैं या नहीं, इस प्रकार किसी भी निर्भरता का खुलासा होता है।

SIMD समानता के लिए निहित गुप्त क्षमता का आकलन करने के लिए मौजूदा अनुप्रयोगों का गतिशील रूप से विश्लेषण करने के लिए कुछ उपकरण मौजूद हैं, जो आगे के संकलक अग्रिमों और/या मैनुअल कोड परिवर्तनों के माध्यम से शोषक हैं।[1]


तकनीक

एक उदाहरण संख्यात्मक डेटा के दो वैक्टरों को गुणा करने के लिए एक कार्यक्रम होगा। एक स्केलर दृष्टिकोण कुछ ऐसा होगा:

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (i = 0; i <1024; i++)

   सी [i] = ए [i] * बी [i];

</वाक्यविन्यास हाइलाइट>

इसे कुछ ऐसा दिखने के लिए वेक्टर किया जा सकता है:

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4)

   सी[i:i+3] = a[i:i+3] * b[i:i+3];

</वाक्यविन्यास हाइलाइट>

यहाँ, c[i:i+3] c[i] से c[i+3] तक चार सरणी तत्वों का प्रतिनिधित्व करता है और वेक्टर प्रोसेसर एक वेक्टर निर्देश के लिए चार ऑपरेशन कर सकता है। चूँकि चार सदिश संक्रियाएँ लगभग एक ही समय में एक अदिश निर्देश के रूप में पूरी होती हैं, सदिश दृष्टिकोण मूल कोड की तुलना में चार गुना तेजी से चल सकता है।

दो अलग-अलग संकलक दृष्टिकोण हैं: एक पारंपरिक वैश्वीकरण तकनीक पर आधारित है और दूसरा लूप खोलना पर आधारित है।

लूप-स्तर स्वचालित वैश्वीकरण

पारंपरिक वेक्टर मशीनों के लिए उपयोग की जाने वाली यह तकनीक लूप स्तर पर SIMD समानता को खोजने और उसका फायदा उठाने की कोशिश करती है। इसमें निम्नानुसार दो प्रमुख चरण होते हैं।

  1. एक अंतरतम लूप खोजें जिसे वेक्टर किया जा सकता है
  2. लूप को ट्रांसफ़ॉर्म करें और वेक्टर कोड जनरेट करें

पहले चरण में, कंपाइलर उन बाधाओं की तलाश करता है जो वैश्वीकरण को रोक सकते हैं। वैश्वीकरण के लिए एक बड़ी बाधा सदिश लंबाई से कम निर्देश स्तर समानता है। अन्य बाधाओं में फ़ंक्शन कॉल और लघु पुनरावृत्ति गणना शामिल हैं।

एक बार जब लूप को वेक्टर करने योग्य निर्धारित किया जाता है, तो लूप को वेक्टर लंबाई से अलग कर दिया जाता है और लूप बॉडी के भीतर प्रत्येक स्केलर इंस्ट्रक्शन को संबंधित वेक्टर इंस्ट्रक्शन से बदल दिया जाता है। नीचे, इस चरण के लिए घटक परिवर्तन उपरोक्त उदाहरण का उपयोग करके दिखाए गए हैं।

  • स्ट्रिपमाइनिंग के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4)

   के लिए (जे = 0; जे <4; जे ++)
       सी [आई + जे] = ए [आई + जे] * बी [आई + जे];

</वाक्यविन्यास हाइलाइट>

  • अस्थायी सरणियों का उपयोग करके लूप वितरण के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   के लिए (जे = 0; जे <4; जे ++) टीए [जे] = ए [आई + जे];
   के लिए (जे = 0; जे <4; जे ++) टीबी [जे] = बी [आई + जे];
   के लिए (जे = 0; जे <4; जे ++) टीसी [जे] = टीए [जे] * टीबी [जे];
   के लिए (जे = 0; जे <4; जे ++) सी [आई + जे] = टीसी [जे];

} </वाक्यविन्यास हाइलाइट>

  • वेक्टर कोड से बदलने के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   वीए = vec_ld (और ए [i]);
   वीबी = vec_ld (और बी [i]);
   vC = vec_mul (vA, vB);
   vec_st (वीसी, और सी [i]);

} </वाक्यविन्यास हाइलाइट>

बुनियादी ब्लॉक स्तर स्वत: वैश्वीकरण

यह अपेक्षाकृत नई तकनीक विशेष रूप से आधुनिक SIMD आर्किटेक्चर को कम वेक्टर लंबाई के साथ लक्षित करती है।[2] हालांकि बुनियादी ब्लॉकों में SIMD समानता की मात्रा बढ़ाने के लिए लूप को अनियंत्रित किया जा सकता है, यह तकनीक लूप के बजाय बुनियादी ब्लॉक के भीतर SIMD समानता का फायदा उठाती है। दो प्रमुख चरण इस प्रकार हैं।

  1. एक बड़े लूप बॉडी बनाने के लिए सदिश लंबाई के एक कारक द्वारा अंतरतम लूप को अनियंत्रित किया जाता है।
  2. आइसोमॉर्फिक स्केलर निर्देश (जो समान ऑपरेशन करते हैं) एक वेक्टर निर्देश में पैक किए जाते हैं यदि निर्भरता ऐसा करने से नहीं रोकती है।

इस दृष्टिकोण के लिए चरण-दर-चरण परिवर्तन दिखाने के लिए, उसी उदाहरण का फिर से उपयोग किया जाता है।

  • लूप अनोलिंग के बाद (वेक्टर लंबाई से, इस मामले में 4 माना जाता है)

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   sA0 = एलडी (&ए [i+0]);
   sB0 = एलडी (&बी [i+0]);
   एससी0 = एसए0 * एसबी0;
   st(sC0, &C[i+0]);
         ...
   sA3 = एलडी (&ए [i+3]);
   एसबी3 = एलडी(&बी[i+3]);
   एससी3 = एसए3 * एसबी3;
   सेंट (एससी3, और सी [i+3]);

} </वाक्यविन्यास हाइलाइट>

  • पैकिंग के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   (sA0, sA1, sA2, sA3) = ld(&A[i+0:i+3]);
   (sB0, sB1, sB2, sB3) = ld(&B[i+0:i+3]);
   (sC0, sC1, sC2, sC3) = (sA0, sA1, sA2, sA3) * (sB0, sB1, sB2, sB3);
   st((sC0, sC1, sC2, sC3), और C[i+0:i+3]);

} </वाक्यविन्यास हाइलाइट>

  • कोड जनरेशन के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   वीए = vec_ld (और ए [i]);
   वीबी = vec_ld (और बी [i]);
   vC = vec_mul (vA, vB);
   vec_st (वीसी, और सी [i]);

} </वाक्यविन्यास हाइलाइट> यहाँ, sA1, sB1, ... अदिश चरों का प्रतिनिधित्व करते हैं और vA, vB और vC सदिश चरों का प्रतिनिधित्व करते हैं।

आईबीएम एक्सएल कंपाइलर को छोड़कर अधिकांश स्वचालित रूप से व्यावसायिक संकलक पारंपरिक लूप-स्तरीय दृष्टिकोण का उपयोग करते हैं,[3]जो दोनों का उपयोग करता है।

नियंत्रण प्रवाह की उपस्थिति में

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

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (i = 0; i <1024; i++)

   अगर (ए[i] > 0)
       सी [i] = बी [i];
   अन्य
       डी [i] = डी [i-1];

</वाक्यविन्यास हाइलाइट>

  • प्रार्थना के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (i = 0; i <1024; i++) {

   पी = ए [i]> 0;
   एनपी = पी;
   सी [i] = बी [i]; (पी)
   डी [i] = डी [i-1]; (एनपी)

} </वाक्यविन्यास हाइलाइट> जहां (पी) कथन की रक्षा करने वाले एक विधेय को दर्शाता है।

  • वैश्वीकरण के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   वीपी = ए [i:i+3] > (0, 0, 0, 0);
   वीएनपी = vec_not (वीपी);
   सी[i:i+3] = बी[i:i+3]; (वीपी)
   (एनपी1, एनपी2, एनपी3, एनपी4) = वीएनपी;
   डी [आई + 3] = डी [आई + 2]; (एनपी4)
   डी [आई + 2] = डी [आई + 1]; (एनपी3)
   डी [आई + 1] = डी [आई]; (एनपी2)
   डी [i] = डी [i-1]; (एनपी1)

} </वाक्यविन्यास हाइलाइट>

  • वेक्टर विधेय को हटाने के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   वीपी = ए [i:i+3] > (0, 0, 0, 0);
   वीएनपी = vec_not (वीपी);
   सी[i:i+3] = vec_sel(सी[i:i+3], बी[i:i+3], वीपी);
   (एनपी1, एनपी2, एनपी3, एनपी4) = वीएनपी;
   डी [आई + 3] = डी [आई + 2]; (एनपी4)
   डी [आई + 2] = डी [आई + 1]; (एनपी3)
   डी [आई + 1] = डी [आई]; (एनपी2)
   डी [i] = डी [i-1]; (एनपी1)

} </वाक्यविन्यास हाइलाइट>

  • अदिश विधेय को हटाने के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   वीपी = ए [i:i+3] > (0, 0, 0, 0);
   वीएनपी = vec_not (वीपी);
   सी[i:i+3] = vec_sel(सी[i:i+3], बी[i:i+3], वीपी);
   (एनपी1, एनपी2, एनपी3, एनपी4) = वीएनपी;
   अगर (एनपी 4) डी [आई + 3] = डी [आई + 2];
   अगर (एनपी3) डी[i+2] = डी[i+1];
   अगर (एनपी2) डी[i+1] = डी[i];
   अगर (एनपी 1) डी [i] = डी [i-1];

} </वाक्यविन्यास हाइलाइट>

=== नियंत्रण प्रवाह === की उपस्थिति में वैश्वीकरण ओवरहेड को कम करना वेक्टर कोड में सभी नियंत्रण पथों में निर्देशों को निष्पादित करने के बाद प्रमुख कारकों में से एक रहा है जो स्केलर बेसलाइन के संबंध में वेक्टर कोड को धीमा कर देता है। नियंत्रण प्रवाह जितना अधिक जटिल होता जाता है और स्केलर कोड में जितने अधिक निर्देश बायपास होते जाते हैं, वैश्वीकरण ओवरहेड उतना ही बड़ा होता जाता है। इस वेक्टरेशन ओवरहेड को कम करने के लिए, वेक्टर शाखाओं को वेक्टर निर्देशों को बाईपास करने के लिए डाला जा सकता है, जैसे स्केलर शाखाएं स्केलर निर्देशों को बाईपास करती हैं।[5] नीचे, AltiVec विधेय का उपयोग यह दिखाने के लिए किया जाता है कि यह कैसे प्राप्त किया जा सकता है।

  • स्केलर बेसलाइन (मूल कोड)

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (i = 0; i <1024; i++) {

   अगर (ए[i] > 0)
   {
       सी [i] = बी [i];
       अगर (बी [मैं] <0)
           डी [i] = ई [i];
   }

} </वाक्यविन्यास हाइलाइट>

  • नियंत्रण प्रवाह की उपस्थिति में वैश्वीकरण के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   वीपीए = ए [i:i+3] > (0, 0, 0, 0);
   सी[i:i+3] = vec_sel(सी[i:i+3], बी[i:i+3], vPA);
   वीटी = बी [i:i+3] <(0,0,0,0);
   vPB = vec_sel ((0, 0, 0, 0), vT, vPA);
   डी[i:i+3] = vec_sel(डी[i:i+3], ई[i:i+3], वीपीबी);

} </वाक्यविन्यास हाइलाइट>

  • वेक्टर शाखाएं डालने के बाद

<वाक्यविन्यास प्रकाश लैंग = सी> के लिए (मैं = 0; मैं <1024; मैं + = 4) {

   अगर (vec_any_gt (ए [i: i + 3], (0, 0, 0, 0)))
   {
       वीपीए = ए [i:i+3] > (0,0,0,0);
       सी[i:i+3] = vec_sel(सी[i:i+3], बी[i:i+3], vPA);
       वीटी = बी [मैं: मैं + 3] <(0, 0, 0, 0);
       vPB = vec_sel ((0, 0, 0, 0), vT, vPA);
       अगर (vec_any_ne (vPB, (0, 0, 0, 0)))
           डी[i:i+3] = vec_sel(डी[i:i+3], ई[i:i+3], वीपीबी);
   }

} </वाक्यविन्यास हाइलाइट> वेक्टर शाखाओं के साथ अंतिम कोड में ध्यान देने योग्य दो बातें हैं; सबसे पहले, vPA के लिए विधेय परिभाषित निर्देश भी vec_any_gt का उपयोग करके बाहरी वेक्टर शाखा के मुख्य भाग में शामिल है। दूसरा, वीपीबी के लिए आंतरिक वेक्टर शाखा की लाभप्रदता वीपीबी की सशर्त संभावना पर निर्भर करती है जिसमें सभी क्षेत्रों में गलत मान होते हैं, दिए गए वीपीए में सभी क्षेत्रों में गलत मूल्य होते हैं।

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

मैनुअल वैश्वीकरण

अधिकांश सी (प्रोग्रामिंग भाषा) और सी ++ कंपाइलर्स में, प्रोग्रामर प्रयास और रखरखाव की कीमत पर मैन्युअल रूप से सदिश बनाने के लिए आंतरिक कार्यों का उपयोग करना संभव है।

यह भी देखें

संदर्भ

  1. Holewinski, Justin; Ramamurthi, Ragavendar; Ravishankar, Mahesh; Fauzia, Naznin; Pouchet, Louis-Noël; Rountev, Atanas; Sadayappan, P. (6 August 2012). "Dynamic trace-based analysis of vectorization potential of applications". ACM SIGPLAN Notices. 47 (6): 371–382. doi:10.1145/2345156.2254108.
  2. Larsen, S.; Amarasinghe, S. (2000). "Exploiting superword level parallelism with multimedia instruction sets". Proceedings of the ACM SIGPLAN conference on Programming language design and implementation. ACM SIGPLAN Notices. 35 (5): 145–156. doi:10.1145/358438.349320. hdl:1721.1/86445.
  3. "Code Optimization with IBM XL Compilers" (PDF). June 2004. Archived from the original (PDF) on 2010-06-10.
  4. Shin, J.; Hall, M. W.; Chame, J. (2005). "Superword-Level Parallelism in the Presence of Control Flow". Proceedings of the international symposium on Code generation and optimization. pp. 165–175. doi:10.1109/CGO.2005.33. ISBN 0-7695-2298-X.
  5. Shin, J. (2007). "Introducing Control Flow into Vectorized Code". Proceedings of the 16th International Conference on Parallel Architecture and Compilation Techniques. pp. 280–291. doi:10.1109/PACT.2007.41.