2015-12-03 4 views
15

वेक्टरिंग कोड के दौरान कैश की संख्या में वृद्धि हुई है, मैंने एसएसई 4.2 और एवीएक्स 2 के साथ 2 वैक्टरों के बीच डॉट उत्पाद को सदिशित किया है, जैसा कि आप नीचे देख सकते हैं। कोड को ओओसी अनुकूलन ध्वज के साथ जीसीसी 4.8.4 के साथ संकलित किया गया था। जैसा कि उम्मीद है कि प्रदर्शन दोनों (और एसईएस 4.2 की तुलना में एवीएक्स 2 तेज) के साथ बेहतर हो गया था, लेकिन जब मैंने पीएपीआई के साथ कोड का प्रोफाइल किया, तो मुझे पता चला कि मिस की कुल संख्या (मुख्य रूप से एल 1 और एल 2) बहुत बढ़ी है:कोड

vectorization के बिना:

PAPI_L1_TCM: 784,112,091 
PAPI_L2_TCM: 195,315,365 
PAPI_L3_TCM: 79,362 
SSE 4.2 के साथ

:

PAPI_L1_TCM: 1,024,234,171 
PAPI_L2_TCM: 311,541,918 
PAPI_L3_TCM: 68,842 
avx 2 के साथ

:

PAPI_L1_TCM: 2,719,959,741 
PAPI_L2_TCM: 1,459,375,105 
PAPI_L3_TCM: 108,140 

क्या मेरे कोड में कुछ गड़बड़ हो सकती है या इस प्रकार का व्यवहार सामान्य है?

avx 2 कोड:

double vec_dotProduct(const vec& vecs, const unsigned int& start_a, const unsigned int& start_b, const int& n) { 
    double dot = 0; 
    register int i = 0; 
    const int loopBound = n-3; 

    __m256d vsum, vecPi, vecCi, vecQCi; 

    vsum = _mm256_set1_pd(0); 

    double * const pA = vecs.x+start_a ; 
    double * const pB = vecs.x+start_b ; 

    for(; i<loopBound ;i+=4){ 
     vecPi = _mm256_loadu_pd(&(pA)[i]); 
     vecCi = _mm256_loadu_pd(&(pB)[i]); 
     vecQCi = _mm256_mul_pd(vecPi,vecCi); 
     vsum = _mm256_add_pd(vsum,vecQCi); 
    } 

    vsum = _mm256_hadd_pd(vsum, vsum); 

    dot = ((double*)&vsum)[0] + ((double*)&vsum)[2]; 

    for(; i<n; i++) 
     dot += pA[i] * pB[i]; 

    return dot; 
} 

SSE 4.2 कोड:

double vec_dotProduct(const vec& vecs, const unsigned int& start_a, const unsigned int& start_b, const int& n) { 
    double dot = 0; 
    register int i = 0; 

    const int loopBound = n-1; 

    __m128d vsum, vecPi, vecCi, vecQCi; 

    vsum = _mm_set1_pd(0); 

    double * const pA = vecs.x+start_a ; 
    double * const pB = vecs.x+start_b ; 

    for(; i<loopBound ;i+=2){ 
     vecPi = _mm_load_pd(&(pA)[i]); 
     vecCi = _mm_load_pd(&(pB)[i]); 
     vecQCi = _mm_mul_pd(vecPi,vecCi); 
     vsum = _mm_add_pd(vsum,vecQCi); 
    } 

    vsum = _mm_hadd_pd(vsum, vsum); 

    _mm_storeh_pd(&dot, vsum); 

    for(; i<n; i++) 
     dot += pA[i] * pB[i]; 

    return dot; 
} 

गैर vectorized कोड:

double dotProduct(const vec& vecs, const unsigned int& start_a, const unsigned int& start_b, const int& n) { 
    double dot = 0; 
    register int i = 0; 

    for (i = 0; i < n; ++i) 
    { 
     dot += vecs.x[start_a+i] * vecs.x[start_b+i]; 
    } 
    return dot; 
} 

संपादित करें: गैर vectorized कोड की सभा:

0x000000000040f9e0 <+0>:  mov (%rcx),%r8d 
    0x000000000040f9e3 <+3>:  test %r8d,%r8d 
    0x000000000040f9e6 <+6>:  jle 0x40fa1d <dotProduct(vec const&, unsigned int const&, unsigned int const&, int const&)+61> 
    0x000000000040f9e8 <+8>:  mov (%rsi),%eax 
    0x000000000040f9ea <+10>: mov (%rdi),%rcx 
    0x000000000040f9ed <+13>: mov (%rdx),%edi 
    0x000000000040f9ef <+15>: vxorpd %xmm0,%xmm0,%xmm0 
    0x000000000040f9f3 <+19>: add %eax,%r8d 
    0x000000000040f9f6 <+22>: sub %eax,%edi 
    0x000000000040f9f8 <+24>: nopl 0x0(%rax,%rax,1) 
    0x000000000040fa00 <+32>: mov %eax,%esi 
    0x000000000040fa02 <+34>: lea (%rdi,%rax,1),%edx 
    0x000000000040fa05 <+37>: add $0x1,%eax 
    0x000000000040fa08 <+40>: vmovsd (%rcx,%rsi,8),%xmm1 
    0x000000000040fa0d <+45>: cmp %r8d,%eax 
    0x000000000040fa10 <+48>: vmulsd (%rcx,%rdx,8),%xmm1,%xmm1 
    0x000000000040fa15 <+53>: vaddsd %xmm1,%xmm0,%xmm0 
    0x000000000040fa19 <+57>: jne 0x40fa00 <dotProduct(vec const&, unsigned int const&, unsigned int const&, int const&)+32> 
    0x000000000040fa1b <+59>: repz retq 
    0x000000000040fa1d <+61>: vxorpd %xmm0,%xmm0,%xmm0 
    0x000000000040fa21 <+65>: retq 

संपादित 2: नीचे आप बड़े एन के लिए वेक्टरकृत और गैर-वेक्टरीकृत कोड के बीच एल 1 कैश मिस की तुलना पा सकते हैं (एन-लेबल पर एक्स-लेबल और एल 1 कैश मिस पर एन)। असल में, बड़े एन के लिए गैर-वेक्टरकृत संस्करण की तुलना में वेक्टरकृत संस्करण में अभी भी अधिक यादें हैं।

enter image description here

+0

आप विधानसभा को देखा है कि आपके संकलक उत्पन्न (जो संकलक आप उपयोग कर रहे, वैसे?) शायद संकलक भी अपने कोड vectorized है, लेकिन एक बेहतर काम किया है? – Rostislav

+0

@ रोस्टिस्लाव मैं जीएनयू जीसीसी 4.8.4 का उपयोग कर रहा हूं। मैं उल्लेख करना भूल गया लेकिन प्रदर्शन वास्तव में बेहतर था, भले ही मिस की संख्या अधिक थी (मैं इसे पहले पोस्ट में जोड़ दूंगा)। – fc67

+1

हमें पहले (गैर-वेक्टरीकृत) मामले के लिए जेनरेट कोड देखने की ज़रूरत होगी। –

उत्तर

0

रोस्तिस्लाव सही है कि संकलक ऑटो vectorizing है, और -O2 पर जीसीसी प्रलेखन से:।

"-O2 अनुकूलन और भी अधिक जीसीसी लगभग सभी समर्थित अनुकूलन करता है कि शामिल नहीं है एक अंतरिक्ष गति व्यापार। " (यहां से: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)

जीसीसी के साथ -O2 ध्वज कोड कोड या गति के पक्ष में सबसे कुशल कोड उत्पन्न करने का प्रयास कर रहा है।

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

इसका कारण संभवतः दो कारकों का संयोजन है।

पहला, तेज़ कोड उसी समय के भीतर मेमोरी/कैश के लिए अधिक अनुरोध उत्पन्न करता है, जो प्री-फ़ेच पूर्वानुमान भविष्यवाणी एल्गोरिदम पर जोर देता है। एल 1 कैश बहुत बड़ा नहीं है, आमतौर पर 1 एमबी - 3 एमबी, और उस सीपीयू कोर पर चल रही सभी प्रक्रियाओं के बीच साझा किया जाता है, इसलिए सीपीयू कोर पूर्व-प्राप्त नहीं हो सकता है जब तक कि पूर्व-प्रीच किए गए ब्लॉक का उपयोग नहीं किया जाता है।यदि कोड तेजी से चल रहा है, तो ब्लॉकों के बीच प्री-फ़ेच करने के लिए कम समय होता है, और पाइप-लाइनों को प्रभावी ढंग से कोड में, अधिकतर कैश मिस को लंबित fetches पूरा होने तक पूरी तरह से CPU कोर halts से पहले निष्पादित किया जाएगा।

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

1

आप कुछ टिप्पणी में देख सकते हैं, कैश छूट जाए प्रदर्शन की वृद्धि से आ रहे हैं।

उदाहरण के लिए हाल ही में सीपीयू के साथ, आप 2 AVX2 प्रत्येक चक्र में प्रत्येक चक्र में तो 512 बिट जोड़ सकते हैं या mul निष्पादित करने में सक्षम हो जाएगा। डेटा को लोड करने के लिए आपको जितना समय लगेगा उतना अधिक होगा क्योंकि इसमें कई कैश लाइनों की आवश्यकता होगी।

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

एक आखिरी बात। सीपीयू अब बहुत ही सरल लूप के साथ सरल पैटर्न को पहचानने के लिए बहुत कुशल हैं और फिर कुछ पुनरावृत्तियों के बाद स्वचालित रूप से प्रीफेच का उपयोग करेंगे। यह कैश आकार के मुद्दे को ठीक करने के लिए पर्याप्त नहीं होगा।

N के लिए अलग अलग आकार के साथ एक कोशिश है, तो आप दिलचस्प परिणाम देखना चाहिए है। इसके अलावा, पहले अपना डेटा संरेखित करें और सुनिश्चित करें कि यदि आप 2 चर का उपयोग करते हैं, तो समान कैश लाइन साझा नहीं कर रहे हैं।

+0

मैंने मूल एन के लिए मूल पोस्ट में एक ग्राफ जोड़ा और गैर-वेक्टरकृत कोड की तुलना में वेक्टरकृत कोड में हमेशा अधिक याद आती है। आप किस तरह के दिलचस्प परिणाम का जिक्र कर रहे थे? – fc67

+0

आप देख सकते हैं कि यदि सरणी काफी बड़ी है, तो आप प्रीफ़ेच का लाभ कभी नहीं प्राप्त कर सकते हैं क्योंकि सीपीयू डेटा खींचने की तुलना में बहुत तेज गणना करता है। Http: //www.google.co.uk/url? Sa = टी एंड स्रोत = वेब और RCT = जम्मू url = http: //www.akkadia.org/drepper/cpumemory.pdf&ved=0ahUKEwjcwLKaounKAhXqApoKHVdnD1YQFggaMAA&usg=AFQjCNHusTHdrOCrTp8oD3nrWSg_Pei7QA&sig2=xFu7F32Gj-kkk0w1k6Fdeg –