У меня есть некоторая проблема в понимании разницы между mpi_type_get_extent
и mpi_type_get_true_extent
. На практике я использовал первое, ожидая результатов, которые я затем получил с последним, поэтому я проверил MPI 3.1 Standard , где я нашел (в разделе 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, так как у меня вообще нет ошибок (ни во время компиляции, ни во время выполнения), я просто не понимаю, как работают две вышеупомянутые подпрограммы. Я бы хотел, чтобы кто-то помог мне понять описание этих подпрограмм в стандартном документе и понять, почему правильно получить результат, которого я не ожидал.
EDIT
В соответствии с запросом @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