2012-11-07 31 views
9

chương trình chính:Tại sao lỗi phân đoạn xảy ra trong mã openmp này?

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 

mô-đun:

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 

biên soạn sử dụng:

ifort -openmp main.f90 my_module.f90 

Nó cung cấp cho các lỗi Segmentation khi thực hiện. Nếu loại bỏ một trong các lệnh in trong chương trình chính, nó chạy tốt. Ngoài ra, nếu loại bỏ các chức năng omp và biên dịch mà không có tùy chọn -openmp, nó cũng chạy tốt.

Trả lời

16

Nguyên nhân có thể xảy ra nhất đối với hành vi này là giới hạn kích thước ngăn xếp của bạn quá nhỏ (vì bất kỳ lý do gì). Vì e_in là riêng tư cho mỗi chuỗi OpenMP, một bản sao cho mỗi luồng được phân bổ trên ngăn xếp luồng (ngay cả khi bạn đã chỉ định -heap-arrays!). 202000 yếu tố của REAL(KIND=8) mất 1616 kB (hoặc 1579 KiB).

Kích thước giới hạn ngăn xếp có thể được điều khiển bởi một số cơ chế:

  • Mở vỏ hệ thống Unix chuẩn số lượng ngăn xếp kích thước được điều khiển bởi ulimit -s <stacksize in KiB>. Đây cũng là giới hạn kích thước ngăn xếp cho luồng OpenMP chính. Giá trị của giới hạn này cũng được sử dụng bởi thư viện chủ đề POSIX (pthreads) làm kích thước ngăn xếp mặc định khi tạo chuỗi mới.

  • OpenMP hỗ trợ kiểm soát giới hạn kích thước ngăn xếp của tất cả bổ sung chủ đề qua biến môi trường OMP_STACKSIZE. Giá trị của nó là một số có hậu tố tùy chọn k/K cho KiB, m/M ffor MiB hoặc g/G cho GiB. Giá trị này không ảnh hưởng đến kích thước ngăn xếp của chuỗi chính.

  • Thời gian chạy GNU OpenMP (libgomp) nhận ra biến môi trường không chuẩn GOMP_STACKSIZE. Nếu đặt giá trị này ghi đè giá trị OMP_STACKSIZE.

  • Thời gian chạy Intel OpenMP nhận ra biến môi trường không chuẩn KMP_STACKSIZE. Nếu đặt giá trị này ghi đè giá trị OMP_STACKSIZE và cũng ghi đè giá trị GOMP_STACKSIZE nếu thời gian chạy OpenMP tương thích được sử dụng (mặc định là thư viện thời gian chạy Intel OpenMP hiện có duy nhất là compat).

  • Nếu không có biến số *_STACKSIZE nào được đặt, mặc định cho thời gian chạy Intel OpenMP là 2m trên kiến ​​trúc 32 bit và 4m trên các bit 64 bit.

  • Trên Windows, kích thước ngăn xếp của sợi chính là một phần của tiêu đề PE và được nhúng bởi trình liên kết. Nếu sử dụng LINK của Microsoft để thực hiện liên kết, kích thước được chỉ định bằng cách sử dụng /STACK:reserve[,commit]. Đối số reserve chỉ định kích thước ngăn xếp tối đa theo byte trong khi đối số tùy chọn commit chỉ định kích thước cam kết ban đầu. Cả hai có thể được chỉ định dưới dạng giá trị thập lục phân sử dụng tiền tố 0x.Nếu việc liên kết lại tệp thực thi không phải là một tùy chọn, kích thước ngăn xếp có thể được sửa đổi bằng cách chỉnh sửa tiêu đề PE với EDITBIN. Nó có cùng một đối số liên quan đến stack với tư cách là trình liên kết. Các chương trình được biên dịch với toàn bộ chương trình tối ưu hóa của MSVC được bật (/GL) không thể chỉnh sửa được.

  • Trình liên kết GNU dành cho mục tiêu Win32 hỗ trợ đặt kích thước ngăn xếp qua đối số --stack. Để chuyển tùy chọn trực tiếp từ GCC, có thể sử dụng -Wl,--stack,<size in bytes>.

Lưu ý rằng ngăn xếp chủ đề đang thực sự phân bổ với kích thước được thiết lập bởi *_STACKSIZE (hoặc giá trị mặc định), không giống như chồng các chủ đề chính, mà bắt đầu nhỏ và sau đó phát triển theo yêu cầu đến hộp set giới hạn. Vì vậy, không đặt *_STACKSIZE thành giá trị lớn tùy ý nếu không bạn có thể đạt đến giới hạn kích thước bộ nhớ ảo của quá trình.

Dưới đây là một số ví dụ:

$ ifort -openmp my_module.f90 main.f90 

Đặt giới hạn chính ngăn xếp kích thước đến 1 MiB (thread OpenMP bổ sung sẽ nhận được 4 MiB theo mặc định):

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

Đặt stack chính giới hạn kích thước đến 1700 KiB:

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

Đặt giới hạn kích thước ngăn xếp chính thành 2 MiB và kích thước ngăn xếp của Chủ đề dditional tới 1 MiB:

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

Trên hầu hết các hệ thống Unix giới hạn kích thước ngăn xếp của các chủ đề chính được thiết lập bởi PAM hoặc cơ chế đăng nhập khác (xem /etc/security/limits.conf). Mặc định trên Scientific Linux 6.3 là 10 MiB.

Một trường hợp khác có thể dẫn đến lỗi là nếu giới hạn không gian địa chỉ ảo được đặt quá thấp. Ví dụ, nếu giới hạn không gian địa chỉ ảo là 1 GiB và giới hạn kích thước ngăn xếp luồng được đặt là 512 MiB, thì thời gian chạy OpenMP sẽ cố gắng phân bổ 512 MiB cho mỗi chuỗi bổ sung. Với hai chủ đề sẽ có 1 GiB cho ngăn xếp, và khi không gian cho mã, thư viện được chia sẻ, heap, vv được thêm lên, kích thước bộ nhớ ảo sẽ phát triển vượt quá 1 GiB và một lỗi sẽ xảy ra:

Đặt giới hạn không gian địa chỉ ảo tới 1 GiB và chạy với hai chủ đề bổ sung với 512 đống MiB (tôi đã nhận xét ra các cuộc gọi đến 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 

Trong trường hợp này OpenMP thư viện thời gian chạy sẽ thất bại trong việc tạo ra một chủ đề mới và sẽ thông báo cho bạn trước khi hủy bỏ việc chấm dứt chương trình.

+0

tôi bị mất rằng, nghĩ rằng những mảng chỉ là 2 yếu tố.Dù sao tôi thường sử dụng -fstack-mảng với mảng lớn hơn theo đơn đặt hàng của cường độ. Nhưng không phải với Ifort. –

+0

Có một chút khó hiểu rằng với cả 'gfortran' và' ifort' các bản sao riêng của mảng tĩnh luôn tự động và được cấp phát trên ngăn xếp luồng mặc dù có bất kỳ tùy chọn trình biên dịch nào có thể ảnh hưởng đến vị trí của các mảng thông thường. –

4

Lỗi phân đoạn là do giới hạn bộ nhớ ngăn xếp khi sử dụng OpenMP. Sử dụng các giải pháp từ câu trả lời trước đã không giải quyết được vấn đề cho tôi trên hệ điều hành Windows của tôi. Sử dụng cấp phát bộ nhớ vào bộ nhớ heap thay vì bộ nhớ ngăn xếp dường như hoạt động:

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) 

Thêm vào đó sẽ không liên quan đến việc thay đổi bất kỳ thông số môi trường mặc định nào.

Lời cảm ơn đến và tham khảo giải pháp ohm314 ở đây: large array using heap memory allocation

+1

Kích thước ngăn xếp chính của các ứng dụng Windows được chỉ định tại thời gian liên kết và không thể kiểm soát tự do sau đó giống như trên hầu hết các hệ thống Unix. Câu trả lời của tôi là cụ thể cho Unix. Tôi sẽ thêm một phần về Windows. Tất nhiên, phân bổ đống là giải pháp tốt nhất, ngoại trừ khi người ta không thể thực sự đủ khả năng để thay đổi mã. –

Các vấn đề liên quan