2016-11-16 6 views
8

रोकता मैं OpenMP के लिए नया हूँ और मैं OpenMP का उपयोग कर निम्न कोड paralelize कोशिश कर रहा हूँ:OpenMP paralelization vectorization

#pragma omp parallel for 
for(int k=0;k<m;k++) 
{ 
    for(int j=n-1;j>=0;j--) 
    { 
     outX[k+j*m] = inB2[j+n * k]/inA2[j*n + j]; 

     for(int i=0;i<j;i++) 
     { 
      inB2[k*n+i] -= inA2[i+n * j] * outX[k + m*j]; 
     } 
    } 
} 

Paralelize बाहरी चक्र बहुत सीधी-सपाट है, लेकिन यह अनुकूलन करने के लिए, मैं paralelize करना चाहता था आंतरिक-चक्र (मैं एक पर पुनरावृत्ति) भी। लेकिन जब मैं ऐसा करने के लिए इस तरह का प्रयास करें:

#pragma omp parallel for 
for(int i=0;i<j;i++) 
{ 
    inB2[k*n+i] -= inA2[i+n * j] * outX[k + m*j]; 
} 

संकलक आंतरिक चक्र ("पाश संभव अलियासिंग की वजह से vectorization के लिए संस्करणीकृत") है, जो यह धीमी चलाने बनाता vectorize नहीं है। मैंने इसे gcc -ffast-math -std=c++11 -fopenmp -O3 -msse2 -funroll-loops -g -fopt-info-vec prog.cpp

किसी भी सलाह के लिए धन्यवाद का उपयोग करके संकलित किया!

संपादित करें: मैं सरणी के लिए __restrict कीवर्ड का उपयोग कर रहा हूं।

EDIT2: दिलचस्प बात यह है कि जब मैं आंतरिक चक्र में केवल प्रगति रखता हूं और इसे बाहरी से हटा देता हूं, तो जीसीसी इसे सदिश बना देगा। तो समस्या केवल तभी होती है जब मैं दोनों चक्रों को paralelize करने की कोशिश करता हूं।

EDIT3: जब मैं सिमड के लिए #pragma omp समानांतर का उपयोग करता हूं तो संकलक लूप को सदिशित करेगा। लेकिन यह अभी भी आंतरिक लूप को समानांतर किए बिना धीमा है।

+0

समांतरता से मैन्युअल रूप से सदिश बनाना आसान है। ऐसा क्यों न करें? (और स्वचालित समांतरता रखें) –

उत्तर

1

उत्तर के लिए सभी को धन्यवाद। मैं #pragma omp parallel for simd का उपयोग कर आंतरिक लूप को सदिश बनाने में कामयाब रहा, लेकिन कार्यक्रम समानांतर के बिना धीमा था। अंत में समस्या को हल करने के लिए मुझे थोड़ा अलग एल्गोरिदम मिला, जो बहुत तेज़ है। आपकी मदद दोस्तों के लिए धन्यवाद!

+1

"वीआईपीओ" (वेक्टरिज़ इनर, समांतर बाहरी) आमतौर पर सबसे अच्छा होता है।तो आंतरिक पाश पर शुद्ध सिम (कोई 'समानांतर' नहीं), और फिर बाहरी लूप की समानांतरता में मदद करता है या नहीं, आमतौर पर एक परीक्षण-एन-एन-एंड एंडवोर होता है। बैंडविड्थ सीमित परिस्थितियों पर कभी-कभी प्रीफेच मदद करता है, लेकिन कैश मिस में बहुत सारे कोर काम कर सकते हैं, जबकि एक कोर कोर बिना छेड़छाड़ के डेटा को स्ट्रीम कर सकता है। यह शायद ही कभी आसान अनुमान लग रहा है। – Holmz

1

मेरा अनुमान है कि आपके भीतर आंतरिक लूप को समानांतर करने के बाद, आपके कंपाइलर ने inA2, inB2 और outX का ट्रैक खो दिया। डिफ़ॉल्ट रूप से, यह मानता है कि किसी भी पॉइंटर्स द्वारा इंगित स्मृति के किसी भी क्षेत्र एक दूसरे के साथ ओवरलैप हो सकता है। सी भाषा में सी 99 मानक ने restrict कीवर्ड पेश किया, जो संकलक को सूचित करता है कि एक पॉइंटर एक मेमोरी ब्लॉक को इंगित करता है जो किसी भी अन्य सूचक द्वारा इंगित नहीं किया जाता है। सी ++ को ऐसा कोई कीवर्ड नहीं मिला है, लेकिन सौभाग्य से, g++ में उचित एक्सटेंशन है। इसलिए लूप द्वारा छुपाए गए पॉइंटर्स की घोषणाओं के लिए __restrict जोड़ने का प्रयास करें। उदाहरण के लिए,

double* outX; 

की जगह

double* __restrict outX; 
+0

दुर्भाग्य से यह मामला नहीं है। मैं __restrict का उपयोग कर रहा हूँ। अच्छा मुद्दा हालांकि, मैं इसे ओपी में जोड़ दूंगा। –

1

साथ आप कर भीतरी पाश पहले vecotorzed की कोशिश की? और फिर समानांतर हिस्सा (जो कैश छूट जाए पर निर्भर करता है धीमे प्रदर्शन में परिणाम हो सकता है) जोड़ने

#pragma omp parallel for 
for(int k=0;k<m;k++) 
{ 
    for(int j=n-1;j>=0;j--) 
    { 
     outX[k+j*m] = inB2[j+n * k]/inA2[j*n + j]; 
Q1 = k*n 
Q2 = n*j 
Q3 = m*j + k 
#pragma omp declare simd private(i,j,k,m,Q1,Q2,Q3) linear(i) uniform(outX,inA2,inB2) shared(inB2,inA2,outX) 
     for(int i=0;i<j;i++) 
     { 
      inB2[Q1+i] -= inA2[Q2+i] * outX[Q3]; 
     } 
    } 
} 

यह हमेशा मुझे कुछ समय साझा, सार्वजनिक आदि के साथ सही #pragma हो रही है ... और मैं परीक्षण नहीं किया इस।

+0

विचार के लिए धन्यवाद। जैसा कि मैंने EDIT3 में उल्लेख किया है, मैं पागल हूं यह सिमड के लिए समानांतर #pragma omp समानांतर का उपयोग करके वेक्टरize करता है। लेकिन यह अभी भी आंतरिक लूप को paralelizing बिना धीमा है। –

+0

यह संकेत दे सकता है कि यह कम्प्यूटेशनल रूप से सीमित के बजाय बैंडविड्थ सीमित है। – Holmz

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