Программирование на кластерах с использованием инструментов Intel (Intel Cluster Studio)

Производные типы в MPI

Показывать лекцию целиком

Производные типы

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

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

    Производные типы данных создаются из базовых типов с помощью подпрограмм-конструкторов. Операции создания производных типов могут применяться рекурсивно.

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

    Подпрограмма MPI_Type_struct (см. Методическое пособие) является наиболее общим конструктором типа в MPI - программист может использовать полное описание каждого элемента типа. Если пересылаемые данные содержат подмножество элементов массива, такая детальная информация не нужна, поскольку у всех элементов один и тот же базовый тип. MPI содержит три конструктора, которые можно использовать в такой ситуации: MPI_Type_contiguous, MPI_Type_vector и MPI_Type_indexed. Первый из них создает производный тип, элементы которого являются непрерывно расположенными элементами массива. Второй создает тип, элементы которого расположены на одинаковых расстояниях друг от друга, а третий создает тип, содержащий произвольные элементы.

    "Векторный" тип создается конструктором MPI_Type_vector. Схема расположения данных в новом типе представлена на рис. 9.1.

    (рис 9.1) Схема векторного типа данных

    Лабораторная работа

    В заданиях лабораторной работы 4 предлагается дописать предлагаемые фрагменты программ на языке C, написанные с использованием процедур MPI. Пропущенные фрагменты обозначены многоточием.

    Задание 1

    В программе на языке Fortran имеется трехмерный массив arr. Используя приведенный ниже шаблон, дополните программу таким образом, чтобы в ней определялся производный тип, соответствующий: а) горизонтальному сечению массива; б) вертикальному сечению массива. Затем сечение должно пересылаться от процесса с рангом 0 процессу с рангом 1. Откомпилировать и запустить программу.

    program main_mpi
    include 'mpif.h'
    parameter  (n = 50)
    real arr(n,  n,  n), b(...)
    integer slice, sizeofreal
    integer rank, ierr, status(MPI_STATUS_SIZE)
    integer tag,   cnt,  vcount,  blocklen,   stride, count
    cnt = ...
    tag = 0
    vcount = .
    blocklen = ...
    call MPI_Init(ierr)
    call MPI_Comm_rank(MPI_COMM_WORLD,  rank, ierr) if   (rank.eq.0) then
    call MPI_Type_extent(MPI_REAL,  sizeofreal, ierr) stride = .
    call MPI_Type_vector(.)
    call MPI_Type_commit(slice, ierr)
    call MPI_Send(arr (...),  cnt,  slice,   1,  tag,  MPI_COMM_WORLD, ierr) 
    else if   (rank.eq.1) then count = .
    call    MPI_Recv(b,     count,     MPI_REAL,     0,     tag, MPI_COMM_WORLD, 
    status, ierr) print *, b end if
    call MPI_Finalize(ierr) end
     

    Задание 2

    В программе на языке C задаются типы членов производного типа, затем количество элементов каждого типа. После этого вычисляются адреса членов типа indata и определяются смещения трех членов производного типа относительно адреса первого, для которого смещение равно 0. Затем определяется производный тип. Аргументы подпрограмм MPI_Type_struct и MPI_Type_commit, а также некоторые другие фрагменты пропущены. Добавить эти фрагменты, откомпилировать и запустить программу.

    #include "mpi.h" #include <stdio.h>
    struct newtype {
    float a;
    float b;
    int n;
    };
    
    int main(int argc,char *argv[])
    {
    int myrank;
    MPI_Datatype NEW_MESSAGE_TYPE; int block_lengths[3]; 
    MPI_Aint displacements[3]; MPI_Aint addresses[4];
     MPI_Datatype typelist[3]; int blocks_number; struct newtype indata;
      int tag = 0; MPI_Status status;
    
    
    MPI_Comm_rank(MPI_COMM_WORLD,   myrank);
    
    typelist[0] = MPI_FLOAT; typelist[1] = MPI_FLOAT; typelist[2]   = MPI_INT;
    block_lengths[0]   = block_lengths[1]   = block_lengths[2]   = 1;
    MPI_Address(indata,  addresses[0]);
    MPI_Address((indata.a),  addresses[1]);
    MPI_Address((indata.b),  addresses[2]);
    MPI_Address((indata.n),  addresses[3]);
    displacements[0]  = addresses[1]  - addresses[0];
    displacements[1]  = addresses[2]  - addresses[0];
    displacements[2]  = addresses[3]  - addresses[0];
    blocks_number = 3;
    MPI_Type_struct(.);
    MPI_Type_commit(.);
    
    if   (myrank == 0)
    {
     
    indata.a = 3.14159; indata.b = 2.71828; indata.n = 2 0 02;
    
    MPI_Send(indata,   1,NEW_MESSAGE_TYPE,   1,  tag, MPI_COMM_WORLD); 
    printf("Process    %i    send:     %f    %f    %i\n",   
      myrank, indata.a, indata.b, indata.n);
    }
    else
    {
    MPI_Recv(indata, 1, NEW_MESSAGE_TYPE, 0, tag, MPI_COMM_WORLD, status);
    printf("Process %i received: %f %f %i, status %s\n", 
    myrank, indata.a,  indata.b,  indata.n, status.MPI_ERROR);
    }
    
    
    
    MPI_Finalize(); return 0;
    }
    Вернуться к учебному плану