I find the comparison to be similar for Concurrent and OpenMP do loops. Here is my understanding and testing results.
First i replace call cpu_time with call system_clock. Then make two programs. One for dc and other for OpenMP.
- Do Concurrent (dc) code
! Concurrent do loop program
!
! windows 10, intel classic compiler
! =======================================
!
! ifort main_dc.f90 /Qopenmp /F5000000 /Qopt-report-phase:openmp
program poisson_solver
implicit none
integer, parameter :: nx=512, ny=512, max_iter=10000
real, parameter :: tol=1.0e-6, dx=1.0/(nx-1), dy=1.0/(ny-1)
real :: phi_old(nx,ny), phi_new(nx,ny), residual(nx,ny)
real :: maxdiff
integer :: i, j, iter
integer(8) :: rate, start_time, end_time
! Initialize with random guess
call random_seed()
call random_number(phi_old)
phi_new = phi_old
! Apply Dirichlet BCs: zero on edges
phi_old(1,:) = 0.0; phi_old(nx,:) = 0.0
phi_old(:,1) = 0.0; phi_old(:,ny) = 0.0
phi_new(1,:) = 0.0; phi_new(nx,:) = 0.0
phi_new(:,1) = 0.0; phi_new(:,ny) = 0.0
print *, "Start solving..."
! Start timer
call system_clock (count=start_time , count_rate=rate)
! Jacobi Iteration
time_loop:do iter = 1, max_iter
maxdiff = 0.0
do concurrent (j=2:ny-1,i=2:nx-1) default (none) shared(phi_old, phi_new)
phi_new(i,j) = 0.25 * (phi_old(i+1,j) + phi_old(i-1,j) + phi_old(i,j+1) + phi_old(i,j-1))
end do
do concurrent (j=2:ny-1,i=2:nx-1) default (none) shared(phi_new, residual)
residual(i,j) = 0.25*(phi_new(i+1,j) + phi_new(i-1,j) + phi_new(i,j+1) + phi_new(i,j-1)) - phi_new(i,j)
end do
maxdiff = maxval(abs(residual(2:nx-1,2:ny-1)))
phi_old = phi_new
if (mod(iter,1000)==0) print *, 'Iter:', iter, ' Maxdiff:', maxdiff
if (maxdiff < tol) exit
end do time_loop
! End timer
call system_clock (count=end_time)
print *, 'Converged after', iter, 'iterations with maxdiff =', maxdiff
print *, 'Time taken (seconds):', real(max(end_time - start_time , 1_8 )) /real(rate),' seconds'
end program poisson_solver
- OpenMP code is
! OpenMP do loop program
!
! windows 10, intel classic compiler
! =======================================
!
! ifort main_omp.f90 /Qopenmp /F5000000 /Qopt-report-phase:openmp
program poisson_solver
implicit none
integer, parameter :: nx=512, ny=512, max_iter=10000
real, parameter :: tol=1.0e-6, dx=1.0/(nx-1), dy=1.0/(ny-1)
real :: phi_old(nx,ny), phi_new(nx,ny), residual(nx,ny)
real :: maxdiff
integer :: i, j, iter
integer(8) :: rate, start_time, end_time
! Initialize with random guess
call random_seed()
call random_number(phi_old)
phi_new = phi_old
! Apply Dirichlet BCs: zero on edges
phi_old(1,:) = 0.0; phi_old(nx,:) = 0.0
phi_old(:,1) = 0.0; phi_old(:,ny) = 0.0
phi_new(1,:) = 0.0; phi_new(nx,:) = 0.0
phi_new(:,1) = 0.0; phi_new(:,ny) = 0.0
print *, "Start solving..."
! Start timer
call system_clock (count=start_time , count_rate=rate)
! Jacobi Iteration
time_loop:do iter = 1, max_iter
maxdiff = 0.0
!$omp parallel do private(i,j) shared(phi_old, phi_new)
do j = 2, ny - 1
do i = 2, nx - 1
phi_new(i,j) = 0.25 * (phi_old(i+1,j) + phi_old(i-1,j) + phi_old(i,j+1) + phi_old(i,j-1))
end do
end do
!$omp end parallel do
!$omp parallel do private(i,j) shared(phi_new, residual)
do j = 2, ny - 1
do i = 2, nx - 1
residual(i,j) = 0.25*(phi_new(i+1,j) + phi_new(i-1,j) + phi_new(i,j+1) + phi_new(i,j-1)) - phi_new(i,j)
end do
end do
!$omp end parallel do
maxdiff = maxval(abs(residual(2:nx-1,2:ny-1)))
phi_old = phi_new
if (mod(iter,1000)==0) print *, 'Iter:', iter, ' Maxdiff:', maxdiff
if (maxdiff < tol) exit
end do time_loop
! End timer
call system_clock (count=end_time)
print *, 'Converged after', iter, 'iterations with maxdiff =', maxdiff
print *, 'Time taken (seconds):', real(max(end_time - start_time , 1_8 )) /real(rate),' seconds'
end program poisson_solver
Testing
Concurrent do loop
D:\testing_gfortran15Version\comparison>ifort main_dc.f90 /Qopenmp /F5000000 /Qopt-report-phase:openmp
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.13.0 Build 20240602_000000
Copyright (C) 1985-2024 Intel Corporation. All rights reserved.
ifort: remark #10448: Intel(R) Fortran Compiler Classic (ifort) is now deprecated and will be discontinued late 2024. Intel recommends that customers transition now to using the LLVM-based Intel(R) Fortran Compiler (ifx) for continued Windows* and Linux* support, new language support, new language features, and optimizations. Use '/Qdiag-disable:10448' to disable this message.
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation. All rights reserved.
-out:main_dc.exe
-subsystem:console
-stack:5000000
-defaultlib:libiomp5md.lib
-nodefaultlib:vcomp.lib
-nodefaultlib:vcompd.lib
main_dc.obj
D:\testing_gfortran15Version\comparison>main_dc
Start solving...
Iter: 1000 Maxdiff: 2.9246032E-02
Iter: 2000 Maxdiff: 1.8029779E-02
Iter: 3000 Maxdiff: 1.4946640E-02
Iter: 4000 Maxdiff: 1.2880355E-02
Iter: 5000 Maxdiff: 1.1320204E-02
Iter: 6000 Maxdiff: 1.0075003E-02
Iter: 7000 Maxdiff: 9.0442300E-03
Iter: 8000 Maxdiff: 8.1699193E-03
Iter: 9000 Maxdiff: 7.4144900E-03
Iter: 10000 Maxdiff: 6.7545176E-03
Converged after 10001 iterations with maxdiff = 6.7545176E-03
Time taken (seconds): 2.525000 seconds
OpenMP do loop
D:\testing_gfortran15Version\comparison>ifort main_omp.f90 /Qopenmp /F5000000 /Qopt-report-phase:openmp
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.13.0 Build 20240602_000000
Copyright (C) 1985-2024 Intel Corporation. All rights reserved.
ifort: remark #10448: Intel(R) Fortran Compiler Classic (ifort) is now deprecated and will be discontinued late 2024. Intel recommends that customers transition now to using the LLVM-based Intel(R) Fortran Compiler (ifx) for continued Windows* and Linux* support, new language support, new language features, and optimizations. Use '/Qdiag-disable:10448' to disable this message.
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation. All rights reserved.
-out:main_omp.exe
-subsystem:console
-stack:5000000
-defaultlib:libiomp5md.lib
-nodefaultlib:vcomp.lib
-nodefaultlib:vcompd.lib
main_omp.obj
D:\testing_gfortran15Version\comparison>main_omp
Start solving...
Iter: 1000 Maxdiff: 1.7876625E-02
Iter: 2000 Maxdiff: 1.2360156E-02
Iter: 3000 Maxdiff: 9.5547438E-03
Iter: 4000 Maxdiff: 7.8075826E-03
Iter: 5000 Maxdiff: 6.8114996E-03
Iter: 6000 Maxdiff: 6.3546896E-03
Iter: 7000 Maxdiff: 6.0142875E-03
Iter: 8000 Maxdiff: 5.7539642E-03
Iter: 9000 Maxdiff: 5.5487156E-03
Iter: 10000 Maxdiff: 5.3788126E-03
Converged after 10001 iterations with maxdiff = 5.3788126E-03
Time taken (seconds): 2.260000 seconds
Compiler reports
Concurrent do loop
Intel(R) Advisor can now assist with vectorization and show optimization
report messages with your source code.
See "https://software.intel.com/en-us/intel-advisor-xe" for details.
Begin optimization report for: POISSON_SOLVER
Report from: OpenMP optimizations [openmp]
OpenMP Construct at D:\testing_gfortran15Version\comparison\main_dc.f90(37,5)
remark #16200: OpenMP DEFINED LOOP WAS PARALLELIZED
OpenMP Construct at D:\testing_gfortran15Version\comparison\main_dc.f90(37,5)
remark #16200: OpenMP DEFINED LOOP WAS PARALLELIZED
OpenMP Construct at D:\testing_gfortran15Version\comparison\main_dc.f90(41,5)
remark #16200: OpenMP DEFINED LOOP WAS PARALLELIZED
OpenMP Construct at D:\testing_gfortran15Version\comparison\main_dc.f90(41,5)
remark #16200: OpenMP DEFINED LOOP WAS PARALLELIZED
===========================================================================
OpenMP do loop
Intel(R) Advisor can now assist with vectorization and show optimization
report messages with your source code.
See "https://software.intel.com/en-us/intel-advisor-xe" for details.
Begin optimization report for: POISSON_SOLVER
Report from: OpenMP optimizations [openmp]
OpenMP Construct at D:\testing_gfortran15Version\comparison\main_omp.f90(37,11)
remark #16200: OpenMP DEFINED LOOP WAS PARALLELIZED
OpenMP Construct at D:\testing_gfortran15Version\comparison\main_omp.f90(45,11)
remark #16200: OpenMP DEFINED LOOP WAS PARALLELIZED
===========================================================================```