2015-11-04 1 views
1

Имейте некоторый опыт работы с MPI, но не с некоторыми более продвинутыми аспектами, такими как производные типы, с чем связан мой вопрос.Как использовать MPI для отправки правильного количества объектов производного типа?

Код, над которым я работаю, имеет несколько массивов размером (-1:nx+2,-1:ny+2,-1:nz+2). Чтобы было ясно, каждый процесс имеет свои значения nx, ny и nz. Между массивами существует перекрытие. Например, x(:,:,-1:2) по одному проку будет представлять ту же самую информацию, что и x(:,:,nz-1:nz+2), на proc, только «ниже».

Производная cell_zface тип был определен:

idir = 3 
sizes = (/nx_glb, ny_glb, nz_glb/) !These nums are the same for all procs. 
subsizes = (/nx, ny, 2/) 
mpitype = MPI_DATATYPE_NULL 
CALL MPI_TYPE_CREATE_SUBARRAY(3, sizes, subsizes, starts, & 
    MPI_ORDER_FORTRAN, mpireal, mpitype, errcode) 
CALL MPI_TYPE_COMMIT(mpitype, errcode) 
cell_zface = mpitype 

Теперь этот производный тип привыкает, успешно, в нескольких MPI_SENDRECV вызовов. Например

CALL MPI_SENDRECV(& 
     x(-1,-1, 1), 1, cell_zface, proc_z_min, tag, & 
     x(-1,-1,nz+1), 1, cell_zface, proc_z_max, tag, & 
     comm, status, errcode) 

Как я понимаю, этот вызов для отправки и получение два «горизонтальных» срезов (т.е. X-Y ломтиков) массива между проками.

Я хочу сделать что-то совсем другое, а именно отправить четыре «горизонтальных» ломтика. Поэтому я пробую

call mpi_send(x(-1,-1,nz-1), 2, cell_zface, & 
        proc_z_max, rank, comm, mpierr) 

с сопроводительным приемом.

И, наконец, моя проблема: код работает, но ошибочно. AFAICT, это отправляет только два горизонтальных среза, хотя вместо аргумента count вместо «1» я использую «2». Я могу это исправить, сделав два вызова mpi_send:

call mpi_send(x(-1,-1,nz-1), 1, cell_zface, & 
        proc_z_max, rank, comm, mpierr) 
call mpi_send(x(-1,-1,nz+1), 1, cell_zface, & 
        proc_z_max, rank, comm, mpierr) 

с сопровождающими получает, но это, конечно, не очень.

Итак, почему mpi_send отправляет только два горизонтальных среза, хотя я установил аргумент count в «2»? И есть ли чистый способ сделать то, что я хочу здесь сделать?

+0

Вы должны понимать, что даже если у вас есть свой «тип», то, что вы действительно имеете под ним, - это один огромный непрерывный блок памяти. Таким образом, хотя вы можете отправить два типа «cell_zface», сам тип имеет только такую ​​большую память, как расстояние между первым и последним (в 1D) ячейками памяти, используемыми вашим типом. Aka, размер вашего типа не является действительно «nx * ny * nz'. – NoseKnowsAll

+0

Чтобы выполнить то, что вы хотите сделать, вам придется указать свой производный тип данных в различной степени. Обратите внимание, что размер типа данных будет таким же, но «объем» (или объем последовательных версий памяти этого типа будет охватывать) не будет. Я считаю, что вы можете выполнить это с помощью [MPI_Type_create_resized] (http://www.mpich.org/static/docs/v3.1/www3/MPI_Type_create_resized.html). – NoseKnowsAll

ответ

1

Каждый тип данных MPI имеет два размера, так сказать. Один - это истинный размер, то есть объем памяти, который требуется для хранения всех значимых данных, относящихся к типу данных. Можно думать об этом как о количестве пространства в фактическом сообщении, которое берет элемент этого типа данных.

Другой размер - это так называемая протяженность. Каждый тип данных в MPI представляет собой набор инструкций типа: «перейти на смещение DISP я из предоставленного местоположения буфера и чтение/запись элемент базового типа типа я». Набор всех (тип i, disp i) пары называются картами типа типа данных. Минимальное смещение называется нижней границей , а максимальное смещение + размер базового типа при этом смещении + любое необходимое дополнение называется верхней границей. Степень типа данных - это разница между верхней границей и нижней границей и дает размер кратчайшего смежного региона памяти, который включает в себя все местоположения, к которым обращается тип данных.

Поскольку MPI указывает, что никакая ячейка памяти не считывается или не записывается более одного раза во время любой операции связи, пары в печатной карте должны ссылаться на непересекающиеся местоположения. Следовательно, истинная степень типа данных всегда больше или равна его размеру.

MPI использует размер типа данных при доступе к последовательным элементам этого типа данных. Следующее утверждение:

MPI_SEND(buf, n, dtype, ...) 

приводит:

  • MPI принимает один элемент типа dtype от места buf следуя правилам, закодированных в качестве typemape из dtype;
  • MPI принимает следующий элемент, начиная с местоположения buf + extent(dtype);
  • ...
  • MPI принимает n -й элемент, начиная с местоположения buf + (n-1)*extent(dtype).

Примитивные типы данных, такие как MPI_INTEGER, MPI_REAL и т.д. имеют свою степень соответствия размеров основного типа (INTEGER, REAL и т.д.) + любые отступы под мандат архитектуры, что делает возможным посылать массивы базовый тип, просто указав количество элементов.

Теперь вернемся к вашему делу. Вы создаете тип данных, который охватывает подмассику nx x ny x 2 из массива nx_glb x ny_glb x nz_glb. Размер этого типа данных действительно nx * ny * 2 раз больше mpireal, но степень фактически nx_glb * ny_glb * nz_glb раз превышает mpireal. Другими словами:

MPI_SEND(buf, 2, cell_zface, ...) 

не извлечет два последовательных nx x ny x 2 плиты из большого массива в buf. Скорее, он будет извлекать одну плиты от каждого из двух последовательных массивов размера nx_glb x ny_glb x nz_glb, начиная с места (начало х, начать у, начать г) в каждом массиве. Если ваша программа не работает при запуске, считайте себя удачливым.

Теперь наступает сложная часть. MPI позволяет дать каждому типу данных поддельную степень (поэтому я назвал степень, определенную ранее «истиной»), искусственно установив значение нижней и верхней границ. Это не влияет на размер типа данных или его типовой карты (т. Е. MPI по-прежнему переходит в одни и те же смещения и управляет элементами одних и тех же базовых типов), но влияет на шаги в памяти, которые MPI делает при доступе к последовательным элементам данного типа данных. Ранее установление степени выполнялось путем «сэндвича» типа данных в строгом соответствии между элементами специальных псевдотипов MPI_LB и MPI_UB. С тех пор, как MPI-2, MPI_TYPE_CREATE_RESIZED используется для достижения того же.

integer(kind=MPI_ADDRESS_KIND) :: lb, extent 
integer :: newtype 

! First obtain the extent of the old type used to construct cell_zface 
call MPI_TYPE_GET_EXTENT(mpireal, lb, extent, errcode) 
! Adjust the extent of cell_zface 
extent = (nx_glb * ny_glb * subsizes(3)) * extent 
call MPI_TYPE_CREATE_RESIZED(cell_zface, lb, extent, newtype, errcode) 
call MPI_TYPE_COMMIT(newtype, errcode) 
! Get rid of the previous type 
call MPI_TYPE_FREE(cell_zface, errcode) 
cell_zface = newtype 

Теперь вы можете использовать cell_zface отправить несколько последовательных плит.

В качестве альтернативы и, предположительно, более простой подход состоит в установке размер 3-го измерения массива, равный размеру 3-го размера подмассива при вызове MPI_TYPE_CREATE_SUBARRAY:

idir = 3 
subsizes = (/nx, ny, 2/) 
sizes = (/nx_glb, ny_glb, subsizes(3)/) !These nums are the same for all procs. 
mpitype = MPI_DATATYPE_NULL 
CALL MPI_TYPE_CREATE_SUBARRAY(3, sizes, subsizes, starts, & 
    MPI_ORDER_FORTRAN, mpireal, mpitype, errcode) 
CALL MPI_TYPE_COMMIT(mpitype, errcode) 
cell_zface = mpitype 

В обоих случаях Я предполагаю, что starts(3) равен 0.

+0

Не ожидал, что так много работы зайдет в ответ! Большое спасибо за полный и очень полезный ответ. Ты мужчина! –

+0

Итак, если я правильно понимаю, шаг этого типа данных в значительной степени зависит от размера всего трехмерного массива. Вот вопрос, который я знаю, что вы не можете ответить окончательно, но по достоинству оцените все, что у вас есть. Вероятно, вы поняли, что я не написал этот код. Итак, имеет ли смысл иметь шаг, равный размеру всего массива? Я не могу придумать ни одного приложения, где это было бы полезно. Конечно, шаг, равный одному измерению, или произведение двух измерений. Но весь массив? Благодарю. –

+1

Первичный замысел конструктора типа subarray предназначен для использования в MPI-IO. Различные ряды MPI предоставляют одинаковые размеры массива и определяют в нем разные разделы, которые предоставляют им (параллельный) доступ к данным массива, хранящимся в виде одного двоичного файла. Степень такого типа данных намеренно равна размеру всего массива - он позволяет легко считывать из набора таких массивов, хранящихся последовательно. Конструктор подмассива может также использоваться для типов данных, которые представляют области ореола в разложении домена, но нужно быть осторожным и иметь в виду его происхождение. –

Смежные вопросы