2012-11-07 13 views
9

मुख्य कार्यक्रम:इस ओपनएमपी कोड में सेगमेंटेशन गलती क्यों हो रही है?

program main                                      
    use omp_lib                                     
    use my_module                                     
    implicit none                                     

    integer, parameter :: nmax = 202000                               
    real(8) :: e_in(nmax) = 0.D0                                 
    integer i                                      

call omp_set_num_threads(2)                                  
!$omp parallel default(firstprivate)                                
!$omp do                                       
    do i=1,2                                      
    print *, e_in(i)                                   
    print *, eTDSE(i)                                   
    end do                                       
!$omp end do                                      
!$omp end parallel                                    
end program main 

मॉड्यूल:

module my_module                                     
    implicit none                                     

    integer, parameter, private :: ntmax = 202000                         
    double complex :: eTDSE(ntmax) = (0.D0,0.D0)                             
!$omp threadprivate(eTDSE)                                  

end module my_module 

संकलित का उपयोग कर:

ifort -openmp main.f90 my_module.f90 

यह विभाजन गलती जब निष्पादन देता है। यदि मुख्य कार्यक्रम में प्रिंट आदेशों में से एक को हटा दें, तो यह ठीक चलता है। इसके अलावा अगर omp फ़ंक्शन को हटा दें और बिना openmp विकल्प संकलित करें, तो यह भी ठीक चलता है।

उत्तर

16

इस व्यवहार के लिए सबसे संभावित कारण यह है कि आपकी स्टैक आकार सीमा बहुत छोटी है (किसी भी कारण से)। चूंकि e_in प्रत्येक ओपनएमपी थ्रेड के लिए निजी है, इसलिए थ्रेड स्टैक पर एक प्रति प्रति थ्रेड आवंटित किया गया है (भले ही आपने -heap-arrays निर्दिष्ट किया हो!)। 202000REAL(KIND=8) के तत्व 1616 केबी (या 1579 कीबी) लेते हैं।

ढेर आकार की सीमा कई तंत्रों के द्वारा नियंत्रित किया जा सकता है:

  • मानक यूनिक्स प्रणाली के गोले पर ढेर आकार की राशि ulimit -s <stacksize in KiB> द्वारा नियंत्रित है। यह मुख्य ओपनएमपी थ्रेड के लिए स्टैक आकार सीमा भी है। इस सीमा का मान POSIX थ्रेड (pthreads) लाइब्रेरी द्वारा नए धागे बनाते समय डिफ़ॉल्ट थ्रेड स्टैक आकार के रूप में भी प्रयोग किया जाता है।

  • ओपनएमपी अतिरिक्त थ्रेड के पर्यावरण चर OMP_STACKSIZE के माध्यम से स्टैक आकार सीमा पर नियंत्रण का समर्थन करता है। इसकी मान एक वैकल्पिक प्रत्यय k/K केबी, m/M एफआईआरआई एमआईबी, या g/G के लिए जीआईबी के लिए एक संख्या है। यह मान मुख्य धागे के ढेर आकार को प्रभावित नहीं करता है।

  • जीएनयू ओपनएमपी रन-टाइम (libgomp) गैर मानक पर्यावरण चर GOMP_STACKSIZE पहचानता है। यदि सेट किया गया है तो यह OMP_STACKSIZE के मान को ओवरराइड करता है।

  • इंटेल ओपनएमपी रन-टाइम गैर-मानक पर्यावरण परिवर्तनीय KMP_STACKSIZE को मान्यता देता है। यदि सेट किया गया है तो यह OMP_STACKSIZE के मान को ओवरराइड करता है और GOMP_STACKSIZE के मान को ओवरराइड करता है यदि संगतता ओपनएमपी रन-टाइम का उपयोग किया जाता है (जो वर्तमान में केवल उपलब्ध इंटेल ओपनएमपी रन-टाइम लाइब्रेरी compat एक डिफ़ॉल्ट है)।

  • *_STACKSIZE चर का कोई भी सेट कर रहे हैं, इंटेल OpenMP रन-टाइम के लिए डिफ़ॉल्ट 32-बिट आर्किटेक्चर पर 2m और 4m 64-बिट वालों पर है।

  • विंडोज़ पर, मुख्य धागे का ढेर आकार पीई हेडर का हिस्सा है और लिंकर द्वारा वहां एम्बेड किया गया है। यदि लिंक करने के लिए माइक्रोसॉफ्ट के LINK का उपयोग करते हैं, तो आकार /STACK:reserve[,commit] का उपयोग करके निर्दिष्ट किया गया है। reserve तर्क बाइट्स में अधिकतम स्टैक आकार निर्दिष्ट करता है जबकि वैकल्पिक commit तर्क प्रारंभिक प्रतिबद्ध आकार निर्दिष्ट करता है। दोनों को 0x उपसर्ग का उपयोग करके हेक्साडेसिमल मानों के रूप में निर्दिष्ट किया जा सकता है।यदि निष्पादन योग्य को पुनः लिंक करना एक विकल्प नहीं है, तो पीई हेडर को EDITBIN के साथ संपादित करके स्टैक आकार को संशोधित किया जा सकता है। यह लिंकर के रूप में एक ही स्टैक-संबंधित तर्क लेता है। एमएसवीसी के पूरे कार्यक्रम अनुकूलन सक्षम (/GL) के साथ संकलित प्रोग्राम संपादित नहीं किए जा सकते हैं।

  • Win32 लक्ष्यों के लिए जीएनयू लिंकर --stack तर्क के माध्यम से स्टैक आकार को सेट करने का समर्थन करता है। सीधे जीसीसी से विकल्प पास करने के लिए, -Wl,--stack,<size in bytes> का उपयोग किया जा सकता है।

ध्यान दें कि धागा ढेर वास्तव में आकार *_STACKSIZE द्वारा निर्धारित (या डिफ़ॉल्ट मान पर) के साथ आवंटित कर रहे हैं, मुख्य थ्रेड के ढेर है, जो छोटे शुरू होता है और फिर मांग पर सेट करने के लिए बढ़ता है के विपरीत सीमा। इसलिए *_STACKSIZE को मनमाने ढंग से बड़े मान पर सेट न करें अन्यथा आप वर्चुअल मेमोरी आकार सीमा को प्रभावित कर सकते हैं।

यहाँ कुछ उदाहरण हैं:

$ ifort -openmp my_module.f90 main.f90 

सेट 1 MiB करने के लिए मुख्य ढेर आकार सीमा (अतिरिक्त OpenMP धागा 4 MiB डिफ़ॉल्ट के अनुसार मिलेगा):

$ ulimit -s 1024 
$ ./a.out 
zsh: segmentation fault (core dumped) ./a.out 

मुख्य ढेर सेट 1700 किबा के लिए आकार सीमा:

$ ulimit -s 1700 
$ ./a.out 
    0.000000000000000E+000 
(0.000000000000000E+000,0.000000000000000E+000) 
    0.000000000000000E+000 
(0.000000000000000E+000,0.000000000000000E+000) 

2 MiB करने के लिए मुख्य ढेर आकार सीमा है और एक के ढेर आकार सेट करें 1 MiB को dditional धागा:

$ ulimit -s 2048 
$ KMP_STACKSIZE=1m ./a.out 
zsh: segmentation fault (core dumped) KMP_STACKSIZE=1m ./a.out 

सबसे यूनिक्स प्रणालियों पर मुख्य थ्रेड के ढेर आकार सीमा पीएएम या अन्य प्रवेश तंत्र (/etc/security/limits.conf देखें) द्वारा निर्धारित है। वैज्ञानिक लिनक्स 6.3 पर डिफ़ॉल्ट 10 एमआईबी है।

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

1 GiB के लिए वर्चुअल पता स्थान सीमा निर्धारित करें और 512 MiB के ढेर के साथ दो अतिरिक्त धागे (मैं omp_set_num_threads() करने के लिए कॉल बाहर टिप्पणी की है) के साथ चलाएँ:

$ ulimit -v 1048576 
$ KMP_STACKSIZE=512m OMP_NUM_THREADS=3 ./a.out 
OMP: Error #34: System unable to allocate necessary resources for OMP thread: 
OMP: System error #11: Resource temporarily unavailable 
OMP: Hint: Try decreasing the value of OMP_NUM_THREADS. 
forrtl: error (76): Abort trap signal 
... trace omitted ... 
zsh: abort (core dumped) OMP_NUM_THREADS=3 KMP_STACKSIZE=512m ./a.out 

इस मामले OpenMP रन-टाइम पुस्तकालय बनाने के लिए विफल हो जाएगा में एक नया धागा और कार्यक्रम समाप्त होने से पहले आपको सूचित करेगा।

+0

मैं याद नहीं सोचा था कि, यह है कि इन सरणियों सिर्फ 2 तत्व हैं।वैसे भी मैं अक्सर परिमाण के आदेशों से बड़े सरणी के साथ -स्टैक-एरे का उपयोग करता हूं। लेकिन इफोर्ट के साथ नहीं। –

+0

यह थोड़ा उलझन में है कि 'gfortran' और' ifort' दोनों के साथ स्थैतिक सरणी की निजी प्रतियां हमेशा स्वचालित होती हैं और किसी भी कंपाइलर विकल्पों के बावजूद थ्रेड स्टैक पर आवंटित होती हैं जो नियमित सरणी के प्लेसमेंट को प्रभावित कर सकती हैं। –

4

सेगमेंटेशन गलती ओपनएमपी का उपयोग करते समय स्टेक मेमोरी सीमा के कारण है। पिछले उत्तर से समाधान का उपयोग करने से मेरे विंडोज ओएस पर समस्या हल नहीं हुई। ढेर में ढेर स्मृति से स्मृति आवंटन का उपयोग करना नहीं बल्कि काम करने के लिए लगता है:

integer, parameter :: nmax = 202000 
real(dp), dimension(:), allocatable :: e_in 
integer i 

allocate(e_in(nmax)) 

e_in = 0 

! rest of code 

deallocate(e_in) 

प्लस यह किसी भी डिफ़ॉल्ट पर्यावरण मानकों को बदलने नहीं पहुंचेगी।

पावती के लिए और यहाँ ohm314 के समाधान का संदर्भ लें: large array using heap memory allocation

+1

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

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