2013-02-13 33 views
6

रोकता है मैं अपने कोड को जीसीसी द्वारा ऑटो वेक्टरिज्ड करने में सक्षम बनाने के लिए काम कर रहा हूं, हालांकि, जब मैं -fopenmp ध्वज शामिल करता हूं तो ऐसा लगता है कि यह ऑटो वेक्टरिसेशन पर सभी प्रयासों को रोकता है। मैं वेक्टरिस के लिए ftree-vectorize -ftree-vectorizer-verbose=5 का उपयोग कर रहा हूं और इसकी निगरानी कर रहा हूं।ओपनएमपी का उपयोग जीसीसी ऑटो वेक्टरिंग

यदि मुझे ध्वज शामिल नहीं है, तो यह मुझे प्रत्येक लूप के बारे में बहुत सारी जानकारी देना शुरू कर देता है, अगर यह सदिश हो और क्यों नहीं। जब मैं omp_get_wtime() फ़ंक्शन का उपयोग करने का प्रयास करता हूं तो संकलक बंद हो जाता है, क्योंकि इसे लिंक नहीं किया जा सकता है। एक बार ध्वज शामिल होने के बाद, यह बस हर समारोह को सूचीबद्ध करता है और मुझे यह बताता है कि इसमें 0 लूप वेक्टर किए गए हैं।

मैंने कुछ अन्य स्थानों को पढ़ लिया है, लेकिन वास्तव में वे किसी भी समाधान पर नहीं आते हैं: http://software.intel.com/en-us/forums/topic/295858http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46032। क्या OpenMP के पास वेक्टरिसेशन को संभालने का अपना तरीका है? क्या मुझे इसे स्पष्ट रूप से बताने की ज़रूरत है?

+0

मुझे लगता है कि आप इस प्रश्न में [answer] (http://stackoverflow.com/a/14717689/771663) में समझदार जानकारी पा सकते हैं। – Massimiliano

+0

धन्यवाद, यह बताता है कि ओपनएमपी के साथ सिमड का उपयोग कैसे करें, लेकिन ऐसा लगता है कि जब मैं ओपनएमपी का उपयोग करता हूं तो सिम स्टॉप के पहले से ही काम करने के कार्यान्वयन का काम क्यों नहीं कर रहा है। क्या दोनों का उपयोग करने का कोई तरीका नहीं है? – superbriggs

+1

यह भी दर्शाता है कि मैं केवल बिट्स की संख्या पर ही काम कर सकता हूं, वे सिर्फ संख्याओं के बीच विभाजित हैं। जीसीसी के साथ ऐसा करने पर मुझे नहीं पूछा गया कि मैं कितने रजिस्टर पर विभाजन करना चाहता हूं। चूंकि मैं एक विश्वविद्यालय 'सुपर कंप्यूटर' का उपयोग कर रहा हूं, मैंने सोचा था कि हार्डवेयर हेम सिम के लिए अतिरिक्त रिक्त स्थान है। अगर मैं सही हूं तो मुझे कैसे पता चलेगा? – superbriggs

उत्तर

9

जीसीसी वेक्टरिसर में एक कमी है जो हाल ही के जीसीसी संस्करणों में हल किया गया प्रतीत होता है। अपने परीक्षण मामले जीसीसी 4.7.2 vectorises सफलतापूर्वक निम्नलिखित सरल पाश में:

एक ही समय जीसीसी 4.6.1 में नहीं है और यह शिकायत करता है, पाश फ़ंक्शन को कॉल या डेटा संदर्भ का विश्लेषण किया नहीं किए जा सकते हैं। वेक्टरिसर में बग parallel for लूप जीसीसी द्वारा लागू किए जाने के तरीके से ट्रिगर किया जाता है।OpenMP निर्माणों संसाधित और विस्तार कर रहे हैं, सरल पाश कोड इस के लिए कुछ सदृश में तब्दील हो जाता:

struct omp_fn_0_s 
{ 
    int N; 
    double *a; 
    double *b; 
    double *c; 
    double d; 
}; 

void omp_fn_0(struct omp_fn_0_s *data) 
{ 
    int start, end; 
    int nthreads = omp_get_num_threads(); 
    int threadid = omp_get_thread_num(); 

    // This is just to illustrate the case - GCC uses a bit different formulas 
    start = (data->N * threadid)/nthreads; 
    end = (data->N * (threadid+1))/nthreads; 

    for (int i = start; i < end; i++) 
     data->a[i] = data->b[i] + data->c[i] * data->d; 
} 

... 

struct omp_fn_0_s omp_data_o; 

omp_data_o.N = N; 
omp_data_o.a = a; 
omp_data_o.b = b; 
omp_data_o.c = c; 
omp_data_o.d = d; 

GOMP_parallel_start(omp_fn_0, &omp_data_o, 0); 
omp_fn_0(&omp_data_o); 
GOMP_parallel_end(); 

N = omp_data_o.N; 
a = omp_data_o.a; 
b = omp_data_o.b; 
c = omp_data_o.c; 
d = omp_data_o.d; 

जीसीसी में vectoriser 4.7 से पहले कि पाश vectorise करने में विफल रहता। यह ओपनएमपी-विशिष्ट समस्या नहीं है। कोई आसानी से इसे ओपनएमपी कोड के साथ पुन: पेश नहीं कर सकता है। - क्योंकि निर्दिष्ट करने के लिए है कि कोई अलियासिंग हो सकता है इस्तेमाल किया restrict कीवर्ड की समान रूप से अच्छी तरह से vectorise चाहिए

struct fun_s 
{ 
    double *restrict a; 
    double *restrict b; 
    double *restrict c; 
    double d; 
    int n; 
}; 

void fun1(double *restrict a, 
      double *restrict b, 
      double *restrict c, 
      double d, 
      int n) 
{ 
    int i; 
    for (i = 0; i < n; i++) 
     a[i] = b[i] + c[i] * d; 
} 

void fun2(struct fun_s *par) 
{ 
    int i; 
    for (i = 0; i < par->n; i++) 
     par->a[i] = par->b[i] + par->c[i] * par->d; 
} 

एक उम्मीद होती है कि दोनों कोड (! कोई OpenMP यहाँ नोटिस): इस बात की पुष्टि करने के लिए मैं निम्नलिखित साधारण परीक्षण लिखा था। दुर्भाग्यवश यह GCC < 4.7 के साथ मामला नहीं है - यह fun1 में लूप को सफलतापूर्वक वेक्टर करता है लेकिन fun2 में वक्रता को विफल करने में विफल रहता है जब यह ओपनएमपी कोड को संकलित करता है।

इस का कारण यह है कि vectoriser साबित होता है कि par->d में असमर्थ है-स्मृति में है कि par->a, par->b, और par->c बिंदु से झूठ नहीं करता है। यह हमेशा fun1 के साथ मामला है, जहां दो मामलों संभव हो रहे हैं नहीं है:

  • d एक रजिस्टर में एक मूल्य के तर्क के रूप में पारित हो जाता है;
  • d स्टैक पर एक मूल्य तर्क के रूप में पारित किया गया है।

x64 सिस्टम पर सिस्टम वी एबीआई अनिवार्य है कि एक्सएमएम रजिस्टरों (एवीएक्स-सक्षम CPUs पर वाईएमएम) में पहले कई फ़्लोटिंग-पॉइंट तर्क पारित किए जाते हैं। इस प्रकार d इस मामले में पारित हो जाता है और इसलिए कोई सूचक कभी भी इंगित नहीं कर सकता - लूप को वेक्टरिज्ड हो जाता है। X86 सिस्टम पर एबीआई अनिवार्य है कि तर्क स्टैक पर पारित किए जाते हैं, इसलिए d को तीन बिंदुओं में से किसी एक द्वारा अलिया किया जा सकता है। दरअसल, -m32 विकल्प के साथ 32-बिट x86 कोड उत्पन्न करने के निर्देश दिए जाने पर जीसीसी fun1 में लूप को सदिश करने से इंकार कर देता है।

जीसीसी 4.7 रन-टाइम चेक डालने से इसके आसपास हो जाता है जो सुनिश्चित करता है कि न तो d और न ही par->d उपनाम प्राप्त करें।

d से छुटकारा unprovable गैर अलियासिंग दूर करता है और निम्नलिखित OpenMP कोड जीसीसी 4.6.1 द्वारा vectorised हो जाता है:

#pragma omp parallel for schedule(static) 
for (int i = 0; i < N; i++) 
    a[i] = b[i] + c[i]; 
+0

ग्रेट उत्तर। लेकिन क्या आप इस बारे में और कह सकते हैं "यह सिर्फ मामले को चित्रित करने के लिए है - जीसीसी थोड़ा अलग सूत्रों का उपयोग करता है"। जीसीसी का क्या सूत्र है? –

+0

@Zboson, मैं इसे यहां (बदसूरत) पेस्ट कर सकता हूं, लेकिन आप 'gcc -fdump-tree-all-fopenmp foo.c'' बजाएंगे और ओपनएमपी विस्तार के बाद आमतौर पर एएसटी की जांच करेंगे, आमतौर पर 'foo' में स्थित है। c.015t.ompexp'। अंतर यह है कि जीसीसी पहले 'आर' धागे को एक अतिरिक्त पुनरावृत्ति देकर' आर = एन% num_threads' विभाजन से शेष को वितरित करता है। –

3

मैं आपके प्रश्न का संक्षिप्त उत्तर देने की कोशिश करूंगा।

  1. क्या OpenMP के पास वेक्टरिसेशन को संभालने का अपना तरीका है?

हाँ ... लेकिन आने वाले ओपनएमपी 4.0 से शुरू हो रहा है। ऊपर पोस्ट link इस निर्माण पर एक अच्छी अंतर्दृष्टि प्रदान करता है। दूसरी ओर, वर्तमान ओपनएमपी 3.1, सिम अवधारणा के "जागरूक" नहीं है। इसलिए अभ्यास में (या, कम से कम, मेरे अनुभव में) ऐसा होता है कि जब भी लूप पर ओपनएमपी वर्कशियरिंग निर्माण का उपयोग किया जाता है तो ऑटो-वेक्टरेशन तंत्र अवरुद्ध होते हैं। किसी भी तरह दो अवधारणाएं ऑर्थोगोनल हैं और आप अभी भी दोनों से लाभ उठा सकते हैं (यह अन्य answer देखें)।

  1. क्या मुझे इसे स्पष्ट रूप से बताने की ज़रूरत है?

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

+0

बहुत बहुत धन्यवाद। आपका पहला लिंक फ़ंक्शन 'VECTOR_ADD' देता है। मैंने पढ़ा है कि ऐसा करने के लिए एक सामान्य आकार के रजिस्टर का उपयोग करता है, इसलिए केवल छोटी संख्याओं को वेक्टरिज्ड करने की अनुमति देता है। मुझे पता है कि मेरे हार्डवेयर में सिमड को संभालने के लिए विशिष्ट रजिस्ट्रार हैं ताकि ऐसा न हो। क्या ओपनएमपी इस रजिस्टर का उपयोग करने का कोई तरीका है? क्या मुझे इन कार्यों का उपयोग करने की ज़रूरत है, इस पर विचार करते हुए कि जीसीसी ने मेरे लिए यह सब किया था? मुझे नहीं लगता कि ओपनएमपी इस फॉर्म को क्यों काम करता है। आपका दूसरा लिंक कहता है कि वे दोनों एक साथ काम कर सकते हैं, लेकिन यह नहीं कि मैं इसे कैसे समझूंगा। आपको पुन: बहुत धन्यवाद। – superbriggs

+0

मुख्य विचार यह है कि ओपनएमपी को सिमडाइजेशन के बारे में पता नहीं होना चाहिए, क्योंकि आप इसकी देखभाल VECTOR_ADD में करते हैं। मैंने कभी भी 3 डीnow का उपयोग नहीं किया, लेकिन इंटेल प्लेटफार्मों पर आप स्पष्ट रूप से कोड को सदिश बनाने के लिए [intrinsics] (http://software.intel.com/en-us/articles/how-to-use-intrinsics) का उपयोग कर सकते हैं। मुख्य दोष यह है कि या तो आप पोर्टेबिलिटी खो देते हैं (जैसे इंट्रिनिक्स अन्य प्लेटफार्मों पर काम नहीं करेगा) या पठनीयता/रखरखाव (सशर्त संकलन के कारण)। – Massimiliano

+0

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

1

आप पूछ रहे हैं "ओपनएमपी सक्षम होने पर जीसीसी वेक्टरेशन क्यों नहीं कर सकता है?"।

ऐसा लगता है कि इस जीसीसी :) http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46032

की एक बग नहीं तो, एक OpenMP एपीआई निर्भरता (नियंत्रण अथवा डेटा) है कि स्वचालित vectorization से बचाता है उत्पन्न हो हो सकता है। ऑटो-वर्टोरिज़ करने के लिए, दिया गया कोड डेटा/नियंत्रण-निर्भरता मुक्त होना चाहिए। यह संभव है कि ओपनएमपी का उपयोग कुछ नकली निर्भरता का कारण बन सकता है।

नोट: ओपनएमपी (4.0 से पहले) थ्रेड-स्तरीय समांतरता का उपयोग करना है, जो सिमड/वेक्टरेशन के ऑर्थोगोनल है। एक कार्यक्रम एक ही समय में ओपनएमपी और सिम समांतरता दोनों का उपयोग कर सकता है।

1

मैं इस पोस्ट भर में भाग गया, जबकि जीसीसी 4.9 विकल्प के बारे में टिप्पणी के लिए खोज openmp- simd, जो omp समानांतर (थ्रेडिंग) को सक्रिय किए बिना OpenMP 4 #pragma omp simd को सक्रिय करना चाहिए। जीसीसी बगजिला pr60117 (पुष्टि) एक ऐसा मामला दिखाता है जहां प्रगा ओएमएम ऑटो-वेक्टरेशन को रोकती है जो प्रज्ञा के बिना हुई थी।

जीसीसी सिमड क्लॉज के साथ भी ओएमपी समानांतर नहीं करता है (समांतर क्षेत्र केवल समानांतर के नीचे घोंसला वाले आंतरिक लूप को स्वत: वेक्टरेट कर सकते हैं)। मैं आईसीसी 14.0.2 के अलावा किसी भी कंपाइलर को नहीं जानता जिसे सिमड के लिए #pragma omp समानांतर के कार्यान्वयन के लिए अनुशंसित किया जा सकता है; अन्य कंपाइलरों के साथ, एसएसई इंट्रिनिक्स कोडिंग को इस प्रभाव को प्राप्त करने की आवश्यकता होगी।

माइक्रोसॉफ्ट कंपाइलर मेरे परीक्षणों में समानांतर क्षेत्रों के अंदर कोई ऑटो-वेक्टरिज़ेशन नहीं करता है, जो ऐसे मामलों के लिए जीसीसी की स्पष्ट श्रेष्ठता दिखाता है।

संयुक्त लूप के संयुक्त समांतरता और वेक्टरिज़ेशन में सर्वोत्तम कार्यान्वयन के साथ कई कठिनाइयों भी हैं। मैं कभी-कभी समानांतर लूप में वेक्टरनाइज़ेशन जोड़कर 2x या 3x से अधिक गति को देखता हूं।एवीएक्स डबल डेटा प्रकार के साथ वेक्टरेशन, उदाहरण के लिए, 4 के कारक द्वारा प्रभावी रूप से खंड आकार को काटता है। विशिष्ट कार्यान्वयन केवल उस मामले के लिए गठबंधन डेटा भाग प्राप्त कर सकता है जहां संपूर्ण सरणी गठबंधन होती है, और भाग भी वेक्टर चौड़ाई के सटीक गुणक होते हैं । जब भाग सभी गठबंधन नहीं होते हैं, तो विभिन्न संरेखणों के कारण अंतर्निहित कार्य असंतुलन होता है।