assembly - आधुनिक सुपरसक्लेर प्रोसेसर पर परिचालन के लिए विलंबता की भविष्यवाणी में क्या विचार आते हैं और मैं उन्हें कैसे हाथ से गणना कर सकता हूं?



x86-64 pipeline (1)

संबंधित: प्रत्येक विधानसभा निर्देश के लिए कितने सीपीयू चक्र की आवश्यकता होती है? प्रति निर्देश के आधार पर थ्रूपुट बनाम विलंबता का एक अच्छा परिचय है, और कई निर्देशों के अनुक्रम के लिए इसका क्या मतलब है।

इसे स्थैतिक (प्रदर्शन) विश्लेषण कहा जाता है। विकिपीडिया कहता है ( https://en.wikipedia.org/wiki/List_of_performance_analysis_tools ) कि एएमडी के एएमडी कोडएक्सएल में एक "स्टैटिक कर्नेल विश्लेषक" (यानी कम्प्यूटेशनल कर्नेल, उर्फ ​​छोरों के लिए) है। मैंने कभी कोशिश नहीं की।

इंटेल के पास यह विश्लेषण करने के लिए एक नि: शुल्क टूल भी है कि सैंडिब्रिज -परिवार सीपीयू में पाइप लाइन के माध्यम से कैसे जाएंगे: IACA क्या है और मैं इसका उपयोग कैसे करूं?

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

स्थैतिक विश्लेषण अक्सर बहुत अच्छा होता है, लेकिन निश्चित रूप से प्रदर्शन काउंटर के साथ प्रोफाइलिंग करके जांच करें। क्या x86 का MOV वास्तव में "मुक्त" हो सकता है? मैं यह सब क्यों नहीं कर सकता? एक सूक्ष्म पाश की जांच करने के लिए एक साधारण लूप की रूपरेखा के उदाहरण के लिए।

आवश्यक पढ़ना:

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

उनके माइक्रो गाइड के बाद के अध्याय सीपीयू में पाइपलाइनों के विवरण को कवर करते हैं जैसे कि नेहेल्म, सैंडब्रिज, हैसवेल, K8 / K10, बुलडोजर, और रायज़ेन। (और एटम / सिल्वरमोंट / जगुआर)।

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

डेविड कैंटर का माइक्रार्क विश्लेषण डॉक्स के साथ बहुत अच्छे हैं। जैसे https://www.realworldtech.com/sandy-bridge/ , https://www.realworldtech.com/haswell-cpu/ , और https://www.realworldtech.com/bulldozer/

X86 टैग विकी में अन्य प्रदर्शन लिंक भी देखें।

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

इंटेल शब्दावली में :

  • "जारी" का अर्थ कोर के आउट-ऑफ-ऑर्डर भाग में एक ऊप्स भेजना है; रजिस्टर-रीनेमिंग के साथ, यह फ्रंट-एंड में अंतिम चरण है। समस्या / नाम बदलें चरण अक्सर पाइपलाइन में सबसे संकीर्ण बिंदु होता है, जैसे Core2 के बाद इंटेल पर 4-चौड़ा। (बाद में हसवेल और विशेष रूप से स्काईलेक जैसे यूरेश के साथ वास्तव में कुछ वास्तविक कोड में बहुत करीब आ रहे हैं, एसकेएल के बेहतर डिकोडर्स और यूओपी-कैश बैंडविड्थ के साथ-साथ बैक-एंड और कैश बैंडविड्थ में सुधार के लिए धन्यवाद।) यह फ्यूजन-डोमेन यूओपी है। : माइक्रो-फ्यूजन आपको फ्रंट-एंड के माध्यम से 2 यूओपी भेजने और केवल एक आरओबी प्रविष्टि लेने की सुविधा देता है। (मैं स्काइलेक पर एक लूप का निर्माण करने में सक्षम था जो प्रति घड़ी 7 अप्रयुक्त-डोमेन यूपीएस को बनाए रखता है )। http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ re: आउट-ऑफ-ऑर्डर विंडो का आकार भी देखें।

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

कई अन्य कंप्यूटर-आर्किटेक्चर साहित्य विपरीत अर्थों में इन शब्दों का उपयोग करते हैं, लेकिन यह वह शब्दावली है जो आप इंटेल के अनुकूलन मैनुअल में पाएंगे, और uops_issued.any या uops_dispatched_port.port_5 जैसे हार्डवेयर प्रदर्शन काउंटरों के नाम।

ठीक उसी तरह जब तक मनमानी अंकगणित x86-64 विधानसभा कोड ले जाएगा

यह OoO निष्पादन के कारण, आस-पास के कोड पर भी निर्भर करता है

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

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

एक छोटे ब्लॉक के लिए विश्लेषण करने के लिए तीन प्रमुख आयाम हैं

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

  • प्रत्येक इनपुट से आउटपुट के लिए विलंबता । देखें कि कौन से निर्देश प्रत्येक इनपुट से प्रत्येक आउटपुट पर निर्भरता श्रृंखला पर हैं। उदाहरण के लिए एक विकल्प को जल्द तैयार होने के लिए एक इनपुट की आवश्यकता हो सकती है।
  • इंटेल सीपीयू पर फ़्यूज़ -डोमेन की कुल यूओपी गणना (फ्रंट-एंड थ्रूपुट बाधाओं के लिए) । जैसे Core2 और बाद में सिद्धांत में जारी कर सकते हैं / आउट-ऑफ-ऑर्डर शेड्यूलर / आरओबी में प्रति घड़ी 4 फ़्यूज़-डोमेन ऊप्स नाम बदल सकते हैं। सैंडब्रिज-परिवार अक्सर यूओपी कैश और लूप बफर के साथ अभ्यास कर सकते हैं, विशेष रूप से स्काईलेक अपने बेहतर डिकोडर और यूओपी-कैश थ्रूपुट के साथ।
  • प्रत्येक बैक-एंड निष्पादन पोर्ट (अप्रयुक्त डोमेन) के लिए यूओपी गणना । उदाहरण के लिए शफल-भारी कोड अक्सर इंटेल सीपीयू पर पोर्ट 5 पर टोंटी जाएगा। इंटेल आमतौर पर केवल थ्रूपुट नंबर प्रकाशित करता है, पोर्ट ब्रेकडाउन नहीं, यही वजह है कि आपको एगनर फॉग के टेबल (या IACA आउटपुट) को कुछ भी सार्थक करने के लिए देखना होगा यदि आप एक ही निर्देश को दोहराते नहीं हैं।

    आम तौर पर आप सबसे अच्छा शेड्यूलिंग / वितरण मान सकते हैं, यूओपी के साथ जो अन्य बंदरगाहों पर चल सकता है व्यस्त बंदरगाहों को बहुत बार चोरी नहीं करता है, लेकिन ऐसा कुछ होता है। ( X86 यूओपी कैसे अनुसूचित हैं, बिल्कुल? )

    सीपीआई को देखना पर्याप्त नहीं है ; दो CPI = 1 निर्देश समान निष्पादन पोर्ट के लिए प्रतिस्पर्धा कर सकते हैं या नहीं भी कर सकते हैं। यदि वे नहीं करते हैं, तो वे समानांतर में निष्पादित कर सकते हैं। जैसे हैसवेल केवल पोर्ट 0 (5 सी विलंबता, 1 सी थ्रूपुट, सीपीआई = 1) पर psadbw चला सकते हैं, लेकिन यह एक एकल है ताकि 1 psadbw + 3 के मिश्रण का मिश्रण प्रति घड़ी 4 निर्देशों को बनाए रख सके। इंटेल सीपीयू में 3 अलग-अलग बंदरगाहों पर वेक्टर ALU हैं, कुछ ऑपरेशनों के साथ सभी 3 (उदाहरण के लिए बूलियन्स) और कुछ केवल एक पोर्ट (जैसे स्काईलेक से पहले पाली) पर दोहराया गया है।

कभी-कभी आप कुछ अलग-अलग रणनीतियों के साथ आ सकते हैं, एक शायद कम विलंबता लेकिन अधिक ऊप्स लागत। एक उत्कृष्ट उदाहरण imul eax, ecx, 10 (1 यूओपी, इंटेल पर 3 सी विलंबता) बनाम lea eax, [rcx + rcx*4] / add eax,eax ईएक्सएक्स, ईएक्सएक्स (2 हॉप, 2 सी विलंबता) जैसे स्थिरांक द्वारा गुणा कर रहा है । आधुनिक कंपाइलर 2 LEA बनाम 1 IMUL का चयन करते हैं, हालांकि 3.7 इष्ट IMUL तक क्लैग होता है जब तक कि यह केवल एक अन्य निर्देश के साथ काम नहीं कर सकता।

देखें कि एक स्थिति या निचले स्तर पर सेट बिट्स की गणना करने का कुशल तरीका क्या है? किसी कार्य को कार्यान्वित करने के कुछ अलग तरीकों के लिए स्थैतिक विश्लेषण का एक उदाहरण।

यह भी देखें कि एगनर के निर्देश तालिकाओं से अलग, हवेलवेल पर केवल 3 चक्र क्यों लगते हैं? (जो कि आपके द्वारा प्रश्न शीर्षक से अधिक विस्तृत तरीके से समाप्त हो रहा है) स्थैतिक विश्लेषण के एक और सारांश के लिए, और एक कमी के लिए कई संचयकों के साथ घूमने के बारे में कुछ साफ सामान।

हर (?) फंक्शनल यूनिट को पाइपलाइन किया जाता है

डिवाइडर को हाल के सीपीयू में पाइपलाइन किया गया है, लेकिन पूरी तरह से पाइपलाइन नहीं किया गया है। (FP divide सिंगल-यूओपी है, हालांकि, यदि आप दर्जनों mulps / addps साथ मिश्रित एक divps करते हैं, तो यह addps थ्रूपुट प्रभाव को प्रभावित कर सकता है यदि विलंबता कोई फर्क नहीं पड़ता: फ़्लोटिंग पॉइंट डिवीजन बनाम फ़्लोटिंग पॉइंट गुणन rcpps + a न्यूटन पुनरावृत्ति बदतर है और एक ही विलंबता के बारे में है।

बाकी सब कुछ मुख्यधारा के इंटेल सीपीयू पर पूरी तरह से पाइपलाइन है; एक एकल के लिए बहु-चक्र (पारस्परिक) थ्रूपुट। (चर-गणना पूर्णांक की तरह shl eax, cl में उनके 3 uops के लिए निम्न-से-प्रत्याशित थ्रूपुट होता है, क्योंकि वे फ़्लैग-मर्जिंग uops के माध्यम से एक निर्भरता बनाते हैं। लेकिन अगर आप FLAGS के माध्यम से उस निर्भरता को एक add या कुछ और के साथ तोड़ते हैं, तो आप। बेहतर थ्रूपुट और विलंबता प्राप्त कर सकते हैं।)

Ryzen से पहले Ryzen पर, पूर्णांक गुणक भी केवल आंशिक रूप से पाइपलाइज्ड होता है। उदाहरण के लिए बुलडोजर का imul ecx, edx केवल 1 यूओपी है, लेकिन 4 सी विलंबता, 2 सी थ्रूपुट के साथ।

Xeon Phi (KNL) में भी कुछ पूरी तरह से पिपलाइज़ किए गए फेरबदल निर्देश नहीं हैं, लेकिन यह बैक-एंड नहीं, फ्रंट-एंड (अनुदेश डिकोड) पर टोंटी को जाता है, और वापस छिपाने के लिए एक छोटे बफर / OoO निष्पादन क्षमता है -बेंड बुलबुले।

यदि यह फ़्लोटिंग-पॉइंट निर्देश है, तो जारी करने से पहले प्रत्येक फ़्लोटिंग-पॉइंट निर्देश (फ़्लोटिंग-पॉइंट निर्देशों में स्थैतिक निर्देश पुन: आदेश है)

नहीं।

हो सकता है कि आप पढ़ते हों सिल्वरमोंट के लिए, जो एफपी / सिमडी के लिए ओओओ निष्पादन नहीं करता है, केवल पूर्णांक (एक छोटी ~ 20 यूओपी खिड़की के साथ)। हो सकता है कि कुछ एआरएम चिप्स उस तरह के हों, जो कि नियॉन के लिए सरल शेड्यूलर के साथ भी हैं? मुझे ARM के बारे में ज्यादा जानकारी नहीं है।

P6 / SnB- परिवार, और सभी AMD OOO चिप्स जैसे मुख्यधारा के बड़े-कोर माइक्रोआर्किटेक्चर, ODO को SIMD के लिए निष्पादित करते हैं और FP पूर्णांक के लिए निर्देश देते हैं। AMD CPU एक अलग शेड्यूलर का उपयोग करते हैं, लेकिन Intel एक एकीकृत शेड्यूलर का उपयोग करता है इसलिए इसका पूर्ण आकार ILP को पूर्णांक या FP कोड में खोजने के लिए लागू किया जा सकता है, जो भी वर्तमान में चल रहा है।

यहां तक ​​कि सिल्वरमोंट स्थित नाइट की लैंडिंग (एक्सोन फी में) ओएमओ को SIMD के लिए निष्पादित करता है।

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

हसवेल के लिए विलंबता की भविष्यवाणी करने का मेरा प्रयास कुछ इस तरह है:

हाँ, यह सही लग रहा है। shufps पोर्ट 5 पर चलता है, addps p1 पर चलता है, mulps p0 या p1 पर चलता है। Skylake समर्पित FP- ऐड यूनिट को ड्राप करता है और P0 / p1 पर FMA इकाइयों पर SIMD FP ऐड / mul / FMA चलाता है, सभी 4c विलंबता के साथ (ऊपर / नीचे 3/5/5 से हैसवेल में, या 3/3/5 में) Broadwell)।

यह एक अच्छा उदाहरण है कि एक SIMD वेक्टर में आमतौर पर पूरे XYZ दिशा वेक्टर को क्यों रखा जाता है। एक्स की एक सरणी, वाई की एक सरणी, और जेड की एक सरणी को ध्यान में रखते हुए, आपको बिना किसी फेरबदल के समानांतर 4 क्रॉस उत्पाद करने देगा।

SSE टैग विकी में इन स्लाइड्स का लिंक होता है: Insomniac Games (GDC 2015) में SIMD, जो 3D वैक्टर के लिए उस सरणी-ऑफ-स्ट्रक्चर बनाम स्ट्रक्चर-ऑफ-एरे मुद्दों को कवर करता है, और क्यों यह हमेशा SIMD के लिए प्रयास करने के लिए एक गलती है। समानांतर में कई ऑपरेशन करने के लिए SIMD का उपयोग करने के बजाय एक एकल ऑपरेशन।

मैं हाथ से, वास्तव में कितनी देर की मनमानी अंकगणित (यानी कोई शाखा या स्मृति, हालांकि यह भी अच्छा होगा) का अनुमान लगाने में सक्षम होना चाहता हूं, x86-64 विधानसभा कोड एक विशेष आर्किटेक्चर को ध्यान में रखेगा, निर्देश निर्देशन, सुपरसक्लेरिटी को ध्यान में रखते हुए, विलंबता, CPI, आदि

इसे प्राप्त करने के लिए नियमों का क्या / क्या वर्णन करना चाहिए?

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

कम से कम, मैं (1) पुष्टि की तलाश कर रहा हूं कि प्रत्येक नियम सही है या प्रत्येक नियम का एक सही कथन है, और (2) किसी भी नियम की एक सूची जिसे मैं भूल गया हूं।

  • संभव के रूप में कई निर्देश प्रत्येक चक्र जारी किए जाते हैं, वर्तमान चक्र से इन-ऑर्डर शुरू करते हैं और संभावित रूप से आगे तक बफर बफर आकार।
  • दिए गए चक्र पर एक निर्देश जारी किया जा सकता है यदि:
    • इसके संचालन को प्रभावित करने वाले कोई भी निर्देश अभी भी निष्पादित नहीं किए जा रहे हैं। तथा:
    • यदि यह फ़्लोटिंग-पॉइंट इंस्ट्रक्शन है, तो जारी करने से पहले प्रत्येक फ़्लोटिंग-पॉइंट इंस्ट्रक्शन (फ़्लोटिंग-पॉइंट निर्देशों में स्थैतिक निर्देश पुन: आदेश है)। तथा:
    • उस चक्र पर उस निर्देश के लिए एक कार्यात्मक इकाई उपलब्ध है। हर (?) फंक्शनल यूनिट को पाइपलाइज्ड किया जाता है, जिसका अर्थ है कि यह प्रति चक्र 1 नया निर्देश स्वीकार कर सकता है, और कुल फंक्शनल यूनिट की संख्या 1 / CPI है, किसी दिए गए फंक्शन क्लास के CPI के लिए ( addps यहाँ: संभवतः उदाहरण के लिए addps और subps उपयोग करें) एक ही कार्यात्मक इकाई? मैं इसे कैसे निर्धारित करूँ?)। तथा:
    • सुपरस्क्लेयर चौड़ाई (आमतौर पर 4 ) की तुलना में कम निर्देश इस चक्र को पहले ही जारी किए जा चुके हैं।
  • यदि कोई निर्देश जारी नहीं किया जा सकता है, तो प्रोसेसर किसी भी स्थिति को जारी नहीं करता है - एक शर्त जिसे "स्टाल" कहा जाता है।

एक उदाहरण के रूप में, निम्नलिखित उदाहरण कोड पर विचार करें (जो एक क्रॉस-उत्पाद की गणना करता है):

shufps   xmm3, xmm2, 210
shufps   xmm0, xmm1, 201
shufps   xmm2, xmm2, 201
mulps    xmm0, xmm3
shufps   xmm1, xmm1, 210
mulps    xmm1, xmm2
subps    xmm0, xmm1

हसवेल के लिए विलंबता की भविष्यवाणी करने का मेरा प्रयास कुछ इस तरह है:

; `mulps`  Haswell latency=5, CPI=0.5
; `shufps` Haswell latency=1, CPI=1
; `subps`  Haswell latency=3, CPI=1

shufps   xmm3, xmm2, 210   ; cycle  1
shufps   xmm0, xmm1, 201   ; cycle  2
shufps   xmm2, xmm2, 201   ; cycle  3
mulps    xmm0, xmm3        ;   (superscalar execution)
shufps   xmm1, xmm1, 210   ; cycle  4
mulps    xmm1, xmm2        ; cycle  5
                           ; cycle  6 (stall `xmm0` and `xmm1`)
                           ; cycle  7 (stall `xmm1`)
                           ; cycle  8 (stall `xmm1`)
subps    xmm0, xmm1        ; cycle  9
                           ; cycle 10 (stall `xmm0`)




superscalar