2015-07-15 14 views
6

मैं एक स्पैर मैट्रिक्स - वेक्टर गुणा को तेज करने के लिए नए AVX2 गेटर निर्देशों का लाभ उठाने का प्रयास कर रहा हूं। मैट्रिक्स एक पंक्ति सूचक के साथ सीएसआर (या येल) प्रारूप में है जो कॉलम इंडेक्स सरणी को इंगित करता है जो बदले में कॉलम रखता है। इस तरह के एक चटाई-vec mul के लिए सी कोड इस तरह दिखता है:AVX2 स्पैर मैट्रिक्स गुणा

for (int row = 0; row < n_rows - 1; row++) { 
    double rowsum = 0; 
    for (int col = row_ptr[row]; col < row_ptr[row + 1]; col++) { 
     rowsum += values[col] * x[col_indices[col]]; 
    } 
    result[row] = rowsum; 
} 

अब मेरा लक्ष्य AVX2 intrinsics के साथ इस तेजी लाने के लिए है। निम्नलिखित कोड https://blog.fox-toolkit.org/?p=174 पर आधारित नवीनतम इंटेल या जीसीसी के साथ काम करता है। मैंने शेष को यहां हटा दिया क्योंकि मेरी पंक्तियां 4 युगल (कॉलम% 4 == 0) पर संरेखित हैं (वैसे भी भाग्यशाली)। यदि कोई दिलचस्पी लेता है तो मेरे पास कोड शेष भी है, लेकिन बिंदु यह है कि कोड वास्तव में थोड़ा धीमा है। मैंने डिस्सेप्लोर की जांच की और उपर्युक्त संस्करण के लिए केवल एफपी निर्देश उत्पन्न किए गए और मेरे AVX2 कोड के लिए सभी AVX2 ऑप्स अपेक्षित दिखाई देते हैं। कैश में फिट होने वाली छोटी मैट्रिक्स के साथ भी AVX2 संस्करण अच्छा नहीं है। मैं यहां परेशान हूं ...

double* value_base = &values[0]; 
double* x_base = &x[0]; 
int* index_base = &col_indices[0]; 


for (int row = 0; row < n_rows - 1; row++) { 
    int col_length = row_ptr[row + 1] - row_ptr[row]; 

    __m256d rowsum = _mm256_set1_pd(0.); 
    for (int col4 = 0; col4 < col_length; col4 += 4) { 
     // Load indices for x vector(const __m128i*) 
     __m128i idxreg  = _mm_load_si128((const __m128i*)index_base); 
     // Load 4 doubles from x indexed by idxreg (AVX2) 
     __m256d x_  = _mm256_i32gather_pd(x_base, idxreg, 8); 
     // Load 4 doubles linear from memory (value array) 
     __m256d v_  = _mm256_load_pd(value_base); 
     // FMA: rowsum += x_ * v_ 
     rowsum = _mm256_fmadd_pd(x_, v_, rowsum); 

     index_base += 4; 
     value_base += 4; 
    } 
    __m256d s = _mm256_hadd_pd(rowsum, rowsum); 
    result[row] = ((double*)&s)[0] + ((double*)&s)[2]; 
    // Alternative (not faster): 
    // Now we split the upper and lower AVX register, and do a number of horizontal adds 
    //__m256d hsum = _mm256_add_pd(rowsum, _mm256_permute2f128_pd(rowsum, rowsum, 0x1)); 
    //_mm_store_sd(&result[row], _mm_hadd_pd(_mm256_castpd256_pd128(hsum), _mm256_castpd256_pd128(hsum))); 
} 

कोई सुझाव स्वागत है।

धन्यवाद एक बहुत, क्रिस

+3

मूल रूप से, बेकार इकट्ठा होता है। – harold

+2

क्या @harold ने कहा: एकत्रित भार बहुत अक्षम हैं और प्रदर्शन को मार देंगे जब तक कि आप भार की प्रारंभिक लागत को कम करने के लिए पर्याप्त गणना नहीं कर रहे हैं। आप इसके लिए स्केलर कोड के साथ ही चिपक सकते हैं। –

+2

नकल '_mm_move_sd' +' _mm_loadh_pd' के साथ एकत्रित होता है। हैसवेल पर यह हार्डवेयर इकट्ठा करने से तेज है। –

उत्तर

9

इकट्ठा Haswell पर धीमी है। मैंने कुछ अलग-अलग तरीकों से 16 बिट मूल्यों (जीएफ 16 गुणा के लिए गुणा करने के लिए) के 8-बिट-इंडेक्स LUT लुकअप को कार्यान्वित किया है, यह पता लगाने के लिए कि सबसे तेज़ क्या है। हैसवेल पर, VPGATHERDD संस्करण ने movd/pinsrw संस्करण तक 1.7x लिया। (केवल कुछ जोड़े VPUNPCK/शिफ्ट निर्देशों को एकत्रित करने से परे आवश्यक थे।) code here, if anyone wants to run the benchmark

जब एक निर्देश पहली बार पेश किया जाता है तो आम बात है, वे इसे सुपर-फास्ट बनाने के लिए बड़ी मात्रा में सिलिकॉन समर्पित नहीं करते हैं। वहां सिर्फ एचडब्ल्यू समर्थन प्राप्त करने के लिए है, इसलिए इसका उपयोग करने के लिए कोड लिखा जा सकता है। सभी सीपीयू पर आदर्श प्रदर्शन के लिए, आपको pshufb के लिए x264 के लिए क्या करना है: SLOW_SHUFFLE कोर 2 जैसे CPU के लिए ध्वज है, और कारक जो आपके सीपीयू को डालने के बजाए आपके सर्वोत्तम-नियमित-खोज फ़ंक्शन-पॉइंटर-सेटिंग में है, का समर्थन करता है।

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

ब्रॉडवेल को तेजी से एकत्रित कार्यान्वयन माना जाता है, लेकिन मेरे पास एक तक पहुंच नहीं है। इंटेल मैनुअल जो निर्देशों के लिए विलंबता/थ्रूपुट सूचीबद्ध करता है, कहता है कि ब्रॉडवेल की इकट्ठा लगभग 1.6x तेज है, इसलिए यह अभी भी हाथ से तैयार किए गए लूप की तुलना में थोड़ा धीमा होगा जो जीपी regs में सूचकांक को बदलता/अनपैक करता है, और उन्हें PINSRW वेक्टरों में उपयोग करता है।

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

उम्मीद है कि स्काइलेक और भी बेहतर होगा। मैंने सोचा कि मैं कुछ कहूंगा कि यह होगा, लेकिन जांच पर, मुझे कुछ भी नहीं मिला।

आरई: स्पैस मैट्रिस: क्या कोई प्रारूप नहीं है जो डेटा को डुप्लिकेट करता है, ताकि आप पंक्तियों या स्तंभों के लिए संगत पढ़ सकें? ऐसा कुछ नहीं है जिसके लिए मुझे कोड लिखना पड़ा, लेकिन मुझे लगता है कि मैंने कुछ उत्तरों में इसका उल्लेख देखा है।

+0

आपका मतलब है कि स्काइलेक AVX2 इकट्ठा ब्रॉडवेल की तुलना में तेज़ होगा? या क्या आपका मतलब है कि AVX512 इकट्ठा ब्रॉडवेल की तुलना में तेज़ होगा? ज़ीऑन प्रोसेसर को छोड़कर स्किलेक में AVX512 नहीं होगा। क्या आपके पिछले पैराग्राफ में आपके बयान के लिए स्रोत है? –

+0

हम्म, मैं भूल जाता हूं कि स्किलेक एवीएक्स 2 के बारे में मैंने जो पढ़ा है, वह अटकलों को अटकलें या सोर्स किया गया था। "टक" में सुधार करने के लिए यह एक बहुत ही स्पष्ट बात है, मान लीजिए कि बहुत सारे ट्रांजिस्टर खर्च किए बिना सुधार के लिए जगह है। मैं देखूंगा कि मुझे वह याद आ रहा है जो मैं याद कर रहा था। –

+0

मैंने देखा [यह] (http://arstechnica.com/gadgets/2015/07/intel-confirms-tick-tock-shattering-kaby-lake-processor-as-moores-law-falters/) आज। मुझे लगता है कि टिक-टोक खत्म हो गया है। कबी झील नामक अगले वर्ष एक और 14 एनएम प्रोसेसर होगा। हो सकता है कि AVX512 (टिक-टोक के बजाय इसे टिक टिक टोक कहा जाना चाहिए)। –

संबंधित मुद्दे