दूसरों को "मान्यता से परे अनुकूलित" कम्प्यूटेशनल रूप से गहन कोड कैसे दस्तावेज़ और सिखाएं?


11

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

लक्ष्य दस्तावेज़ बनाने के लिए हैं, और अनुकूलन तकनीकों को पढ़ाने के लिए, ताकि कोड अप्राप्य न हो जाए और नए डेवलपर्स को हटाने के लिए प्रवण न हो। (*)

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

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

आमतौर पर, एक सॉफ्टवेयर लेखक फ़ंक्शन के कई संस्करणों को प्रत्येक अनुकूलन / एल्गोरिथ्म के प्रलेखन के रूप में रख सकता है जो जगह लेता है। अपनी अनुकूलन तकनीकों का अध्ययन करने के लिए कोई इन संस्करणों को दूसरों के लिए कैसे उपलब्ध करता है?

सम्बंधित:


1
आप कोड में अलग-अलग संस्करण रख सकते हैं, टिप्पणी कर सकते हैं, साथ ही बहुत सारी टिप्पणियाँ पाठक को बताएंगे कि क्या चल रहा है।
माइक डनलैवी

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

1
@MikeDunlavey: आउच, कृपया इसे टिप्पणी न करें। बस एक ही फ़ंक्शन के कई कार्यान्वयन हैं, और जो सबसे तेज़ है उसे कॉल करें। इस तरह आप आसानी से कोड के एक अलग संस्करण में स्विच कर सकते हैं, और उन सभी को बेंचमार्क कर सकते हैं।
स्लेस्के

2
@ स्लेस्के कभी-कभी केवल अधिक बाइनरी कोड होने से यह धीमा हो सकता है।
quant_dev

@ क्वेंट_देव: हां, ऐसा हो सकता है। मुझे लगता है कि यह महत्वपूर्ण है कि कोड नियमित रूप से बनाया गया हो और (आदर्श रूप से) उसे अद्यतित रखा जाए। शायद इसे डीबग मोड में ही बनाएँ।
साल्के

जवाबों:


10

संक्षिप्त जवाब

अनुकूलन को स्थानीय रखें, उन्हें स्पष्ट करें, उन्हें अच्छी तरह से प्रलेखित करें और स्रोत कोड और रन-टाइम प्रदर्शन के मामले में दोनों को एक दूसरे के साथ अनुकूलित संस्करणों की तुलना करना आसान बना दें।

पूरा जवाब

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

आदर्श रूप से, आपको अपनी निर्माण प्रक्रिया में प्रदर्शन परीक्षण को सुनिश्चित करने की आवश्यकता होती है, इसलिए आपको पता चलता है कि नई प्रौद्योगिकियां पुराने अनुकूलन को अमान्य कर देती हैं।

याद है:

कार्यक्रम अनुकूलन का पहला नियम: यह मत करो।

कार्यक्रम अनुकूलन का दूसरा नियम (केवल विशेषज्ञों के लिए!): अभी तक ऐसा न करें। "

- माइकल ए। जैक्सन

यह जानने के लिए कि क्या अब समय के लिए बेंचमार्किंग और परीक्षण की आवश्यकता है।

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

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

उदाहरण

उदाहरण के लिए, आपको एक फास्ट फूरियर ट्रांसफ़र फ़ंक्शन की सुविधा देता है। हो सकता है कि आपके पास एक बुनियादी, एल्गोरिथम कार्यान्वयन fft.cऔर में परीक्षण हो fft_tests.c

फिर साथ में पेंटियम आता है और आप MMX निर्देशोंfft_mmx.c का उपयोग करके निश्चित बिंदु संस्करण को लागू करने का निर्णय लेते हैं । बाद में पेंटियम 3 आता है और आप एक संस्करण जोड़ने का निर्णय लेते हैं जिसमें स्ट्रीमिंग सिमडी एक्सटेंशन का उपयोग किया जाता है ।fft_sse.c

अब आप CUDA जोड़ना चाहते हैं , इसलिए आप जोड़ते हैं fft_cuda.c, लेकिन पाते हैं कि आप जिस टेस्ट डेटासेट का उपयोग वर्षों से कर रहे हैं, वह CUDA संस्करण SSE संस्करण की तुलना में धीमा है! आप कुछ विश्लेषण करते हैं और एक डेटासेट को जोड़ते हैं जो 100 गुना बड़ा है और आपको वह गति मिलती है जिसकी आप अपेक्षा करते हैं, लेकिन अब आप जानते हैं कि CUDA संस्करण का उपयोग करने के लिए सेट-अप समय महत्वपूर्ण है और छोटे डेटासेट के साथ आपको एक का उपयोग करना चाहिए उस सेट-अप लागत के बिना एल्गोरिथ्म।

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

सभी एक OOP कार्यान्वयन के लिए जाते हैं, जहां एक आधार वर्ग जो अनप्टीमाइज्ड एल्गोरिथ्म को लागू करता है, और व्युत्पन्न वर्ग अलग-अलग अनुकूलन लागू करते हैं।

महत्वपूर्ण बात यह है कि जो चीजें समान हैं , उन्हें वही रखें , ताकि अंतर स्पष्ट हो


7

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

जबकि आपने उल्लेख नहीं किया है, मैं Cयहाँ मान रहा हूँ ।

Cकोड में सबसे सरल तरीका , एक अनुकूलन करता है (और यह तब भी लागू होता है जब चीजों को पोर्टेबल बनाने की कोशिश की जाती है)

 
#ifdef OPTIMIZATION_XYZ_ENABLE 
   // your optimzied code here... 
#else  
   // your basic code here...

जब आप #define OPTIMIZATION_XYZ_ENABLEमेकफाइल में संकलन के दौरान सक्षम होते हैं , तो सब कुछ उसी के अनुसार काम करता है।

आमतौर पर फ़ंक्शंस के बीच में कोड की कुछ लाइनों को काटने पर गड़बड़ हो सकती है जब बहुत सारे फ़ंक्शंस ऑप्टिमाइज़ किए जाते हैं। इसलिए, इस मामले में एक विशिष्ट कार्य करने के लिए विभिन्न फ़ंक्शन पॉइंटर्स को परिभाषित करता है।

मुख्य कोड हमेशा एक फ़ंक्शन पॉइंटर जैसे के माध्यम से निष्पादित होता है


   codec->computed_idct(blocks); 

लेकिन फ़ंक्शन पॉइंटर्स को उदाहरण के प्रकार के आधार पर परिभाषित किया जाता है (उदाहरण के लिए यहां निष्क्रिय फ़ंक्शन विभिन्न सीपीयू वास्तुकला के लिए अनुकूलित है।



if(OPTIMIZE_X86) {
  codec->computed_idct = compute_idct_x86; 
}
else if(OPTIMZE_ARM) {
  codec->computed_idct = compute_idct_ARM;
}
else {
  codec->computed_idct = compute_idct_C; 
}

आपको libjpeg कोड और libmpeg2 कोड देखना चाहिए और ऐसी तकनीकों के लिए ffmpeg हो सकता है ।


6

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

मैंने पाया है कि इस कदम को सफलतापूर्वक पूरा करने में तीन आवश्यक तत्व हैं

  1. इस्तेमाल किया एल्गोरिथ्म बिल्कुल स्पष्ट होना चाहिए।
  2. कार्यान्वयन की प्रत्येक पंक्ति का उद्देश्य स्पष्ट होना चाहिए।
  3. अपेक्षित परिणामों से विचलन को जल्द से जल्द पहचाना जाना चाहिए।

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

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

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

मेरी सबसे हार्दिक सिफारिश है कि किसी भी कदम पर कंजूसी न करें। आपको बाद में उनकी आवश्यकता होगी;)


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

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

सबसे पहले, मैं स्वचालित परीक्षण, अस्थायी बिंदु अंकगणित और समानांतर कोड के बारे में आपका दर्द महसूस करता हूं। मुझे डर है कि कोई समाधान नहीं है जो सभी मामलों के लिए मान्य है। आमतौर पर मैं काफी उदार सहिष्णुता के साथ काम करता हूं, लेकिन आपके उद्योग में यह संभव नहीं है।
9x पर drxzcl

2
व्यवहार में व्हाइटपॉपर अक्सर "फुल" भागों (कोई सार्थक परिचय, कोई अमूर्त, न्यूनतम निष्कर्ष / चर्चा नहीं करता है और केवल संदर्भ जो इसे समझने के लिए आवश्यक हैं) के बिना एक वैज्ञानिक कागज के पहले मसौदे की तरह दिखता है। मैं कागज को रिपोर्ट की एक रिपोर्ट के रूप में, और एल्गोरिथ्म विकास और / या एल्गोरिथ्म चयन का एक अभिन्न अंग देखता हूं। आपने इस एल्गोरिथम (वर्णक्रमीय FFT कहना) को लागू करना चुना। हकीकत में यह क्या है? आपने इसे दूसरों के ऊपर क्यों चुना? इसके समांतर लक्षण क्या हैं? प्रयास चयन / विकास कार्य के साथ आनुपातिक होना चाहिए।
drxzcl 10

5

मेरा मानना ​​है कि इसे कोड की व्यापक टिप्पणी के माध्यम से हल किया जाना चाहिए, जहां कोड के प्रत्येक महत्वपूर्ण ब्लॉक में पहले से व्याख्यात्मक टिप्पणी है।

टिप्पणियों में विनिर्देशों या हार्डवेयर संदर्भ सामग्री के उद्धरण शामिल होने चाहिए।

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

मैं आपके चेहरे के चर नामकरण का उपयोग यह सुनिश्चित करने के लिए करूंगा कि क्या चल रहा है। हंगेरियन नहीं, लेकिन दो ऊर्ध्वाधर पिक्सेल के बीच बाइट्स में दूरी का वर्णन करने के लिए 'स्ट्राइड' जैसी चीजें।

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


1
एक ही परियोजना के लिए एक ही चीज़ (जैसे "स्ट्राइड" का उपयोग करके एक ही शब्द के लिए एक सुसंगत शब्दावली का उपयोग करना) जैसे कि एक ही परियोजना में "चरण", "संरेखण") से मदद मिलेगी। एक प्रोजेक्ट में कई प्रोजेक्ट के कोड आधार को एकीकृत करते समय यह कुछ मुश्किल है।
rwong
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.