Сравнение Fortran/OpenMP на 2 платформах (компиляторы GCC и PGI). Неожиданные сроки исполнения
Я скомпилировал (с помощью компиляторов GCC и PGI) и запустил небольшую программу на Fortran/OpenMP на двух разных платформах (на основе Haswell и Skylake), просто чтобы почувствовать разницу в производительности. Я не знаю, как интерпретировать результаты - они для меня загадка.
Вот небольшая программа (взята с сайта разработчика Nvidia и немного адаптирована).
PROGRAM main
use, intrinsic :: iso_fortran_env, only: sp=>real32, dp=>real64
use, intrinsic :: omp_lib
implicit none
real(dp), parameter :: tol = 1.0d-6
integer, parameter :: iter_max = 1000
real(dp), allocatable :: A(:,:), Anew(:,:)
real(dp) :: error
real(sp) :: cpu_t0, cpu_t1
integer :: it0, it1, sys_clock_rate, iter, i, j
integer :: N, M
character(len=8) :: arg
call get_command_argument(1, arg)
read(arg, *) N !!! N = 8192 provided from command line
call get_command_argument(2, arg)
read(arg, *) M !!! M = 8192 provided from command line
allocate( A(N,M), Anew(N,M) )
A(1,:) = 1
A(2:N,:) = 0
Anew(1,:) = 1
Anew(2:N,:) = 0
iter = 0
error = 1
call cpu_time(cpu_t0)
call system_clock(it0)
do while ( (error > tol) .and. (iter < iter_max) )
error = 0
!$omp parallel do reduction(max: error) private(i)
do j = 2, M-1
do i = 2, N-1
Anew(i,j) = (A(i+1,j)+A(i-1,j)+A(i,j-1)+A(i,j+1)) / 4
error = max(error, abs(Anew(i,j)-A(i,j)))
end do
end do
!$omp end parallel do
!$omp parallel do private(i)
do j = 2, M-1
do i = 2, N-1
A(i,j) = Anew(i,j)
end do
end do
!$omp end parallel do
iter = iter + 1
end do
call cpu_time(cpu_t1)
call system_clock(it1, sys_clock_rate)
write(*,'(a,f8.3,a)') "...cpu time :", cpu_t1-cpu_t0, " s"
write(*,'(a,f8.3,a)') "...wall time:", real(it1 it0)/real(sys_clock_rate), " s"
END PROGRAM
Две платформы, которые я использовал:
- Intel i7-4770 @ 3,40 ГГц (Haswell), 32 ГБ ОЗУ / Ubuntu 16.04.2 LTS
- Intel i7-6700 @ 3,40 ГГц (Skylake), 32 ГБ ОЗУ / Linux Mint 18.1 (~ Ubuntu 16.04)
На каждой платформе я скомпилировал программу Fortran с
- GCC Gfortran 6.2.0
- PGI pgfortran 16.10 Community Edition
Я, очевидно, скомпилировал программу независимо на каждой платформе (я только переместил файл.f90; я не переместил никакой двоичный файл)
Я запускал 5 раз каждый из 4 исполняемых файлов (по 2 на каждую платформу), собирая время стен, измеренное в секундах (как распечатано программой). (Ну, я провёл весь тест несколько раз, и время, показанное ниже, определенно показательно)
Последовательное исполнение. Программа составлена из:
- gfortran - быстрый main.f90 -o gcc-seq
- pgfortran -fast main.f90 -o pgi-seq
Время (лучшее из 5):
- Haswell> gcc-seq: 150.955, pgi-seq: 165.973
- Skylake> gcc-seq: 277.400, pgi-seq: 121.794
Многопоточное исполнение (8 потоков). Программа составлена из:
- gfortran -Ofast -fopenmp main.f90 -o gcc-omp
- pgfortran -fast -mp = allcores main.f90 -o pgi-omp
Время (лучшее из 5):
- Haswell> gcc-omp: 153.819, pgi-omp: 151.459
- Skylake> gcc-omp: 113.497, pgi-omp: 107.863
При компиляции с OpenMP я проверял число потоков в параллельных регионах с помощью omp_get_num_threads(), и на самом деле всегда есть 8 потоков, как и ожидалось.
Есть несколько вещей, которые я не понимаю:
- Использование компилятора GCC: почему в Skylake OpenMP имеет существенное преимущество (277 против 113 с), а в Haswell - вообще нет? (150 против 153 с) Что происходит на Haswell?
- Использование компилятора PGI: почему OpenMP имеет такое небольшое преимущество (если таковое имеется) на обеих платформах?
- Сосредоточив внимание на последовательных прогонах, почему существуют такие огромные различия во времени выполнения между Haswell и Skylake (особенно, когда программа компилируется с GCC)? Почему эта разница все еще так актуальна - но с ролью Хэсвелла и Скайлэйк поменялись местами! - когда включен OpenMP?
- Кроме того, когда OpenMP включен и используется GCC, время процессора всегда намного больше времени стены (как я и ожидал), но когда используется PGI, время процессора и стены всегда одинаково, также тогда программа использовала несколько потоки.
Как я могу иметь какой-то смысл из этих результатов?