2012-02-28 18 views
5

मै मैट्रिक्स में एक अजीब प्रदर्शन समस्या में आया बेंचमार्क (MOSBENCH सूट से मेटिस में matrix_mult)। बेंचमार्क को डेटा को टाइल करने के लिए अनुकूलित किया गया था कि सक्रिय कामकाजी सेट 12kb (32x32 इंच की 3 टाइल्स) था और एल 1 कैश में फिट होगा। एक लंबी कहानी को कम करने के लिए, आंतरिक दो सबसे लूपों को स्वैप करने के लिए कुछ सरणी इनपुट आकार (4096, 8192) पर लगभग 4x का प्रदर्शन अंतर था और दूसरों पर 30% अंतर था। समस्या अनिवार्य रूप से एक स्ट्रॉइड पैटर्न में बनाम तत्वों तक पहुंचने के लिए नीचे आ गई। कुछ सरणी आकारों में मुझे लगता है कि एक खराब घुमावदार पहुंच उत्पन्न हुई जिसने बहुत सी कैश लाइन टकराव उत्पन्न किए। 2-तरफा सहयोगी एल 1 से 8-तरफा सहयोगी एल 1 में बदलते समय प्रदर्शन अंतर काफी कम होता है।संकलक नेस्टेड लूप अनुकूलन।

मेरा प्रश्न यह है कि अनुक्रमिक मेमोरी एक्सेस को अधिकतम करने के लिए जीओसी ऑप्टिमाइज़ लूप ऑर्डरिंग क्यों नहीं करता है?

नीचे समस्या का एक सरलीकृत संस्करण है (ध्यान दें कि प्रदर्शन का समय एल 1 कॉन्फ़िगरेशन पर अत्यधिक निर्भर है। नीचे दिखाए गए नंबर 2.3 गीगाहर्ट्ज एएमडी सिस्टम से हैं 64-एल 1 2-वे-साथ सहयोगी -ओ 3 के साथ संकलित)।

N = ARRAY_SIZE // 1024 
int* mat_A = (int*)malloc(N*N*sizeof(int)); 
int* mat_B = (int*)malloc(N*N*sizeof(int)); 
int* mat_C = (int*)malloc(N*N*sizeof(int)); 

// Elements of mat_B are accessed in a stride pattern of length N 
// This takes 800 msec 
for (int t = 0; t < 1000; t++) 
    for (int a = 0; a < 32; a++) 
     for (int b = 0; b < 32; b++) 
     for (int c = 0; c < 32; c++) 
      mat_C[N*a+b] += mat_A[N*a+c] * mat_B[N*c+b]; 

// Inner two loops are swapped 
// Elements are now accessed sequentially in inner loop 
// This takes 172 msec 
for (int t = 0; t < 1000; t++) 
    for (int a = 0; a < 32; a++) 
     for (int c = 0; c < 32; c++) 
     for (int b = 0; b < 32; b++) 
      mat_C[N*a+b] += mat_A[N*a+c] * mat_B[N*c+b]; 
+4

क्योंकि संकलक के लिए यह साबित करना बहुत मुश्किल है कि इस तरह के परिवर्तन ऑपरेशन के अर्थशास्त्र को नहीं बदलते हैं। – Sven

+0

शायद आपको google gcc + graphite के लिए यह दिलचस्प लगेगा, जो पॉलीहेड्रल मॉडल के आधार पर लूप ट्रांसफॉर्मेशन के लिए अब विलय वाली शाखा थी। कहीं संभावित परिवर्तनों की एक सूची है। –

+0

मुझे लगता है कि चूंकि पूर्णांक जोड़ना कम्यूटिक है क्योंकि यह एक संकलक के लिए यह साबित करना काफी आसान होगा कि ऑपरेशन लूपर ऑर्डरिंग के लिए परिवर्तनीय है। मैं सोच रहा हूं कि यह कोड उदाहरण के बारे में क्या है जो इसे अनुकूलित करने के लिए गैर-तुच्छ बनाता है। – Mark

उत्तर

1
  1. जीसीसी साबित होता है कि संकेत ओवरलैप नहीं में सक्षम नहीं हो सकता है। यदि आप गैर मानक एक्सटेंशन का उपयोग कर ठीक हैं तो आप __restrict का उपयोग करने का प्रयास कर सकते हैं।
  2. जीसीसी प्रत्येक प्रोसेसर के लिए पुन: संकलित करने की आवश्यकता से बचने के लिए आपके आर्किटेक्चर का पूर्ण लाभ नहीं लेता है। -march विकल्प का उपयोग करके आपके सिस्टम के उचित मूल्य में मदद मिल सकती है।
+0

यह ध्यान देने योग्य है कि सी 99 के लिए _is_ मानक प्रतिबंधित है, बस सी ++ के लिए नहीं। यह भी देखें http://stackoverflow.com/questions/776283/what-does-the-restrict-keyword-mean-in-c – torek

+0

@torek मुझे पता है, बस यह स्पष्ट करना चाहता था कि यह एक गैर-मानक एक्सटेंशन है लेकिन समर्थित है कई कंपाइलर्स – taurdir

0

जीसीसी में अनुकूलन का एक समूह है जो आप चाहते हैं बस करें।

-फ्लूप-स्ट्रिप-खान और -फ्लूप-ब्लॉक कंपाइलर विकल्पों को देखें। मैनुअल से

उद्धरण:

छोरों पर पाश अवरुद्ध परिवर्तनों को पूरा करें। स्ट्रिप खानों को अवरुद्ध करना लूप घोंसला में प्रत्येक पाश जैसे कि स्मृति तत्व लूप कैश के अंदर फिट हो जाता है। स्ट्रिप लम्बाई लूप-ब्लॉक-टाइल-आकार पैरामीटर का उपयोग करके बदला जा सकता है।

+0

धन्यवाद, हालांकि समस्या कैश में फ़िट नहीं होने वाले आंतरिक लूपों के कारण नहीं है, क्योंकि उस अनुकूलन कोड में हाथ से पहले से ही किया गया था। आंतरिक लूप में केवल 12 केबी डेटा पदचिह्न होता है। 3 * 1024 int मान। – Mark

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