У меня есть некоторые проблемы с пониманием разницы между mpi_type_get_extent
и mpi_type_get_true_extent
. На практике я использовал первое, ожидая результатов, которые я затем получил со вторым, поэтому я проверил Стандарт MPI 3.1, где я нашел (в разделе 4.1.8 True Extent of Datatypes)
Однако экстент типа данных нельзя использовать в качестве оценки объема пространства, которое необходимо выделить, если пользователь изменил экстент.
что заставило меня подумать, что я не должен был испытывать никакой разницы в использовании двух подпрограмм, пока я не изменил размер типа данных.
Но я явно что-то упускаю.
Объявлен следующий производный от MPI тип данных,
sizes = [10,10,10]
subsizes = [ 3, 3, 3]
starts = [ 2, 2, 2]
CALL MPI_TYPE_CREATE_SUBARRAY(ndims, sizes, subsizes, starts, MPI_ORDER_FORTRAN, MPI_DOUBLE_PRECISION, newtype, ierr)
следующий код
call mpi_type_size(newtype, k, ierr)
call mpi_type_get_extent(newtype, lb, extent, ierr)
call mpi_type_get_true_extent(newtype, tlb, textent, ierr)
write(*,*) k/DBS, lb/DBS, extent/DBS, tlb/DBS, textent/DBS ! DBS is the size of double precision
производит вывод (очевидно, одинаковый для всех процессов)
27 0 1000 222 223
Итак, mpi_type_size
ведет себя так, как я ожидаю, возвращая PRODUCT(subsizes)*DBS
в k
; с другой стороны, я ожидал от обоих mpi_type_get_extent
и mpi_type_get_true_extent
того, что возвращает только последний (поскольку я вообще не изменил newtype
), особенно 222 223
, которые в основном являются starts(1) + starts(2)*sizes(1) + starts(3)*sizes(1)*sizes(2)
и 1 + (subsizes - 1)*[1, sizes(1), sizes(1)*sizes(2)]
.
Почему mpi_type_get_extent
возвращает 0
и PRODUCT(sizes)
в lb
и extent
независимо от subsizes
и starts
?
Я не публиковал MWE, так как у меня вообще нет ошибок (ни во время компиляции, ни во время выполнения), я просто не понял, как работают две вышеупомянутые процедуры. В принципе, я хотел бы, чтобы кто-нибудь помог мне понять описание этих подпрограмм в стандартном документе и почему правильно получить тот результат, которого я не ожидал.
РЕДАКТИРОВАНИЕ По просьбе @GillesGouaillardet я добавляю «минимальный» рабочий пример для запуска с минимум 4 процессами (пожалуйста, запустите его ровно с 4 процессами, чтобы у нас было тот же вывод), в конце этого вопроса. Последние строки можно раскомментировать (с пониманием), чтобы показать, что типы, представляющие несмежные области памяти, работают правильно при использовании с count > 1
, после того, как они были должным образом изменены с помощью mpi_type_create_resized
. С этими закомментированными строками программа печатает size
, lb
, extent
, true_lb
, true_extent
для всех созданных типов (даже промежуточных, не зафиксированных):
mpi_type_contiguous 4 0 4 0 4
mpi_type_vector 4 0 13 0 13
mpi_type_vector res 4 0 1 0 13
mpi_type_create_subarray 4 0 16 0 13
mpi_type_create_subarray res 4 0 1 0 13
Все типы представляют одну строку или столбец матрицы 4 на 4, поэтому их size
предсказуемо всегда равно 4
; тип столбца имеет extent
и true_extent
оба равные 4
единицам, поскольку он представляет четыре последовательных действительных числа в памяти; тип, созданный с помощью mpi_type_vector
, имеет extent
и true_extent
, равные 13
реалов, как я и ожидал (см. хороший эскиз); если я хочу использовать его с count > 1
, я должен изменить его размер, изменив его extent
(а true_extent
останется прежним); теперь самое сложное:
Что это за 16
как extent
типа, созданного с помощью mpi_type_create_subarray
? Честно говоря, я ожидал, что эта подпрограмма вернет уже измененный тип, готовый к использованию с count > 1
(т.е. тип с size = 4
, extent = 1
, true_extent = 13
), но, похоже, это не так: удивительно для меня extent
равно 16
, что соответствует размеру глобального массива!
Вопрос: почему? Почему extent
типа, созданного с помощью mpi_type_create_subarray
, является произведением элементов аргумента array_of_sizes
?
program subarray
use mpi
implicit none
integer :: i, j, k, ierr, myid, npro, rs, mycol, myrowugly, myrow_vec, myrow_sub
integer(kind = mpi_address_kind) :: lb, extent, tlb, textent
real, dimension(:,:), allocatable :: mat
call mpi_init(ierr)
call mpi_comm_rank(mpi_comm_world, myid, ierr)
call mpi_comm_size(mpi_comm_world, npro, ierr)
allocate(mat(npro,npro))
mat = myid*1.0
call mpi_type_size(mpi_real, rs, ierr)
call mpi_type_contiguous(npro, mpi_real, mycol, ierr)
call mpi_type_commit(mycol, ierr)
call mpi_type_size(mycol, k, ierr)
call mpi_type_get_extent(mycol, lb, extent, ierr)
call mpi_type_get_true_extent(mycol, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_contiguous ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_vector(npro, 1, npro, mpi_real, myrowugly, ierr)
call mpi_type_size(myrowugly, k, ierr)
call mpi_type_get_extent(myrowugly, lb, extent, ierr)
call mpi_type_get_true_extent(myrowugly, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_vector ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_create_resized(myrowugly, int(0, mpi_address_kind)*rs, int(1, mpi_address_kind)*rs, myrow_vec, ierr)
call mpi_type_commit(myrow_vec, ierr)
call mpi_type_size(myrow_vec, k, ierr)
call mpi_type_get_extent(myrow_vec, lb, extent, ierr)
call mpi_type_get_true_extent(myrow_vec, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_vector res ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_create_subarray(2, [npro, npro], [1, npro], [0, 0], mpi_order_fortran, mpi_real, myrowugly, ierr)
call mpi_type_size(myrowugly, k, ierr)
call mpi_type_get_extent(myrowugly, lb, extent, ierr)
call mpi_type_get_true_extent(myrowugly, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_create_subarray ', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
call mpi_type_create_resized(myrowugly, int(0, mpi_address_kind)*rs, int(1, mpi_address_kind)*rs, myrow_sub, ierr)
call mpi_type_commit(myrow_sub, ierr)
call mpi_type_size(myrow_sub, k, ierr)
call mpi_type_get_extent(myrow_sub, lb, extent, ierr)
call mpi_type_get_true_extent(myrow_sub, tlb, textent, ierr)
if (myid == 0) print *, 'mpi_type_create_subarray res', k/rs, lb/rs, extent/rs, tlb/rs, textent/rs
!if (myid == 0) call mpi_send(mat(1,1), 2, mycol, 1, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_recv(mat(1,3), 2, mycol, 1, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_recv(mat(1,1), 2, mycol, 0, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_send(mat(1,3), 2, mycol, 0, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_send(mat(1,1), 2, myrow_vec, 1, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_recv(mat(3,1), 2, myrow_vec, 1, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_recv(mat(1,1), 2, myrow_vec, 0, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_send(mat(3,1), 2, myrow_vec, 0, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_send(mat(1,1), 2, myrow_sub, 1, 666, mpi_comm_world, ierr)
!if (myid == 0) call mpi_recv(mat(3,1), 2, myrow_sub, 1, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_recv(mat(1,1), 2, myrow_sub, 0, 666, mpi_comm_world, mpi_status_ignore, ierr)
!if (myid == 1) call mpi_send(mat(3,1), 2, myrow_sub, 0, 666, mpi_comm_world, ierr)
!do i = 0, npro
!if (myid == i) then
!print *, ""
!print *, myid
!do j = 1, npro
!print *, mat(j,:)
!end do
!end if
!call mpi_barrier(mpi_comm_world, ierr)
!end do
call mpi_finalize(ierr)
end program subarray
MPI_TYPE_CREATE_SUBARRAY
(с предустановленным типом данных , напримерMPI_DOUBLE_PRECISION
, разницы нет). - person Enlico   schedule 30.04.2018MPI_Type_create_subarray()
может изменить экстент под капотом. В Фортране тип данных, описывающий столбец двумерной квадратной матрицы, заканчиваетсяsize==extent
, но тип данных, описывающий строку, имеет тот же размер, ноextent
— это размер одного элемента. - person Gilles Gouaillardet   schedule 30.04.2018extent
типа, представляющего строку матрицы Фортранаm
наn
, равно1+m*(n-1)
, и я ожидал, чтоmpi_type_get_extent
вернется. - person Enlico   schedule 30.04.2018extent
иtrue_extent
. Не стесняйтесьMPI_Send(matrix, 2, row_datatype, ...)
, и когда вы получите правильные результаты, дважды проверьтеextent
иtrue_extent
. - person Gilles Gouaillardet   schedule 01.05.2018C
и создать тип данных для одного столбца. - person Gilles Gouaillardet   schedule 01.05.2018extent
есть проблема, которую я пытаюсь решить здесь. В любом случае я добавил компилируемый код, который можно запустить. - person Enlico   schedule 01.05.2018extent
, котороеmpi_type_create_subarray
придает типу, который он создает. - person Enlico   schedule 01.05.2018