Openmp question

Below is my file example.f95 that uses OpenMP:

subroutine pv_parallel(n, x, r, res)
  use omp_lib
  
  integer(8) :: n
  real(8) :: x(n), r, res
  integer(8) :: i
  
  res = 0.0d0
  
  !$omp parallel do reduction(+:res)
  do i = 1, n
    res = res + x(i)/(1 + r)**(i - 1)
  end do
  !$omp end parallel do  
end subroutine

!gfortran -fopenmp -fimplicit-none -fpic -shared example.f95 -o example.so

I would like to ask whether I am using OpenMP correctly in this file.
PS: is use omp_lib needed here? I am not using any functions/subroutines from it.

1 Like

By the looks of it, yes, this is correct as far as OpenMP is concerrned. Of course, as you do not initialise x, n and r to any value, the program will probably not produce anything useful, but then you do not write it to a file or screen :slight_smile:
A few points of criticism:

  • Do use “IMPLICIT NONE” - if you use it in a module, then only the module requires it, subroutines and functions inherit it.
  • Do not rely on a literal 8 as the real kind - while popular, it is not guaranteed to give you double-precision reals. There are far better and portable alternatives for that.
  • Why use integer(8)? Unless you plan to add more than 2000 million numbers, it seems a bit of overkill.
  • The workload in the iterations is very small, it could very well be that the overhead due to OpenMP is far exceeding the total workload of the loop. Given that this is merely your example, it is not of much importance, but such considerations could play a role in any serious program!
  • Also do not use a file extension “.f95”. The de facto standard is to use “.f90” for free-form Fortran code. Sometimes you see “.f95”, “.f03” etc. to indicate that the source code is intended to adhere any of these implied standards, but that is not generally supported and some compilers may not even accept such extensions.
5 Likes

PS: is use omp_lib needed here? I am not using any functions/subroutines from it.

No, using the module is not required.

1 Like

Here is my suggestion although I am not very experienced in OpenMP.
Usually I just print variables to check if I correctly use OpenMP, for example

subroutine pv_parallel(n, x, r, res)
  use omp_lib
  implicit none
  
  integer, parameter :: dp = kind(1d0)
  integer(dp) :: n
  real(dp) :: x(n), r, res
  integer :: i
  
  res = 0.0d0
  
  !$omp parallel do reduction(+:res)
  do i = 1, n
    res = res + x(i) / (1_dp+r)**(i-1)
    write(*,*) "i = ", i, "    thread_id = ", omp_get_thread_num()
  end do
  !$omp end parallel do  

end subroutine

I also modified the code according to @Arjen’s suggestion.

The execute result looks like:

$ gfortran test.f90 -fopenmp
$ ./a.out
 i =           10     thread_id =            9
 i =            1     thread_id =            0
 i =            8     thread_id =            7
 i =            5     thread_id =            4
 i =            9     thread_id =            8
 i =            6     thread_id =            5
 i =            7     thread_id =            6
 i =            4     thread_id =            3
 i =            3     thread_id =            2
 i =            2     thread_id =            1

Obviously OpenMP works well.
BTW, usually I will also compare the results between parallel version and serial version (by removing -fopenmp flag) to check if the result of parallel version is correct.

Finally, omp_lib contains several useful runtime subroutines and functions. You need to include use omp_lib if you want to use them. In my example above, I used omp_get_thread_num() which is a runtime function in omp_lib. If I don’t use it, just like your example, use omp_lib is not necessary.

2 Likes