Каждый тип данных MPI имеет два свойства: размер и экстент. Размер — это фактическое количество байтов, которые представляет тип данных, а экстент — это количество байтов, которые тип данных занимает в памяти. Некоторые типы данных не являются смежными, что означает, что их размер может быть меньше, чем их экстент, например. (показано здесь в псевдокоде)
MPI_TYPE_VECTOR(count = 1,
blocklength = 10,
stride = 20,
oldtype = MPI_INTEGER,
newtype = newtype)
создает тип данных, который берет первые 10 (blocklength
) элементов из 20 (stride
). Этот тип данных имеет размер, в 10
раз превышающий размер MPI_INTEGER
, что в большинстве систем составляет 40
байт. Его размер в два раза больше или 80
байт на большинстве систем. Если бы count
было равно 2, то он занял бы 10 элементов, затем пропустил бы следующие 10, затем взял бы еще 10 элементов и еще раз пропустил бы следующие 10. Следовательно, его размер и его протяженность были бы в два раза больше.
Когда вы указываете определенное количество элементов в любой подпрограмме MPI, например. MPI_SEND
, MPI делает что-то вроде этого:
- Он инициализирует внутренний буфер данных адресом аргумента исходного буфера.
- Он обращается к карте типов данных, чтобы решить, сколько байтов и откуда взять, и добавляет их к создаваемому сообщению. Количество добавляемых байтов равно размеру типа данных.
- Он увеличивает внутренний указатель данных на степень типа данных.
- Он уменьшает внутренний счетчик и, если он все еще не равен нулю, повторяет предыдущие два шага.
Одной из отличных особенностей MPI является то, что экстент типа данных не обязательно должен соответствовать его размеру (как показано в векторном примере), и можно даже присвоить любое значение экстента, которое он хочет, для типа данных, используя MPI_TYPE_CREATE_RESIZED
. Это позволяет создавать очень сложные шаблоны доступа к данным. Например, использование MPI_SCATTERV
для разброса матрицы по блокам, которые не охватывают целые строки (C) или столбцы (Fortran), требует использования таких типов с измененным размером.
Вернемся к векторному примеру. Независимо от того, создаете ли вы векторный тип с помощью count = 1
, а затем вызываете MPI_SEND
с помощью count = 2
, или создаете векторный тип с помощью count = 2
, а затем вызываете MPI_SEND
с помощью count = 1
, конечный результат будет одинаковым. Часто создается тип данных, полностью описывающий объект, который требуется отправить. В этом случае один дает count = 1
в вызове MPI_SEND
. Но бывают случаи, когда может быть выгоднее создать тип данных, описывающий только часть объекта, например одну часть, а затем вызвать MPI_SEND
с count
, равным количеству частей, которые нужно отправить. Иногда это вопрос личных предпочтений, иногда — алгоритмических требований.
Что касается вашего последнего вопроса, Фортран хранит матрицы в порядке столбцов, что означает, что data(i,j)
находится рядом с data(i±1,j)
в памяти, а не с data(i,j±1)
. Следовательно, data(M,N)
состоит из N
последовательных векторов-столбцов по M
элементов каждый. Расстояние между двумя элементами, например data(1,1)
и data(1,2)
, зависит от M
. Вот почему вы предоставляете M
в конструкторе типа. Матрицы с разным количеством строк (например, разные M
) не будут «подходить» к карте типов созданного типа, и для построения сообщения будут использоваться неправильные элементы.
person
Hristo Iliev
schedule
10.12.2012