MPI — разница между mpi_type_get_extent и mpi_type_get_true_extent

У меня есть некоторые проблемы с пониманием разницы между 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, я должен изменить его размер, изменив его extenttrue_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

person Enlico    schedule 30.04.2018    source источник
comment
(ответ на исчезнувший комментарий) У меня нет ошибок, я просто не понимаю, что не так с моим пониманием этих двух инструментов MPI применительно к определяемому пользователем типу, например, созданному с помощью MPI_TYPE_CREATE_SUBARRAY (с предустановленным типом данных , например MPI_DOUBLE_PRECISION, разницы нет).   -  person Enlico    schedule 30.04.2018
comment
Вы можете не отвечать на удаленные комментарии, есть причина, по которой я все-таки удалил его... Под ошибкой я имел в виду разные результаты, но тем не менее, я удалил комментарий. Ваш код не компилируется напрямую, но необходимые объявления хорошо предсказуемы.   -  person Vladimir F    schedule 30.04.2018
comment
Что касается вашего редактирования (повторяю, что мой первый комментарий удален, так что забудьте об этом), даже программы, которые дают какой-то результат, который нужно объяснить, обычно нуждаются в MWE, не только программы с ошибками, но и все другие программы. В любом случае, ваш код, вероятно, в порядке, а объявления предсказуемы, поэтому я удалил комментарий.   -  person Vladimir F    schedule 30.04.2018
comment
Короче говоря, MPI_Type_create_subarray() может изменить экстент под капотом. В Фортране тип данных, описывающий столбец двумерной квадратной матрицы, заканчивается size==extent, но тип данных, описывающий строку, имеет тот же размер, но extent — это размер одного элемента.   -  person Gilles Gouaillardet    schedule 30.04.2018
comment
@GillesGouaillardet, что вы подразумеваете под размером одного элемента? Насколько я читал и видел, extent типа, представляющего строку матрицы Фортрана m на n, равно 1+m*(n-1), и я ожидал, что mpi_type_get_extent вернется.   -  person Enlico    schedule 30.04.2018
comment
Вы смешиваете extent и true_extent. Не стесняйтесь MPI_Send(matrix, 2, row_datatype, ...), и когда вы получите правильные результаты, дважды проверьте extent и true_extent.   -  person Gilles Gouaillardet    schedule 01.05.2018
comment
@GillesGouaillardet, действительно, название вопроса - это как раз разница между [...].   -  person Enlico    schedule 01.05.2018
comment
как насчет написания минимально воспроизводимого примера, как я предлагал ранее? Возможно, вы захотите записать его в C и создать тип данных для одного столбца.   -  person Gilles Gouaillardet    schedule 01.05.2018
comment
(Я не программист на C, написать это очень сложно.) Ссылка, которую вы предложили, говорит сразу после заголовка: Когда вы задаете вопрос о проблеме, вызванной вашим кодом; ну, у моего кода нет проблем, у моего понимания extent есть проблема, которую я пытаюсь решить здесь. В любом случае я добавил компилируемый код, который можно запустить.   -  person Enlico    schedule 01.05.2018
comment
Да, закомментированные строки делают это. Я не хочу повторяться, но код работает. Правильно. Это работает, потому что я соответствующим образом изменяю размер типов данных, которые я создаю, чтобы представлять несмежные области памяти. Я просто пытаюсь понять, что означает extent, которое mpi_type_create_subarray придает типу, который он создает.   -  person Enlico    schedule 01.05.2018


Ответы (1)


MPI_Type_create_subarray() создает производный тип данных, экстент которого по определению является произведением всех размеров.

Определение находится в стандарте MPI 3.1 на странице 96.

MPI_Type_create_subarray() обычно используется для MPI-IO, поэтому такое определение экстента имеет смысл.

Это может быть не то, что вы хотите в этом очень конкретном случае, но подумайте о подмассиве 2x2 массива 4x4. Какой степени вы ожидаете?

person Gilles Gouaillardet    schedule 01.05.2018
comment
Итак, это (ub_marker, size0*ex), последний элемент карты типов eq. (4.2), нести ответственность, я правильно понял? - person Enlico; 01.05.2018
comment
Да, это мое понимание - person Gilles Gouaillardet; 01.05.2018
comment
О, наконец! Я надеюсь, что этот вопрос дал вам возможность укрепить свои знания, так как он помог мне улучшить свои. Кстати, поскольку рассматриваемый тип данных является подмассивом S массива A, я ожидал, что его extent будет равно либо его true_extent (которое является свойством S как части A, в котором он живет), либо, по крайней мере, его subsize (который будет свойством только S), но не size, который является свойством только A. - person Enlico; 01.05.2018