Run only part of fortran coarray code parallel rest serial - parallel-processing

I have a main program that has subroutine written using coarrays. The problem is that while running the code it treats the entire code (main + subroutine) as parallel code and runs it on all specified processors. For eg., the Below program prints "Hello from main" four times when running using 4 CPUs. I want that the main program runs on one CPU while when it encounters a subroutine that uses coarrays it runs on all specified CPUs.
Main program that call subroutine coarray_test
program main
implicit none
write (*,*) "Hello from main "
call coarray_test
end program
Subroutine coarray_test
subroutine coarray_test
implicit none
write (*,*) "Hello from Subroutine coarray_test "
return
end subroutine coarray_test
Command used for compile and execution
export FOR_COARRAY_NUM_IMAGES=4
ifort -g -coarray -o test.out main.f90 coarray_test.f90
./test.out
Output
Hello from main
Hello from Subroutine coarray_test
Hello from main
Hello from Subroutine coarray_test
Hello from main
Hello from Subroutine coarray_test
Hello from main
Hello from Subroutine coarray_test
Expected Output
Hello from main
Hello from Subroutine coarray_test
Hello from Subroutine coarray_test
Hello from Subroutine coarray_test
Hello from Subroutine coarray_test

You are misunderstanding the CAF model. It is based, like MPI, on independent processes. So the whole code is executed by each process. If you want some part executed byonly one process you can say if (image==0).
But think:
if only one process computes something, how are the other ones going to get that result?
and what do you gain from only one process being active? The other ones are idle while they could be doing useful work.
Really, the bits that you want executed only once, probably need to be done redundantly on all processes. With the exeception of print statements and other I/O.

Related

Compile Module and Main Program In the Same File Using GFortran?

I am new to fortran and I have this fortran90 program I am trying to run where the module and the main are in the same file called main.f90:
module real_precision
implicit none
integer, parameter :: sp = selected_real_kind(1)
integer, parameter :: dp = selected_real_kind(15)
end module real_precision
program main_program
use real_precision
implicit none
real(sp) :: a = 1.0_sp
real(dp) :: b = 1.0_dp
print *, a
print *, b
end program main_program
And I compiled it once doing:
gfortran main.f90 -o main.x
Then run it:
./main.x
However I made a change to the module and saved it but compiling and running it this same way provides the same output which leads me to think that the module needs to be compiled? How do I compile both where they're in the same file? I could make the module a separate file but I'd like to know how to do it this way!
selected_real_kind(p) returns the kind parameter of a real with precision at least p digits (if one exists). It does not give a kind parameter for a real with exactly that precision.
If your compiler has does not have a real with precision less than q then selected _real_kind(q) and selected_real_kind(q-1) will not return different kind parameters.

External naming of fortran subroutine inside a module using GCC

My objectif is to rename a fortran subroutine inside a module to be easily callable by C code (i.e. without the __<modulename>_MOD_ prefix), and using GCC-6.3.0. I cannot use bind(c,name='') even if it works great. I have read that I should use interface, but without any success. Here is the MWE:
module testmodule
interface
subroutine func02
!GCC$ ATTRIBUTES CDECL :: func01
end subroutine
end interface
contains
subroutine func01
print*,"func01"
end subroutine
end module
I compile using command gfortran -c test.f90 and then I check if the subroutine is correctly renamed using nm test.o, but there is no sign of func02.
Any help appreciated.
You can use BIND(C) to rename the subroutine. Whatever you read about INTERFACE seems to be a red herring.
module testmodule
contains
subroutine func01() bind(c, name='func2')
print*,"func01"
end subroutine
end module
With the simple command 'gfortran -c a.f90', I see the following results
nm a.o
U _gfortran_st_write
U _gfortran_st_write_done
U _gfortran_transfer_character_write
00000000 T func2

Unable to suppress bound checking

Firstly, I wasn't aware that bound checking was automatic when using gfortran. With the following code:
gfortran -Wno-array-bounds initial_parameters.f08 derrived_types.f08 lin_alg.f08 constitutive_models.f08 input_subs.f08 Subprograms.f08 mainprog.f08
I still receive the compile time warnings:
Warning: Array reference at (1) is out of bounds (3 > 2) in dimension 2
I am probably being silly here but from reading this, I thought that -Wno-array-bounds was supposed to suppress this warning? Compiling with -w successfully inhibits all warnings.
I don't know if it's relevant but the source of these warning are "Subprograms.f08" and "constitutive_models.f08" which are both modules containing subroutines and are used in the main program.
The same behaviour occurs if I attempt to compile an individual module with
gfortran -Wno-array-bounds -c constitutive_models.f08
I can confirm that compile warning with gfortran (4.4) with this simple code:
integer,parameter::dim=3
integer :: x(2)
if(dim.eq.1)write(*,*)x(dim)
end
Warning: Array reference at (1) is out of bounds (3 > 2) in dimension 2
this could arguably be considered a bug since one would expect the compiler to optimize out the whole if statement. Note ifort compiles this just fine.
a very simple workaround fixes this example:
integer,parameter::dim=3
integer :: x(2),dimx=dim
if(dim.eq.1)write(*,*)x(dimx)
end
of course since its just a warning, and you know its not a problem, you can choose to ignore it too !
note the use of the parameter in the logical, in case the compiler feels like optimizing it later.
So what I may suggest is to use overloaded subroutines in order to process the data - then you would have generic behavior without the need to pass the dimension argument explicitly to the function(thus getting rid of the warning). And then I would recommend you to follow Holmz's advice regarding using all warnings during testing stage and then completely turning them off during production build (-w). For now I wasn't able to find an efficient way of suppressing this warning (apart from -w) - it seems that the check for array bounds is on by default and is not overridden -fno-bounds-check or -Wno-array-bounds. But overloaded functions can be a better solution to your problem, the implementation should look like this in this case:
module functions
implicit none
interface test_dim
module procedure test_func1d, test_func2d, test_func3d
end interface ! test_dim
contains
subroutine test_func1d(input1d)
real, intent(in) :: input1d(:)
print*, "DOING 1 DIM"
print*, "SHAPE OF ARRAY:", shape(input1d)
end subroutine test_func1d
subroutine test_func2d(input2d)
real, intent(in) :: input2d(:,:)
print*, "DOING 2 DIM"
print*, "SHAPE OF ARRAY:", shape(input2d)
end subroutine test_func2d
subroutine test_func3d(input3d)
real, intent(in) :: input3d(:,:,:)
print*, "DOING 3 DIM"
print*, "SHAPE OF ARRAY:", shape(input3d)
end subroutine test_func3d
end module functions
program test_prog
use functions
implicit none
real :: case1(10), case2(20,10), case3(30, 40, 20)
call test_dim(case1)
call test_dim(case2)
call test_dim(case3)
end program test_prog
And the output produced by this function looks like this:
DOING 1 DIM
SHAPE OF ARRAY: 10
DOING 2 DIM
SHAPE OF ARRAY: 20 10
DOING 3 DIM
SHAPE OF ARRAY: 30 40 20

Confusing debugging error in Fortran program

I've been sitting here for a while quite baffled as to why my debugger keeps displaying an error in my code when the program runs fine. There are three parts to a very simple program that is just reading in information from a file.
My code is broken into three Fortran files given below and compiled via
ifort -o test global.f90 read.f90 test.f90
global.f90:
module global
implicit none
integer(4), parameter :: jsz = 904
end module global
read.f90:
subroutine read(kp,q,wt,swt)
implicit none
integer(4) :: i, j
integer(4), intent(in) :: kp
real(8), intent(out) :: swt, q(kp,3), wt(kp)
swt = 0.0d0; q(:,:) = 0.0d0; wt(:) = 0.0d0
open(7,file='test.dat')
read(7,*) ! Skipping a line
do i = 1, kp
read(7,1000)(q(i,j),j=1,3), wt(i)
swt = swt + wt(i)
end do
close(7)
return
1000 format(3F10.6,1X,1F10.6)
end subroutine read
test.f90:
program test
use global
integer(4) :: i, j
real(8) :: tot, qq(jsz,3), wts(jsz)
call read(jsz,qq,wts,tot)
stop
end program test
The error I keep receiving is
Breakpoint 1, read (kp=904,
q=<error reading variable: Cannot access memory at address 0x69bb80>,
wt=..., swt=6.9531436082559572e-310) at read.f90:6
This error appears right when the subroutine of read is called. In other words, I'm adding a breakpoint at the read subroutine and running the code in gdb after the breakpoint is added. The program will continue to run as expected and give the correct outputs when I include write statements in the 'test' program. However, if I use the gdb print options I receive an error of 'Cannot access memory at address 0x69bb80' for array q only. All other arrays and variables can be displayed with no problems.
As I would like the read subroutine to be a stand alone subroutine and not necessarily use any global parameters, I have not used the global module and instead called the variable kp into the subroutine. I decided to test whether using the global module would help, and if I use jsz in place of kp, I do indeed remove the error. However, since this isn't my overall goal with the subroutine, I would hopefully like to figure out how to fix this without the use of the global module. (I also tried not using the global at all and setting the parameter variable of kp in the test.f90 program directly, but this also gives the error.)
Any insight on possible reasons for this error, or suggestions to try and fix the memory addressing issue would be greatly appreciated.
I think this is an issue specific to the ifort+gdb combination that is fixed with newer gdb versions. Here's a smaller example to reproduce the issue:
$ cat test.f90
subroutine bar(arg)
integer, intent(inout):: arg
print *, 'bar argument is', arg
arg = 42
end subroutine bar
program test
integer:: param
param = 3
call bar(param)
print *, 'post-bar param:', param
end program test
$ ifort -g -O0 -o test test.f90
$ gdb --quiet test
Reading symbols from /home/nrath/tmp/test...done.
(gdb) b 4
Breakpoint 1 at 0x402bd0: file test.f90, line 4.
(gdb) r
Starting program: /home/nrath/tmp/test
[Thread debugging using libthread_db enabled]
Breakpoint 1, bar (arg=#0x2aaa00000003) at test.f90:4
4 print *, 'bar argument is', arg
(gdb) p arg
$1 = (REF TO -> ( INTEGER(4) )) #0x2aaa00000003: <error reading variable>
(gdb) quit
$ gdb --version | head -1
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
However, if you compile with gfortran instead of ifort, or if you use GDB 7.7.1, it works fine.
Did you add the INTERFACE statement to the end of your programme?
You need it when you call a function that is not contained in the programme.

OpenMP in FORTRAN does not run expected number of threads

I am new to parallel programming, and am having trouble getting a simple parallel Fortran program to use multiple threads in OpenMP. The following program:
Program Hello
Use omp_lib
Implicit None
INTEGER nthreads
nthreads = 4
CALL OMP_SET_NUM_THREADS(nthreads)
write(*,*) omp_get_num_procs()
write(*,*) omp_get_max_threads()
write(*,*) omp_get_num_threads()
!$OMP PARALLEL
Write(*,*) 'Hello'
Write(*,*) omp_get_num_threads()
!%OMP END PARALLEL
End Program Hello
Produces the result:
32
4
1
Hello
1
What is the reason that the number of threads inside the parallel region is not the same as nthreads that I set above? I am compiling the program using gfortran -f openmp Hello.f on a Windows machine running cygwin.
I try it compiling in Linux with gfortran. And I get error because the OMP directives. I changed it to:
!$OMP PARALLEL
Write(*,*) 'Hello'
Write(*,*) omp_get_num_threads()
!$OMP END PARALLEL
(Notice !$OMP). And now it works. The output:
$ ./a.out
16
4
1
Hello
4
Hello
4
Hello
4
Hello
4
The sentinel, i.e. !$omp or *$omp or c$omp must appear at the beginning of the line by itself.
It simply launches a single thread otherwise and doesn't complain.
!$OMP PARALLEL
Write(*,*) 'Hello'
Write(*,*) omp_get_num_threads()
!$OMP END PARALLEL
I don't know if it's the issue or not, but the last directive in the OP's code has a % instead of a $. May be just a typo, but I had recently posted code that a silly typo like that caused me trouble.

Resources