Я пытался (без особого успеха) уменьшить MPI, используя специальную операцию в Fortran 2008. Мне удалось сделать это на C, но о Fortran 2008 информации немного меньше.
Этот код работает с включенной функцией сокращения MPI_SUM. Он просто суммирует каждое существующее значение ранга в глобальную сумму. Моей непосредственной целью было бы определить пользовательскую функцию, чтобы сделать то же самое. Любая помощь?
program main
use mpi_f08
implicit none
integer :: ierror, isize, irank
integer :: local_value, global_value
call MPI_INIT(ierror)
call MPI_COMM_SIZE(MPI_COMM_WORLD, isize)
call MPI_COMM_RANK(MPI_COMM_WORLD, irank)
if (irank == 0) then
local_value = irank
global_value = 0
call MPI_Reduce(local_value, global_value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD, ierror)
print *, "global_value", global_value
else ! MPI if rank > 0
local_value = irank
call MPI_Reduce(local_value, global_value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD, ierror)
end if ! MPI if rank
call MPI_FINALIZE(ierror)
end program main
Мне удалось написать функциональную реализацию на Фортране, но по какой-то причине результат с использованием 4 процессов MPI был 3 вместо 6. Непонятно, почему. Тем не менее, чтобы двигаться дальше, мне нужна (правильно) работающая реализация Fortran 2008.
РЕДАКТИРОВАТЬ - вот код Фортрана, который компилируется, но не работает должным образом.
program main
use mpi
implicit none
integer :: local_value, global_sum
integer :: ierr, rank, size
integer :: my_op
call MPI_Init(ierr)
call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
call MPI_Op_create(custom_sum_op, .true., my_op, ierr)
if (rank == 0) then
local_value = rank
global_sum = 0
call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
print *, "Global sum: ", global_sum
else ! irank > 0
local_value = rank
call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
endif ! MPI if rank 0
call MPI_Finalize(ierr)
contains
subroutine custom_sum_op(res, a)
integer, intent(inout) :: res
integer, intent(in) :: a
res = a + res
end subroutine custom_sum_op
end program main
Не используйте MPI_INT
для Фортрана, это тип данных C. Кроме того, аргументы ierror
не являются обязательными, их можно избежать, если вы все равно их не проверяете.
Вполне может помочь, если вы отредактируете вопрос, чтобы показать свою ошибочную реализацию Fortran. Проблема может быть не в том, о чем вы думаете.
Подпрограмма является внутренней. Указатель на него будет действителен только тогда, когда содержащий его код все еще выполняется. Для основной программы это должно быть нормально, но в MPI стеки иногда делают странные вещи. Это не вызывает проблемы здесь, но может вызвать проблемы в будущем.
Спасибо всем, я обновил вопрос (неработающей) версией Фортрана.
Вот работающий пример с интерфейсом пользовательской функции, взятым из стандарта MPI. То, что у вас есть, определенно не соответствует тому, что говорит стандарт; у вас только 2 аргумента вместо 4, они не того типа для интерфейса mpi_f08
, и вы возвращаете результат в первом аргументе, а не во втором.
ijb@ijb-Latitude-5410:~/work/stack$ cat op_create.f90
Module my_sum_module
Implicit None
Public :: my_sum
Private
Contains
Subroutine my_sum( invec, inoutvec, len, datatype )
Use, Intrinsic :: iso_fortran_env, Only : stdout => output_unit
Use, Intrinsic :: iso_C_binding , Only : c_ptr
Use mpi_f08
Implicit None
Type( c_ptr ) , Value :: invec
Type( c_ptr ) , Value :: inoutvec
Integer :: len
Type( mpi_datatype ) :: datatype
Integer, Dimension( : ), Pointer :: in_fptr
Integer, Dimension( : ), Pointer :: inout_fptr
If( datatype == mpi_integer ) Then
Call c_f_pointer( invec , in_fptr , [ len ] )
Call c_f_pointer( inoutvec, inout_fptr, [ len ] )
inout_fptr = inout_fptr + in_fptr
Else
Write( stdout, * ) 'Unkown data type in my_sum'
Call mpi_abort( mpi_comm_world, 5 )
End If
End Subroutine my_sum
End Module my_sum_module
Program test
Use, Intrinsic :: iso_fortran_env, Only : stdout => output_unit
Use mpi_f08, Only : mpi_comm_world
Use mpi_f08, Only : mpi_integer
Use mpi_f08, Only : mpi_sum
Use mpi_f08, Only : mpi_op
Use mpi_f08, Only : mpi_init, mpi_finalize
Use mpi_f08, Only : mpi_comm_rank, mpi_comm_size
Use mpi_f08, Only : mpi_reduce
Use mpi_f08, Only : mpi_op_create
Use my_sum_module, Only : my_sum
Implicit None
Type( mpi_op ) :: op
Integer :: root
Integer :: answer
Integer :: me, nproc
Call mpi_init()
Call mpi_comm_rank( mpi_comm_world, me )
Call mpi_comm_size( mpi_comm_world, nproc )
If( me == 0 ) Then
Write( stdout, * ) 'Running on', nproc, ' processes'
End If
root = 0
Call mpi_reduce( me, answer, 1, mpi_integer, mpi_sum, root, mpi_comm_world )
If( me == root ) Then
Write( stdout, * ) 'Answer to sum = ', answer
End If
Call mpi_op_create( my_sum, .True., op )
Call mpi_reduce( me, answer, 1, mpi_integer, op, root, mpi_comm_world )
If( me == root ) Then
Write( stdout, * ) 'Answer to my_sum = ', answer
End If
Call mpi_finalize()
End Program test
ijb@ijb-Latitude-5410:~/work/stack$ mpif90 --version
GNU Fortran (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ijb@ijb-Latitude-5410:~/work/stack$ mpif90 -Wall -Wextra -fcheck=all -O -g -std=f2018 op_create.f90
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 1 ./a.out
Running on 1 processes
Answer to sum = 0
Answer to my_sum = 0
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 2 ./a.out
Running on 2 processes
Answer to sum = 1
Answer to my_sum = 1
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
Running on 3 processes
Answer to sum = 3
Answer to my_sum = 3
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 4 ./a.out
Running on 4 processes
Answer to sum = 6
Answer to my_sum = 6
ijb@ijb-Latitude-5410:~/work/stack$ mpirun -np 5 --oversubscribe ./a.out
Running on 5 processes
Answer to sum = 10
Answer to my_sum = 10
ijb@ijb-Latitude-5410:~/work/stack$
Спасибо! Я вижу, что структура кода объявления пользовательской функции вместе с использованием указателей делает эту, казалось бы, простую задачу немного более сложной, чем я изначально ожидал. Ваше здоровье :)
Добро пожаловать. Пожалуйста, используйте тег fortran для всех вопросов по Fortran. Вы можете добавить тег версии для вопросов, касающихся конкретной версии, но это не один из них. Современный MPI API также используется в более поздних версиях стандарта Фортрана.