प्रतिनिधि इंटरव्यू विषय

C++ कोडिंग साक्षात्कार: C++26 std::simd के साथ पोर्टेबल वेक्टराइज़्ड कोड कैसे लिखेंगे?

कोडिंगकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

N फ्लोट्स पर एलिमेंट-वाइज़ ट्रांसफ़ॉर्म लागू करें, अधिमानतः C++26 std::simd के साथ, जबकि N के वेक्टर-चौड़ाई का गुणज न होने या रनटाइम हार्डवेयर के अनुपयुक्त होने पर भी शुद्धता बनी रहे। मास्क, टेल, अलाइनमेंट, अपवादात्मक मान, कंपाइलर समर्थन और प्रदर्शन प्रमाण की व्याख्या करें।

प्रॉम्प्ट और संदर्भ

एक ऐसे ऐरे पर y[i] = a * x[i] + b लागू करें जहाँ N वेक्टर चौड़ाई का गुणज नहीं हो सकता है और इनपुट में NaN हो सकता है। C++26 डेटा-पैरेलल प्रकारों का उपयोग करें और टेल, अलाइनमेंट, मास्क, कंपाइलर समर्थन, स्केलर फ़ॉलबैक की व्याख्या करें, और यह बताएं कि आप यह कैसे साबित करते हैं कि ऑप्टिमाइज़ेशन मदद करता है।

साक्षात्कारकर्ता क्या जांचता है

  • क्या आप जानते हैं कि std::simd एक पोर्टेबल डेटा-पैरेलल एब्स्ट्रैक्शन है, किसी एक निश्चित निर्देश की गारंटी नहीं।
  • क्या आप वेक्टर मानों, मास्क, निश्चित आकार और नेटिव चौड़ाई में अंतर करते हैं, और आंशिक अंतिम बैच को संभालते हैं।
  • क्या आप गलत अलाइनमेंट मान्यताओं, अलियासिंग उल्लंघनों, आउट-ऑफ-बाउंड्स एक्सेस और गलत NaN व्यवहार से बचते हैं।
  • क्या आप फ़ीचर टेस्टिंग और फ़ॉलबैक पाथ तैयार करते हैं जबकि C++26 और टूलचेन समर्थन अभी भी असमान हैं।
  • क्या आप केवल सोर्स कोड से गति का दावा करने के बजाय बेंचमार्क, शुद्धता परीक्षण और हार्डवेयर काउंटरों का उपयोग करते हैं।

स्पष्टीकरण के लिए प्रश्न

  1. क्या लक्षित कंपाइलर और मानक लाइब्रेरी C++26 simd हेडर को लागू करते हैं, या केवल एक प्रयोगात्मक नेमस्पेस को?
  2. क्या इनपुट और आउटपुट अलियास हो सकते हैं, और NaN, अनंत (infinity), और राउंडिंग आवश्यकताएं क्या हैं?
  3. N रेंज, तत्व प्रकार, त्रुटि सहनशीलता और लक्षित CPU/GPU निर्देश सेट क्या हैं?
  4. क्या लूप मेमोरी-बैंडविड्थ बाउंड है, और क्या इसकी कॉल आवृत्ति वेक्टराइज़ेशन जटिलता को सही ठहराने के लिए पर्याप्त उच्च है?
  5. क्या एक निश्चित ABI चौड़ाई आवश्यक है, या कार्यान्वयन लक्षित हार्डवेयर के लिए नेटिव चौड़ाई चुन सकता है?

30-सेकंड उत्तर रूपरेखा

"मैं पहले simd हेडर कार्यान्वयन और संख्यात्मक अनुबंध की पुष्टि करूँगा, फिर std::simd के साथ एक बैच लोड करूँगा, मल्टीप्लाई-ऐड लागू करूँगा, और इसे स्टोर करूँगा। मुख्य लूप पूर्ण वेक्टर को संभालता है; एक मास्क या स्केलर लूप बिना आउट-ऑफ-बाउंड्स एक्सेस के टेल को संभालता है। लोड टैग एक कल्पित कास्ट के बजाय वास्तविक अलाइनमेंट से मेल खाना चाहिए। मैं एक स्केलर संदर्भ रखूँगा और फ़ीचर परीक्षणों और एक बिल्ड मैट्रिक्स के साथ C++26, एक प्रयोगात्मक कार्यान्वयन, या स्केलर फ़ॉलबैक का चयन करूँगा। अंत में, मैं समान इनपुट पर NaN, त्रुटि, और सीमा व्यवहार का परीक्षण करूँगा और एक निश्चित बेंचमार्क और हार्डवेयर काउंटरों के साथ थ्रूपुट और बैंडविड्थ की तुलना करूँगा।"

चरण-दर-चरण गहन विश्लेषण

1. डेटा-पैरेलल एब्स्ट्रैक्शन चुनें

C++26 डेटा-पैरेलल प्रकार कई तत्वों पर एक ऑपरेशन व्यक्त करने के लिए वेक्टर मान और मास्क प्रदान करते हैं। std::simd की लेन गणना कार्यान्वयन और लक्षित हार्डवेयर द्वारा चुनी जाती है; केवल तभी एक निश्चित आकार का प्रकार चुनें जब लेआउट या इंटरफ़ेस स्थिरता की आवश्यकता हो। मानक एब्स्ट्रैक्शन कंपाइलर को SIMD रजिस्टरों या किसी अन्य उपयुक्त कार्यान्वयन में मैप करने की अनुमति देता है।

2. पूर्ण-बैच लूप लिखें

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

cpp
template<class V>
void axpb_simd(const float* x, float* y, std::size_t n, float a, float b) {
  const V va(a), vb(b);
  std::size_t i = 0;
  for (; i + V::size() <= n; i += V::size()) {
    V vx(&x[i], std::element_aligned_tag{});
    (vx * va + vb).copy_to(&y[i], std::element_aligned_tag{});
  }
  for (; i < n; ++i) y[i] = a * x[i] + b;
}

3. टेल के लिए मास्क का उपयोग करें

एक स्केलर टेल लूप का ऑडिट करना सबसे आसान है। यदि टेल सामान्य हैं, तो एक सक्रिय मास्क बनाएं और केवल वैध लेनों को लोड और स्टोर करें। मास्क को रीड और राइट दोनों को बाधित करना चाहिए ताकि निष्क्रिय लेन आउट-ऑफ-बाउंड्स एक्सेस या साइड इफेक्ट्स का कारण न बन सकें। कुछ स्केलर पुनरावृत्तियों को हटाने के लिए सीमा स्पष्टता का त्याग न करें।

4. NaN, त्रुटि, और अपवाद सिमेंटिक्स को परिभाषित करें

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

5. मानकीकृत और फ़ॉलबैक पाथ प्रदान करें

C++26 simd हेडर का फ़ीचर-टेस्ट मैक्रो __cpp_lib_simd है, लेकिन टूलचेन समर्थन पिछड़ सकता है। क्षमता का पता लगाने के बाद, बिल्ड को मानक प्रकारों, किसी कार्यान्वयन के प्रयोगात्मक इंटरफ़ेस, या स्केलर टेम्पलेट का चयन करना चाहिए। सार्वजनिक API में कंपाइलर-निजी वेक्टर प्रकार को उजागर न करें। प्रत्येक पाथ को समान शुद्धता परीक्षण चलाने चाहिए।

6. प्रदर्शन और सीमाओं को साबित करें

स्केलर, SIMD और विभिन्न चौड़ाई की तुलना करने वाले बेंचमार्क में N, डेटा वितरण, कंपाइलर विकल्प और थ्रेड गणना को स्थिर करें। थ्रूपुट, विलंबता, कैश मिस, वेक्टर-निर्देश अनुपात और मेमोरी बैंडविड्थ रिकॉर्ड करें; N=1,000, खाली इनपुट, अनअलाइन्ड एड्रेस और NaN डेटा का अलग-अलग परीक्षण करें। यदि मेमोरी बैंडविड्थ या कॉल ओवरहेड बाधा है, तो SIMD मदद नहीं कर सकता है और सरल कार्यान्वयन बना रहना चाहिए।

मजबूत नमूना उत्तर

"मैं std::simd को एक पोर्टेबल डेटा-पैरेलल एब्स्ट्रैक्शन के रूप में मानता हूँ और एक निश्चित लेन गणना या निर्देश नहीं मानता। मुख्य लूप V::size() पूर्ण बैचों को प्रोसेस करता है और उन ऐरे के लिए element_aligned_tag का उपयोग करता है जो अनअलाइन्ड हो सकते हैं; टेल एक स्केलर लूप या एक मास्क का उपयोग करता है जो रीड और राइट को बाधित करता है। मैं पहले अलियासिंग, NaN प्रसार और त्रुटि आवश्यकताओं को परिभाषित करता हूँ, फिर फ़ीचर परीक्षणों के साथ C++26, एक प्रयोगात्मक कार्यान्वयन, या एक स्केलर टेम्पलेट का चयन करता हूँ। मैं N=1,000, खाली इनपुट, अनअलाइन्ड एड्रेस और NaN का परीक्षण करता हूँ, और हार्डवेयर काउंटरों के साथ थ्रूपुट, कैश व्यवहार और बैंडविड्थ की तुलना करता हूँ। यदि मेमोरी लूप को सीमित करती है, तो मैं वेक्टराइज़ेशन को बाध्य नहीं करता।"

सामान्य गलतियाँ

  • std::simd को एक निश्चित-चौड़ाई वाला रजिस्टर मानना → कोड एक CPU पर निर्भर करता है → कार्यान्वयन-चयनित या स्पष्ट रूप से निश्चित चौड़ाई का जानबूझकर उपयोग करें।
  • टेल के लिए एक पूर्ण वेक्टर लोड करना → आउट-ऑफ-बाउंड्स एक्सेस → एक मास्क या स्केलर टेल लूप का उपयोग करें।
  • अलाइनमेंट मान लेना → अपरिभाषित व्यवहार या धीमा लोड → लोड टैग को वास्तविक गारंटी से मिलाएं।
  • केवल औसत मानों की तुलना करना → NaN, अनंत, और राउंडिंग अंतर गायब हो जाते हैं → विशेष-मान और त्रुटि अनुबंधों को परिभाषित करें।
  • वेक्टर निर्देश देखने के बाद सफलता की घोषणा करना → मेमोरी बैंडविड्थ हावी हो सकती है → निश्चित बेंचमार्क और काउंटरों के साथ इसे साबित करें।

फॉलो-अप और प्रतिक्रियाएं

आप निश्चित बनाम नेटिव चौड़ाई कैसे चुनते हैं?

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

टेल के लिए हमेशा मास्क का उपयोग क्यों नहीं करते?

एक मास्क लूप के आकार को एक जैसा रखता है लेकिन कंस्ट्रक्शन, लोड और स्टोर ओवरहेड जोड़ सकता है। एक छोटे टेल को स्केलर कोड के साथ ऑडिट करना आसान होता है; जब टेल अनुपात महत्वपूर्ण हो तो मापे गए मास्क और स्केलर टेल की तुलना करें।

आप कैसे साबित करते हैं कि कंपाइलर ने लूप को स्केलराइज़ नहीं किया?

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

क्या होगा यदि प्रोडक्शन कंपाइलर में simd हेडर अनुपलब्ध है?

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

सार्वजनिक स्रोत

संबंधित प्रश्न

संबंधित इंटरव्यू टूल

कोडिंग प्रॉम्प्ट के लिए स्क्रीनशॉट का उपयोग करें

समस्या को कैप्चर करें, फिर क्रम से प्रतिबंधों (constraints), समाधान, कोड, एज केस और जटिलता पर काम करें।

टूल देखें