2013-01-16 11 views
10

में साझा किया जाना चाहिए या नहीं, मेरे पास एक लूप है जो मैट्रिक्स ए अपडेट करता है और मैं इसे openmp बनाना चाहता हूं लेकिन मुझे यकीन नहीं है कि कौन से चर साझा किए जाने चाहिए और निजी। मैंने सोचा होगा कि आईआई और जेजे काम करेंगे लेकिन ऐसा नहीं है। मुझे लगता है कि मैं एक! $ OMP परमाणु अद्यतन कहीं भी जरूरत है ...सुनिश्चित नहीं है कि ओपनएमपी लूप

पाश सिर्फ -1 एन कणों एन और के बीच की दूरी की गणना करता है और एक मैट्रिक्स ए

  !$OMP PARALLEL DO PRIVATE(ii,jj) 
      do ii=1,N-1 
        do jj=ii+1,N 
          distance_vector=X(ii,:)-X(jj,:) 
          distance2=sum(distance_vector*distance_vector) 
          distance=DSQRT(distance2) 
          coff=distance*distance*distance 
          PE=PE-M(II)*M(JJ)/distance 
          A(jj,:)=A(jj,:)+(M(ii)/coff)*(distance_vector) 
          A(ii,:)=A(ii,:)-(M(jj)/coff)*(distance_vector) 
        end do 
      end do 
      !$OMP END PARALLEL DO 

उत्तर

23

OpenMP के स्वर्ण नियम यह है कि सभी चर (कुछ बहिष्कारों के साथ), जिन्हें बाहरी क्षेत्र में परिभाषित किया गया है, समानांतर क्षेत्र में डिफ़ॉल्ट रूप से साझा किए जाते हैं। चूंकि 2008 से पहले फोरट्रान में कोई स्थानीय क्षेत्र नहीं है (यानी पिछले संस्करणों में BLOCK ... END BLOCK नहीं है), सभी चर (threadprivate वाले को छोड़कर) साझा किए जाते हैं, जो मेरे लिए बहुत स्वाभाविक है (इयान बुश के विपरीत, मैं उपयोग करने का बड़ा प्रशंसक नहीं हूं default(none) और फिर विभिन्न जटिल वैज्ञानिक कोडों में सभी 100+ स्थानीय चरों की दृश्यता को फिर से शुरू करना)। , साझा क्योंकि यह सब धागे में एक ही होना चाहिए और वे केवल अपने मूल्य पढ़ा -

  • N:

    यहाँ कैसे प्रत्येक चर के बंटवारे वर्ग निर्धारित करने के लिए है।

  • ii - यह एक कार्यशाला निर्देश के अधीन लूप का काउंटर है, इसलिए इसकी साझाकरण कक्षा private होने की पूर्व निर्धारित है। यह PRIVATE खंड में स्पष्ट रूप से घोषित करने के लिए चोट नहीं पहुंचाता है, लेकिन यह वास्तव में आवश्यक नहीं है।
  • jj - एक लूप का लूप काउंटर, जो वर्कशियरिंग निर्देश के अधीन नहीं है, इसलिए jjprivate होना चाहिए।
  • X -, साझा क्योंकि सभी धागे का संदर्भ और केवल इसे से पढ़ें।
  • distance_vector - स्पष्ट रूप से private होना चाहिए के रूप में प्रत्येक धागा कणों के विभिन्न जोड़े पर काम करता है।
  • distance, distance2, और coff - डिट्टो।
  • M - X के रूप में एक ही कारण के लिए साझा किया जाना चाहिए।
  • PE - एक संचायक चर (मुझे लगता है कि इस प्रणाली के संभावित ऊर्जा है) और एक कमी आपरेशन का विषय होना चाहिए, जैसे एक REDUCTION(+:....) खंड में रखा जाना चाहिए के रूप में कार्य करता है।
  • A - यह एक मुश्किल है। इसे या तो A(jj,:) को सिंक्रनाइज़ करने वाली संरचनाओं के साथ संरक्षित किया जा सकता है या अपडेट किया जा सकता है, या आप कमी का उपयोग कर सकते हैं (ओपनएमपी सी/सी ++ के विपरीत फोरट्रान में सरणी चर पर कटौती की अनुमति देता है)। A(ii,:) को कभी भी एक से अधिक धागे द्वारा संशोधित नहीं किया गया है, इसलिए इसे विशेष उपचार की आवश्यकता नहीं है।

A से अधिक कमी के साथ जगह में, प्रत्येक थ्रेड A की अपनी निजी कॉपी प्राप्त होगा और यह एक स्मृति हॉग हो सकता है, हालांकि मुझे शक है तो आप इस प्रत्यक्ष हे (एन) अनुकरण कोड का प्रयोग करेंगे प्रणालियों की गणना करने के कणों की बहुत बड़ी संख्या के साथ। कमी कार्यान्वयन से जुड़े एक निश्चित ओवरहेड भी है। इस मामले में आपको REDUCTION(+:...) खंड की सूची में A जोड़ने की आवश्यकता है।

सिंक्रनाइज़िंग संरचनाओं के साथ आपके पास दो विकल्प हैं। आप या तो ATOMIC निर्माण या CRITICAL निर्माण इस्तेमाल कर सकते हैं। ATOMIC केवल अदिश संदर्भों के लिए लागू है के रूप में, आप करने के लिए "unvectorise" काम पाश है और प्रत्येक बयान के ATOMIC लागू होगा, जैसे:

!$OMP ATOMIC UPDATE 
A(jj,1)=A(jj,1)+(M(ii)/coff)*(distance_vector(1)) 
!$OMP ATOMIC UPDATE 
A(jj,2)=A(jj,2)+(M(ii)/coff)*(distance_vector(2)) 
!$OMP ATOMIC UPDATE 
A(jj,3)=A(jj,3)+(M(ii)/coff)*(distance_vector(3)) 

तुम भी एक पाश के रूप में इस पुनर्लेखन कर सकते हैं - घोषित करने के लिए मत भूलना लूप काउंटर private

!$OMP CRITICAL (forceloop) 
A(jj,:)=A(jj,:)+(M(ii)/coff)*(distance_vector) 
!$OMP END CRITICAL (forceloop) 

महत्वपूर्ण क्षेत्रों का नामकरण वैकल्पिक और थोड़ा इस विशेष मामले में अनावश्यक है लेकिन सामान्य रूप में यह असंबंधित महत्वपूर्ण क्षेत्रों को अलग करने के लिए अनुमति देता है:

CRITICAL के साथ पाश unvectorise की कोई जरूरत नहीं है।

कौन सा तेज़ है? ATOMIC या CRITICAL के साथ अनलॉक किया गया? यह कई चीजों पर निर्भर करता है। आम तौर पर CRITICAL रास्ता धीमा है क्योंकि इसमें अक्सर ओपनएमपी रनटाइम में फ़ंक्शन कॉल शामिल होते हैं, जबकि परमाणु वृद्धि, कम से कम x86 पर, लॉक किए गए अतिरिक्त निर्देशों के साथ कार्यान्वित की जाती है। जैसा कि वे अक्सर कहते हैं, वाईएमएमवी।

पुनरावृत्ति के लिए, अपने पाश में काम करने का संस्करण होना चाहिए कुछ की तरह:

!$OMP PARALLEL DO PRIVATE(jj,kk,distance_vector,distance2,distance,coff) & 
!$OMP& REDUCTION(+:PE) 
do ii=1,N-1 
    do jj=ii+1,N 
     distance_vector=X(ii,:)-X(jj,:) 
     distance2=sum(distance_vector*distance_vector) 
     distance=DSQRT(distance2) 
     coff=distance*distance*distance 
     PE=PE-M(II)*M(JJ)/distance 
     do kk=1,3 
     !$OMP ATOMIC UPDATE 
     A(jj,kk)=A(jj,kk)+(M(ii)/coff)*(distance_vector(kk)) 
     end do 
     A(ii,:)=A(ii,:)-(M(jj)/coff)*(distance_vector) 
    end do 
end do 
!$OMP END PARALLEL DO 

मैं मान लिया गया है कि आपके सिस्टम 3-आयामी है।


यह सब के साथ कहा, मैं दूसरी इयान बुश है कि आप पर पुनर्विचार करने के लिए कैसे स्थिति और त्वरण मैट्रिक्स स्मृति में बाहर रखी हैं की जरूरत है। उचित कैश उपयोग आपके कोड को बढ़ावा दे सकता है और कुछ संचालन के लिए भी अनुमति देगा, उदा। X(:,ii)-X(:,jj) वेक्टरिज्ड होने के लिए, यानी वेक्टर सिम निर्देशों का उपयोग करके कार्यान्वित किया गया।

+1

शुक्रिया, फिर से धन्यवाद। बस एक बहुत ही बुनियादी सवाल - सरल लूप के लिए यह जटिल क्यों होना चाहिए। मेरा मतलब है कि आप सिर्फ बाहरी लूप को नाथ्रेड तरीके से विभाजित करना चाहते हैं और कुछ मैट्रिक्स को पॉप्युलेट करना चाहते हैं (कम से कम मेरे द्वारा किए गए सामान में)। मैं देख सकता हूँ तुम क्यों जटिल मामलों के लिए निजी आदि की जरूरत है और इसलिए यह 'अतिरिक्त इंजीनियरिंग' लेकिन क्यों सिर्फ राज्य नहीं! $ OMP parallell डीओ साझा (मैट्रिक्स) तो यह सिर्फ N/nthreads विभाजन और उद्धार का एक फूलदान है। प्रत्येक धागे में सब कुछ अनुक्रम में किया जाएगा। मुझे लगता है कि मैं सोच रहा हूं - डिफ़ॉल्ट रूप से सब कुछ निजी क्यों नहीं बनाते, साझा नहीं किया गया है, फिर साझा करें। – Griff

+0

@ ग्रिफ, सी/सी ++ में इन चरों को सबसे नीचे लूप के अंदर घोषित किया जा सकता है और फिर वे स्वचालित रूप से निजी होते हैं। वे साझा किए जाते हैं सीरियल कोड के ओपनएमपी मैच के अर्थशास्त्र की इच्छा से उपजी है। वैसे, आप एटोमिक्स से छुटकारा मिल सकता है अगर आप न्यूटन के तीसरे नियम के बारे में एक पल के लिए भूल जाते हैं और दोनों पाश, n' 'एक (ii के लिए काम के साथ' 1 से अधिक चलाने के लिए, :) 'केवल (अप्रभावी है)। –

+0

क्या वैसे भी मैं आपको जांचने के लिए एक प्रश्न के रूप में पोस्ट करने के बिना आपको एक नया कोड दिखा सकता हूं? यह कुछ हद तक आसान है, लेकिन लंबा है और मैं केवल यह सुनिश्चित करना चाहता हूं कि मैं इसे शब्दों में सही तरीके से समझूं। धन्यवाद। – Griff

3

के रूप में लिखा आप की आवश्यकता होगी अद्यतन करता है दौड़ की स्थिति से बचने के लिए कुछ सिंक्रनाइज़ेशन। 2 थ्रेड केस पर विचार करें। Ii = 1 के साथ थ्रेड 0 शुरू करें, और इसलिए jj = 2,3,4, .... और थ्रेड 1 ii = 2 के साथ शुरू होता है, और इसलिए jj = 3,4,5,6 पर विचार करता है। इस प्रकार लिखा गया है कि धागा 0 ii = 1, jj = 3 और थ्रेड 1 पर विचार कर रहा है ii = 2, jj = 3 एक ही समय में देख रहा है। यह स्पष्ट रूप से लाइन

     A(jj,:)=A(jj,:)+(M(ii)/coff)*(distance_vector) 

में समस्याएं पैदा कर सकता के रूप में दोनों धागे जेजे की एक ही मूल्य है। तो हाँ, आपको दौड़ से बचने के लिए अपडेट को ए सिंक्रनाइज़ करने की आवश्यकता है, हालांकि मुझे यह स्वीकार करना होगा कि मुझे अच्छा तरीका मेरे लिए तुरंत स्पष्ट नहीं है। मैं इस पर सोचूंगा और संपादित करूंगा कि मेरे साथ कुछ होता है या नहीं।

हालांकि मैं 3 अन्य टिप्पणी मिल गया है:

1) आपका स्मृति पहुँच पैटर्न भयानक है, और इस इच्छा को सही करने, मैं उम्मीद, कम से कम के रूप में ज्यादा गति देने में बहुत कम परेशानी के साथ किसी भी OpenMP के रूप में। फोरट्रान में आप सबसे पहले सूचकांक को सबसे तेज़ी से नीचे जाना चाहते हैं - यह सुनिश्चित करता है कि मेमोरी एक्सेस स्थानिक रूप से स्थानीय हैं और इसलिए मेमोरी पदानुक्रम का अच्छा उपयोग सुनिश्चित करता है। यह देखते हुए कि आधुनिक मशीन पर अच्छे प्रदर्शन के लिए यह सबसे महत्वपूर्ण बात है, आपको वास्तव में यह अधिकार प्राप्त करने का प्रयास करना चाहिए। तो ऊपर बेहतर होगा कि आप सरणियों ताकि ऊपर के रूप में

 do ii=1,N-1 
       do jj=ii+1,N 
         distance_vector=X(:,ii)-X(:jj) 
         distance2=sum(distance_vector*distance_vector) 
         distance=DSQRT(distance2) 
         coff=distance*distance*distance 
         PE=PE-M(II)*M(JJ)/distance 
         A(:,jj)=A(:,jj)+(M(ii)/coff)*(distance_vector) 
         A(:,ii)=A(:,ii)-(M(jj)/coff)*(distance_vector) 
       end do 
     end do 

नोट यह कैसे पहले सूचकांक नीचे चला जाता है, बल्कि आपके पास के रूप में दूसरे से लिखा जा सकता है की व्यवस्था कर सकते हैं।

2) यदि आप ओपनएमपी का उपयोग करते हैं तो मैं दृढ़ता से सुझाव देता हूं कि आप डिफ़ॉल्ट (कोई नहीं) का उपयोग करें, इससे बुरा कीड़े से बचने में मदद मिलती है। यदि आप मेरे छात्रों में से एक थे तो आप ऐसा करने के लिए अंकों का भार खो देंगे!

3) Dsqrt पुरातन है - आधुनिक फोरट्रान (में यानी सभी में 1967 के बाद कुछ भी) लेकिन कुछ अस्पष्ट मामलों sqrt बहुत काफी अच्छा है, और अधिक लचीला है

+0

मैं तुम्हारी मदद की सराहना करते हैं। अगर मैं स्मृति में सुधार करता हूं, तो भी मुझे साझा और निजी चीज़ों की समस्या के साथ छोड़ दिया गया है। ii और jj स्पष्ट रूप से लेकिन बस जोड़ना! एएमपी एटॉमिक अपडेट ए (:, जेजे) और ए (:, ii) से पहले काम नहीं करता है। – Griff

+0

हाँ - उचित टिप्पणी। ii और jj निजी होना चाहिए क्योंकि प्रत्येक थ्रेड पुनरावृत्तियों के अपने संयोजन पर काम करेगा। दौड़ को हल करने का सबसे आसान तरीका समस्या रेखा की रक्षा के लिए महत्वपूर्ण omp का उपयोग करना है। मुझे स्वीकार करना होगा कि मुझे यकीन नहीं है कि क्या आप परमाणुओं का उपयोग लाइनों के साथ कर सकते हैं जिनमें सरणी वाक्यविन्यास शामिल है - मेरा अनुमान है कि आप नहीं कर सकते हैं। –

+0

एक साइड प्रश्न के रूप में: '** *' के बजाय 'a * a * a' के साथ तेजी से एक्सपोनेंटेशन है? – sigma

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