我是MPI编程新手。我必须测试3个代码,例如顺序,OpenMP和MPI代码。这些3码(不是真正的代码,只是举例)分别给定为遵循Single vs OpenMP vs MPI - Fortran
顺序码
program no_parallel
implicit none
integer, parameter :: dp = selected_real_kind(15,307)
integer :: i, j
real(kind = dp) :: time1, time2
real(kind = dp), dimension(1000000) :: a
!Initialisation
do i = 1, 1000000
a(i) = sqrt(dble(i)/3.0d+0)
end do
call cpu_time(time1)
do j = 1, 1000
do i = 1, 1000000
a(i) = a(i) + sqrt(dble(i))
end do
end do
call cpu_time(time2)
print *, a(1000000)
print *, 'Elapsed real time = ', time2 - time1, 'second(s)'
end program no_parallel
的OpenMP的代码
program openmp
implicit none
integer, parameter :: dp = selected_real_kind(15,307)
integer :: i, j
real(kind = dp) :: time1, time2, omp_get_wtime
real(kind = dp), dimension(1000000) :: a
!Initialisation
do i = 1, 1000000
a(i) = sqrt(dble(i)/3.0d+0)
end do
time1 = omp_get_wtime()
!$omp parallel
do j = 1, 1000
!$omp do schedule(runtime)
do i = 1, 1000000
a(i) = a(i) + sqrt(dble(i))
end do
!$omp end do
end do
!$omp end parallel
time2 = omp_get_wtime()
print *, a(1000000)
print *, 'Elapsed real time = ', time2 - time1, 'second(s)'
end program openmp
的MPI代码
program MPI
implicit none
include "mpif.h"
integer, parameter :: dp = selected_real_kind(15,307)
integer :: ierr, num_procs, my_id, destination, tag, source, stat, i, j
real(kind = dp) :: time1, time2
real(kind = dp), dimension(1000000) :: a
call MPI_INIT (ierr)
call MPI_COMM_RANK (MPI_COMM_WORLD, my_id, ierr)
call MPI_COMM_SIZE (MPI_COMM_WORLD, num_procs, ierr)
!Initialisation
do i = 1, 1000000
a(i) = sqrt(dble(i)/3.0d+0)
end do
destination = 0
tag = 999
source = 3
stat = MPI_STATUS_SIZE
time1 = MPI_Wtime()
do j = 1, 1000
do i = 1 + my_id, 1000000, num_procs
a(i) = a(i) + sqrt(dble(i))
end do
end do
call MPI_BARRIER (MPI_COMM_WORLD, ierr)
if(my_id == source) then
call MPI_SEND (a(1000000), 1, MPI_DOUBLE_PRECISION, destination, tag, MPI_COMM_WORLD, ierr)
end if
if(my_id == destination) then
call MPI_RECV (a(1000000), 1, MPI_DOUBLE_PRECISION, source, tag, MPI_COMM_WORLD, stat, ierr)
end if
time2 = MPI_Wtime()
if(my_id == 0) then
print *, a(1000000) !, 'from ID =', my_id
print *, 'Elapsed real time = ', time2 - time1, 'second(s)'
end if
stop
call MPI_FINALIZE (ierr)
end program MPI
我使用Intel Fortran Compiler 17.0.3
和-O0
优化标志编译了这些代码。 OpenMP和MPI代码都是在4个核心Haswell Desktop上执行的。我分别获得了顺序OpenMP和MPI代码8.08s
,2.1s
和3.2s
的CPU时间。实际上,我期待OpenMP和MPI代码之间的结果几乎相似;然而,事实并非如此。我的问题:
关于MPI代码,如果我想打印出来的
a(1000000)
的结果,是有可能做到这一点在一个更聪明的方式,而不做这样call MPI_SEND
和call MPI_RECV
?您是否清楚MPI代码中哪些部分仍然可以优化?
对于MPI代码中的
source
,是否可以自动定义它?在这种情况下,很容易对我来说,因为处理器的数量是4,所以a(1000000)
必须被分配到线程3
预先感谢您。
未优化('-O0')代码的性能比较是无用的,没有实际的相关性。这不值得讨论。您还想使用挂钟,而不是CPU时间(https://stackoverflow.com/a/6880133/620382)。 – Zulan
@Zulan:谢谢,但你根本没有帮助:)当然,我发布了这个理由。我用-O3编译了MPI代码,但CPU时间保持不变(仍为3.2s)。由于我也是MPI编程中的新手,我想知道基本没有使用优化标志。关于答案中的CPU时间,此CPU时间仅适用于顺序代码。所以,我实际上不需要这个CPU时间。我想现在如果仍然可以优化与OpenMP相比的MPI代码。无论如何感谢您的回答。 –
您的顺序代码正在使用CPU时间(我们假设,从您调用的函数:-)),但您的并行代码正在使用已过时的挂钟时间。 (这就是为什么这些函数在名称中有'W'的原因......)。所以你不能明智地比较它们。 –