OpenMP segmentation error with uncalled program subroutine [duplicate] - fortran

This question already has answers here:
Why Segmentation fault is happening in this openmp code?
(2 answers)
Closed 2 years ago.
I have a very strange error when I enable OpenMP in my compilation options. I have pinned it down to a call to a module subroutine using a dynamic sized array from my main program subroutine. Here is a simplified example:
module arr_mod
contains
subroutine add2_mod(arr)
integer, dimension(:) :: arr
integer i, n
n = size(arr)
do i=1,n
arr(i) = arr(i)+2
enddo
end subroutine
end module
PROGRAM TEST_OMP
use arr_mod
integer, dimension(2000000) :: array
array = 0
write(*,*) array(1)
contains
subroutine add2()
! Note that this subroutine is not even called in the main program...
! When the next line is commented, the program runs.
call add2_mod(array)
end subroutine
END PROGRAM TEST_OMP
When I compile and run this program without OpenMP, it runs fine:
$ gfortran -o test_omp test_omp.f90
$ ./test_omp
0
But when I use OpenMP, the program immediately segfaults:
$ gfortran -o test_omp test_omp.f90 -fopenmp
$ ./test_omp
[1] 10291 segmentation fault ./test_omp
If I remove the program subroutine (or simply comment the add2_mod call), it works fine even with OpenMP. It still works fine even if I call the add2_mod subroutine from the main program directly.
It also works when compiling with optimizations (tested with -O3), and when setting unlimited stack with ulimit -s unlimited.
As far as I can tell, it works fine with Intel Fortran (tested on version 17, with no specific flags other than -qopenmp).

As noted in the gfortran documentation:
-fopenmp implies -frecursive, i.e., all local arrays will be allocated on the stack. When porting existing code to OpenMP, this may lead to
surprising results, especially to segmentation faults if the stacksize
is limited.
To overcome this limitation, you can force the array on the heap with the allocatable specifier:
module arr_mod
contains
subroutine add2_mod(arr)
integer, dimension(:) :: arr
integer i, n
n = size(arr)
do i=1,n
arr(i) = arr(i)+2
enddo
end subroutine
end module
PROGRAM TEST_OMP
use arr_mod
integer, dimension(:), allocatable :: array ! array is allocated on the heap
allocate(array(2000000))
array = 0
write(*,*) array(1)
contains
subroutine add2()
call add2_mod(array)
end subroutine
END PROGRAM TEST_OMP
Which will work fine with the -fopenmp flag.

Related

Why does coarray with allocatable component creates segmentation faults when accessed from different image?

I want to use the fortran coarray feature to have different size arrays on different images.
Following the 2008/2018 standard, this should be possible by using a derived type containing an allocatable. I am using gfortran 8.2.0 with opencoarrays 2.3.1.1 MPI library on macOS Mojave.
program Main
implicit none
type :: Array_Type
double precision, dimension(:), allocatable :: values
end type
type(Array_Type), codimension[*] :: array
if(this_image() == 1) then
allocate(array%values(2))
array%values = this_image()
else
allocate(array%values(1))
endif
sync all
print *, this_image(), array[1]%values(:)
sync all
end program
The program is compiled by
gfortran -Wall -fcoarray=lib Main.f90 -lcaf_mpi
An even simpler example leads to the same segmentation fault when the allocated array is accessed by other images.
program Main
implicit none
type :: Array_Type
double precision, dimension(:), allocatable :: values
end type
type(Array_Type), codimension[*] :: array
allocate(array%values(2))
sync all
print *, this_image(), array[1]%values(:)
sync all
end program
Solution
The code works correctly with the specified system as long as MPICH instead of the default OpenMpi is used with OpenCoarrays.
Additionally, the OpenCoarrays compiler wrapper should be used: caf Main.f90
I opened an issue at the OpenCoarrays GitHub site: https://github.com/sourceryinstitute/OpenCoarrays/issues/625

Program stops due to array allocation in a function [duplicate]

The following code is returning a Segmentation Fault because the allocatable array I am trying to pass is not being properly recognized (size returns 1, when it should be 3). In this page (http://www.eng-tips.com/viewthread.cfm?qid=170599) a similar example seems to indicate that it should work fine in F95; my code file has a .F90 extension, but I tried changing it to F95, and I am using gfortran to compile.
My guess is that the problem should be in the way I am passing the allocatable array to the subroutine; What am I doing wrong?
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
PROGRAM test
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
IMPLICIT NONE
DOUBLE PRECISION,ALLOCATABLE :: Array(:,:)
INTEGER :: iii,jjj
ALLOCATE(Array(3,3))
DO iii=1,3
DO jjj=1,3
Array(iii,jjj)=iii+jjj
PRINT*,Array(iii,jjj)
ENDDO
ENDDO
CALL Subtest(Array)
END PROGRAM
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
SUBROUTINE Subtest(Array)
DOUBLE PRECISION,ALLOCATABLE,INTENT(IN) :: Array(:,:)
INTEGER :: iii,jjj
PRINT*,SIZE(Array,1),SIZE(Array,2)
DO iii=1,SIZE(Array,1)
DO jjj=1,SIZE(Array,2)
PRINT*,Array(iii,jjj)
ENDDO
ENDDO
END SUBROUTINE
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%!
If a procedure has a dummy argument that is an allocatable, then an explicit interface is required in any calling scope.
(There are numerous things that require an explicit interface, an allocatable dummy is but one.)
You can provide that explicit interface yourself by putting an interface block for your subroutine inside the main program. An alternative and far, far, far better option is to put the subroutine inside a module and then USE that module in the main program - the explicit interface is then automatically created. There is an example of this on the eng-tips site that you provided a link to - see the post by xwb.
Note that it only makes sense for a dummy argument to have the allocatable attribute if you are going to do something related to its allocation status - query its status, reallocate it, deallocate it, etc.
Please also note that your allocatable dummy argument array is declared with intent(in), which means its allocation status will be that of the associated actual argument (and it may not be changed during the procedure). The actual argument passed to your subroutine may be unallocated and therefore illegal to reference, even with an explicit interface. The compiler will not know this and the behaviour of inquiries like size is undefined in such cases.
Hence, you first have to check the allocation status of array with allocated(array) before referencing its contents. I would further suggest to implement loops over the full array with lbound and ubound, since in general you can't be sure about array's bounds:
subroutine subtest(array)
double precision, allocatable, intent(in) :: array(:,:)
integer :: iii, jjj
if(allocated(array)) then
print*, size(array, 1), size(array, 2)
do iii = lbound(array, 1), ubound(array, 1)
do jjj = lbound(array, 2), ubound(array, 2)
print*, array(iii,jjj)
enddo
enddo
endif
end subroutine
This is a simple example that uses allocatable dummy arguments with a module.
module arrayMod
real,dimension(:,:),allocatable :: theArray
end module arrayMod
program test
use arrayMod
implicit none
interface
subroutine arraySub
end subroutine arraySub
end interface
write(*,*) allocated(theArray)
call arraySub
write(*,*) allocated(theArray)
end program test
subroutine arraySub
use arrayMod
write(*,*) 'Inside arraySub()'
allocate(theArray(3,2))
end subroutine arraySub

Openmp parallel workshare for allocatable array

I want to do some element-wise calculation on arrays in Fortran 90, while parallelize my code with openmp. I have now the following code :
program test
implicit none
integer,parameter :: n=50
integer :: i
integer(8) :: t1,t2,freq
real(8) :: seq(n),r(n,n,n,n)
real(8),dimension(n,n,n,n) :: x
call system_clock(COUNT_RATE=freq)
seq=[(i,i=1,n)]
x=spread(spread(spread(seq,2,n),3,n),4,n)
call system_clock(t1)
!$omp parallel workshare
! do some array calculation
r=atan(exp(-x))
!$omp end parallel workshare
call system_clock(t2)
print*, sum(r)
print '(f6.3)',(t2-t1)/real(freq)
end program test
I want now to replace the static arrays x and r with allocatable arrays, so I type :
real(8),dimension(:,:,:,:),allocatable :: x,r
allocate(x(n,n,n,n))
allocate(r(n,n,n,n))
but that the program run in serial without errors and the compiler doesn't take account of the line "!$omp parallel workshare".
What options should I use to parallelize in this case? I have tried with omp parallel do with loops but it is much slower.
I am compiling my code with gfortran 5.1.0 on windows :
gfortran -ffree-form test.f -o main.exe -O3 -fopenmp -fno-automatic
I have come across this issue in gfortran before. The solution is to specify the array in the following form:
!$omp parallel workshare
! do some array calculation
r(:,:,:,:) = atan(exp(-x))
!$omp end parallel workshare
Here is the reference.

Fortran arrays in hybrid MPI/OpenMP

I am facing the following issue when running a hybrid MPI/OpenMP
code with GNU and Intel compilers and OpenMPI. The code is big (commercial)
written in Fortran. It compiles and runs fine with GNU compilers
but crashes with Intel compilers.
I have monitored the part of the code when the program stops working,
it has the following structure:
subroutine test(n,dy,dy)
integer :: i
integer, parameter :: n=6
real*8 :: dx(num),dy(num), ener
ener=0.0
!$omp parallel num_threads(2)
!$omp do
do i=1,100
ener = ener + funct(n,dx,dy) + i
enddo
!$omp end do
!$omp end parallel
end subroutine test
and the function funct has this structure:
real*8 function funct(n,dx,dy)
integer :: n
real*8 :: dx(*),dy(*)
funct = 0.0
do i=1,n
funct = funct + dx(i)+dy(i)
enddo
end function funct
Specifically the code stops inside funct (with Intel). The
program is able to get the end of funct but only one thread
of the two requested is able to return the value, I checked
that by printing the thread numbers.
This issue is only for Intel compilers, for GNU I don't get
the issue.
One way to avoid the issue, I found, is by using plain arrays
inside funct as follows:
real*8 function funct(n,dx,dy)
integer :: n
real*8 :: dx(n),dy(n)
but my point is that I don't understand what is happening.
My guess is that in the Intel case, the compiler cannot
figure out the length of dx and dy inside funct but I am
not sure. I tried to reproduce this issue with a small
Fortran program but I was not able to see that issue.
Any comment is welcome.
One update: I eliminated the issue with the race condition (this is
not the real problem, what I wrote here was the structure of the code).
I realized that subroutinetest is being called from another subroutine
upper which defines dx,dy as pointers:
subroutine upper
real*8,save,pointer :: dx(:)=>Null(), dy(:)=>Null()
....
call test(n,dx,dy)
...
end subroutine upper
what I did now, was to replace pointers by allocatables:
subroutine upper
real*8,save,dimension(:),allocatable :: dx,dy
....
allocate(dx(n),dy(n))
call test(n,dx,dy)
...
end subroutine upper
and I don't get the issue with Intel. I don't know what could be the
difference between pointers and allocatables.
Thanks.

How to force fortran compiler to generate an error in case of violation "intent(in)" by subroutine with omitted intent

This question is connected to my previous question: How to force compiler to interpret omitted intent as intent(inout) . It appears impossible to interpret omitted intent as intent(inout), so problem of violation of intent(in) is still exists.
The same example:
module test
implicit none
contains
subroutine fun1(x)
real(8), intent(in)::x
call fun2(x)
end subroutine
subroutine fun2(x)
real(8) :: x
x = 10
end subroutine
end module
This code can be compiled without any errors/warnings by gfortran and ifort. So my questions is:
How to force fortran compiler to generate an error when intent(in) variable is passed to subroutine with omitted intent ( but with declared interface)?
As IanH said you need a processor (i.e. compiler) that can pick this up for you. For instance the NAG compiler does (disclaimer - I work for NAG) if you give it the right flags. I modified your code a very little to make it portable and added a driver to show this:
$ cat t.f90
module test
implicit none
Integer, Parameter :: wp = Selected_real_kind( 12, 70 )
contains
subroutine fun1(x)
real(wp), intent(in)::x
call fun2(x)
end subroutine
subroutine fun2(x)
real(wp) :: x
x = 10
end subroutine
end module
Program test_test
Use test
Implicit None
Real( wp ) :: x
x = 5.0_wp
Call fun1( x )
End Program test_test
$ nagfor t.f90
NAG Fortran Compiler Release 5.3.1 pre-release(904)
[NAG Fortran Compiler normal termination]
$ ./a.out
$ nagfor -C=all -C=undefined t.f90
NAG Fortran Compiler Release 5.3.1 pre-release(904)
[NAG Fortran Compiler normal termination]
$ ./a.out
Runtime Error: t.f90, line 15: Dummy argument X is associated with an expression - cannot assign
Program terminated by fatal error
Aborted (core dumped)
$
So search the flags, there may be something to help - if not complain to whoever supplies the compiler!