MPI - разница между mpi_type_get_extent и mpi_type_get_true_extent - PullRequest
0 голосов
/ 30 апреля 2018

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

enter image description here

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

1 Ответ

0 голосов
/ 01 мая 2018

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

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

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

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

...