Interface de passagem de mensagens

MPI

logotipo
Dados básicos

desenvolvedor Fórum MPI
Versão atual  Versão 4.0 (PDF; 4,3 MB)
(9 de junho de 2021)
sistema operacional Linux , Unix , Microsoft Windows NT , macOS
categoria API
Falando alemão Não
Site da MPI

Message Passing Interface ( MPI ) é um padrão que descreve a troca de mensagens durante cálculos paralelos em sistemas de computador distribuídos. Ele define uma coleção de operações e suas semânticas, ou seja, uma interface de programação , mas nenhum protocolo específico e nenhuma implementação.

Um aplicativo MPI geralmente consiste em vários processos que se comunicam entre si , todos iniciados em paralelo no início da execução do programa. Todos esses processos trabalham juntos em um problema e usam mensagens para troca de dados que são explicitamente enviadas de um processo para outro. Uma vantagem desse princípio é que a troca de mensagens também funciona além dos limites do computador. Os programas MPI paralelos podem, portanto, ser executados em clusters de PC (aqui, a troca de mensagens, por exemplo, via TCP ) e em computadores paralelos dedicados (aqui a troca de mensagens ocorre por meio de uma rede de alta velocidade, como InfiniBand ou Myrinet ou via rede principal compartilhada memória ).

história

Em 1992, o desenvolvimento do padrão MPI 1.0 começou com rascunhos (novembro de 1992, fevereiro de 1993, novembro de 1993). O ponto de partida foram as bibliotecas de comunicação mais antigas, como PVM, PARMACS, P4, Chameleon e Zipcode. O padrão apareceu em 5 de maio de 1994 com

  • Comunicação ponto a ponto
  • comunicação global
  • Grupos, contexto e comunicadores
  • Arredores
  • Interface de criação de perfil
  • Integração de linguagem para C e Fortran 77

Em junho de 1995, os erros foram corrigidos com o MPI 1.1.

Em 18 de julho de 1997, foi publicada a versão estável MPI 1.2, que, além de novas correções de erros, permite a identificação da versão. Também é conhecido como MPI-1.

Em 30 de maio de 2008, o MPI 1.3 foi lançado com mais correções de bugs e esclarecimentos.

Ao mesmo tempo que a versão 1.2, o padrão MPI 2.0 foi adotado em 18 de julho de 1997. Isso também é conhecido como MPI-2 e inclui as seguintes extensões:

  • entrada / saída de arquivo paralelo
  • gerenciamento de processo dinâmico
  • Acesso à memória de outros processos
  • integração de linguagem adicional de C ++ e Fortran 90

Em 23 de junho de 2008, as partes anteriormente separadas MPI-1 e MPI-2 foram combinadas em um documento comum e publicadas como MPI 2.1. MPI Standard Versão 2.2 é datado de 4 de setembro de 2009 e contém outras melhorias e pequenas melhorias.

Em 21 de setembro de 2012, o MPI Forum publicou MPI-3, que incorpora novas funcionalidades, como coletivos não bloqueadores, um modelo de comunicação unilateral aprimorado (RMA, Remote Memory Access), uma nova interface Fortran, comunicação relacionada à topografia e não -bloqueio de entrada e saída paralelas.

MPI-4 foi lançado em 9 de junho de 2021. As principais inovações são interfaces de funções que suportam parâmetros com uma faixa maior de valores. Anteriormente, devido ao tipo de dados de 32 bits especificado , parâmetros essenciais como B. o número de elementos de dados a serem comunicados é limitado a pouco mais de dois bilhões. Os coletivos persistentes abrem possibilidades para otimizar a comunicação repetida e, ao contrário das operações coletivas já existentes, podem ser executados em qualquer ordem. Além disso, o tratamento de erros foi aprimorado em muitos pontos e um novo modelo de sessão para o uso dinâmico dos recursos gerenciados pelo MPI foi introduzido.

Um dos principais desenvolvedores é Bill Gropp .

Comunicação ponto a ponto

O tipo mais básico de comunicação ocorre entre dois processos: um processo de envio transfere informações para um processo de recebimento. Em MPI, esta informação é embalado em chamadas mensagens com os parâmetros buffer, counte datatypesão descritos abaixo. Deve existir uma operação de recebimento adequada para cada operação de envio. Como a mera sequência de operações de processamento nem sempre é suficiente em aplicativos paralelos, o MPI também oferece o tagparâmetro - somente se esse valor for idêntico para as operações de envio e recebimento, os dois se encaixarão.

Bloqueio de envio e recebimento

As operações mais simples para comunicação ponto a ponto são enviar e receber :

int MPI_Send (void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
  • buf : Ponteiro para o buffer de envio
  • contagem : número de elementos no buffer de envio
  • tipo de dados : tipo de dados dos elementos no buffer de envio
  • dest : Classificação do processo alvo
  • tag : marca a mensagem
  • comm : comunicador do grupo de processo
int MPI_Recv (void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status* status)
  • buf: Ponteiro para um buffer de recebimento de tamanho suficiente
  • count: Número de elementos no buffer de recepção
  • datatype: Tipo de dados dos elementos no buffer de recebimento
  • source: Classificação do processo de origem (com source=MPI_ANY_SOURCEé recebido por qualquer processo)
  • tag: marcação esperada da mensagem ( tag=MPI_ANY_TAGcada mensagem é recebida com)
  • comm: Comunicador do grupo de processo
  • status: Ponteiro para uma estrutura de status na qual as informações sobre a mensagem recebida devem ser armazenadas

As duas operações são de bloqueio e assíncronas . Que significa:

  • MPI_Recvpode ser executado antes que o associado tenha MPI_Sendiniciado
  • MPI_Recv bloqueado até que a mensagem tenha sido completamente recebida

O seguinte se aplica de forma análoga:

  • MPI_Sendpode ser executado antes que o associado tenha MPI_Recviniciado
  • MPI_Send bloqueado até que o buffer de envio possa ser reutilizado (ou seja, a mensagem foi completamente transmitida ou temporariamente armazenada em buffer)

Programa de amostra

O uso de MPI_Sende MPI_Recvé ilustrado no seguinte exemplo ANSI-C para 2 processos MPI:

#include "mpi.h"
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int myrank, message_size=50, tag=42;
    char message[message_size];
    MPI_Status status;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

    if (myrank == 0) {
        MPI_Recv(message, message_size, MPI_CHAR, 1, tag, MPI_COMM_WORLD, &status);
        printf("received \"%s\"\n", message);
    }
    else {
        strcpy(message, "Hello, there");
        MPI_Send(message, strlen(message)+1, MPI_CHAR, 0, tag, MPI_COMM_WORLD);
    }
    MPI_Finalize();
    return 0;
}

Comunicação sem bloqueio

A eficiência de uma aplicação paralela pode freqüentemente ser aumentada pela sobreposição da comunicação com cálculo e / ou evitando tempos de espera relacionados à sincronização. Para tanto, o padrão MPI define a chamada comunicação sem bloqueio, na qual apenas é iniciada a operação de comunicação. Uma função separada deve então ser chamada para encerrar tal operação. Ao contrário da variante de bloqueio, quando a operação é iniciada, Requesté criado um objeto que pode ser usado para verificar ou aguardar a conclusão desta operação.

int MPI_Isend (void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request* request)
  • ...
  • request: Endereço da estrutura de dados que contém informações sobre a operação
int MPI_Irecv (void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request* request)
  • ...

Progresso da consulta

Para saber o andamento de uma dessas operações, a seguinte operação é usada:

int MPI_Test (MPI_Request* request, int* flag, MPI_Status* status)

Onde flag=1ou é 0definido dependendo se a operação foi concluída ou ainda está em andamento.

Aguardando bloqueio

A seguinte operação é usada para esperar por uma MPI_Isend- ou - MPI_Irecvoperação de forma bloqueadora :

int MPI_Wait (MPI_Request* request, MPI_Status* status)

Sincronizando o envio

As variantes síncronas MPI_Ssende também são MPI_Issenddefinidas para as operações de envio . Nesse modo, o envio não terminará até que a operação de recebimento associada seja iniciada.

Variantes de buffer

...

Grupos e comunicadores

Os processos podem ser resumidos em grupos , em que cada processo recebe um número único, a chamada classificação . É necessário um comunicador para acessar um grupo . Se uma operação de comunicação global deve ser restrita a um grupo, o comunicador pertencente ao grupo deve ser especificado. O comunicador para o conjunto de todos os processos é chamado MPI_COMM_WORLD.

O commgrupo pertencente ao comunicador está incluído

int MPI_Comm_group (MPI_Comm comm, MPI_Group* group)

As operações de conjunto usuais estão disponíveis para grupos de processos.

União

Dois grupos group1e group2podem ser combinados em um novo grupo new_group:

int MPI_Group_union (MPI_Group group1, MPI_Group group2, MPI_Group* new_group)

Os processos group1mantêm sua numeração original. Os group2que ainda não estão incluídos no primeiro são numerados consecutivamente.

Interseção

A intersecção de dois grupos é obtida com

int MPI_Group_intersection (MPI_Group group1, MPI_Group group2, MPI_Group* new_group)

diferença

A diferença entre dois grupos é obtida com

int MPI_Group_difference (MPI_Group group1, MPI_Group group2, MPI_Group* new_group)

Comunicação global

Em aplicações paralelas, muitas vezes encontramos padrões de comunicação especiais nos quais vários ou até mesmo todos os processos MPI estão envolvidos ao mesmo tempo. O padrão MPI, portanto, definiu suas próprias operações para os padrões mais importantes. Estes são aproximadamente divididos em três tipos: sincronização (barreira), comunicação (por exemplo, transmissão, coleta, tudo para todos) e comunicação acoplada com cálculo (por exemplo, redução ou varredura). Algumas dessas operações usam um processo MPI selecionado que tem uma função especial e é normalmente rootreferido como. Além das operações de comunicação regulares, também existem variantes baseadas em vetores (por exemplo, Scatterv) que permitem diferentes argumentos para cada processo onde faz sentido.

Transmissão

A operação de transmissão para três processos

Com a operação de transmissão , um processo MPI selecionado envia os mesmos dados para roottodos os outros processos em seu grupo comm. A função definida para isso é idêntica para todos os processos envolvidos:

int MPI_Bcast (void *buffer, int count, MPI_Datatype type, int root, MPI_Comm comm)

O processo MPI rootdisponibiliza bufferseus dados, enquanto os outros processos transferem o endereço de seu buffer de recebimento aqui. Os parâmetros restantes devem ser iguais (ou equivalentes) em todos os processos. Depois que a função retorna, todos os buffers contêm os dados que estavam originalmente rootdisponíveis apenas para.

Juntar

A operação de coleta

Com a operação Gather , o processo MPI coleta rootos dados de todos os processos envolvidos. Os dados de todos os buffers de envio são armazenados um após o outro (classificados de acordo com a classificação) no buffer de recebimento:

int MPI_Gather (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)

Variante baseada em vetor

A variante baseada em vetor da operação de coleta permite um número de elementos dependente do processo:

int MPI_Gatherv (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm)

  • recvcounts: Campo contendo o número de elementos recebidos pelos processos individuais (apenas para rootrelevantes)
  • displs: Campo cuja entrada i especifica a mudança no buffer de recebimento em que os dados do processo i devem ser armazenados (também apenas rootrelevante)

Deve-se observar que, nos campos, são permitidos intervalos no buffer de recebimento, mas não sobreposições. Se, por exemplo, 1, 2 e 3 elementos do tipo inteiro devem ser recebidos de 3 processos , então recvcounts = {1, 2, 3}e deve ser displs = {0, 1 * sizeof(int), 3 * sizeof(int)}definido.

Scatter

A operação de dispersão

Com uma operação de dispersão , o processo MPI envia rootcada processo envolvido em um elemento de dados diferente, mas igualmente grande:

int MPI_Scatter (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)

Variante baseada em vetor

int MPI_Scatterv (void *sendbuf, int *sendcounts, int *displs, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)

acumulação

A acumulação é uma forma especial de operação de coleta . Os dados de todos os processos envolvidos também são coletados aqui, mas também são reduzidos a uma data usando uma operação de redução especificada. Por exemplo, deixar que o valor no processo de classificação , em seguida, proporciona Reduzir (+), o total de todos os valores: .

int MPI_Reduce (void *sendbuf, void *recvbuf, int count, MPI_Datatype type, MPI_Op op, int root, MPI_Comm comm)

As opseguintes operações de redução predefinidas existem para o parâmetro :

Operações lógicas

  • MPI_LAND: link AND lógico
  • MPI_BAND: operação AND bit a bit
  • MPI_LOR: link OR lógico
  • MPI_BOR: operação OR bit a bit
  • MPI_LXOR: link lógico OU exclusivo
  • MPI_BXOR: operação OR exclusiva bit a bit

Operaçoes aritimeticas

  • MPI_MAX: Máximo
  • MPI_MIN: Mínimo
  • MPI_SUM: Total
  • MPI_PROD: Produtos
  • MPI_MINLOC: Mínimo com processo
  • MPI_MAXLOC: Máximo com processo

As operações MPI_MINLOCe também MPI_MAXLOCretornam a classificação do processo MPI que determinou o resultado.

Operações personalizadas

Além das operações de redução predefinidas, você também pode usar suas próprias operações de redução. Para tanto, é anunciada ao MPI uma operação de lógica binária livremente programável, que deve ser associativa e opcionalmente comutativa:

int MPI_Op_create (MPI_User_function *function, int commute, MPI_Op *op)

A função de usuário associada calcula um valor de saída de dois valores de entrada e faz isso - por razões de otimização - não apenas uma vez com escalares, mas elemento por elemento em vetores de qualquer comprimento:

typedef void MPI_User_function (void *invec, void *inoutvec, int *len, MPI_Datatype *datatype)

Redução de Prefixo

Além da acumulação mencionada acima, existe também uma variante Allreduce - que disponibiliza o mesmo resultado para todos os processos MPI e não apenas para um rootprocesso. A chamada redução de prefixo agora estende essa opção, não calculando o mesmo resultado para todos os processos, mas sim calculando um resultado parcial específico do processo. Por exemplo, deixar de novo o valor no processo de classificação , em seguida, proporciona leitura (+) a soma parcial dos valores de classificação para : .

int MPI_Scan (void *sendbuf, void *recvbuf, int count, MPI_Datatype type, MPI_Op op, MPI_Comm comm)

Se o próprio valor não for incluído no cálculo (ou seja, excluído), isso pode ser feito com a função de varredura exclusiva MPI_Exscan.

Allgather

A Operação Allgather

Na operação Allgather , cada processo envia os mesmos dados para todos os outros processos. É, portanto, uma operação multi-broadcast na qual não existe um processo MPI separado.

int MPI_Allgather (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm)

Todos para todos (troca total)

A operação tudo-para-todos

Com a comunicação geral - semelhante à comunicação Allgather - os dados são trocados entre todos os processos. No entanto, apenas a i- ésima parte do buffer de envio é enviada para o i- ésimo processo. Os dados que vêm do processo com classificação j são correspondentemente armazenados na j -ésima posição no buffer de recepção.

int MPI_Alltoall (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm)

Também existe a operação de sincronização MPI_Barrier . Esta função só retorna depois que todos os processos MPI no grupo especificado alcançaram esta parte do programa.

MPI-2

Uma segunda versão do padrão MPI está disponível desde 1997, adicionando algumas extensões ao padrão MPI-1.1 ainda existente. Essas extensões incluem, entre outros

  • gerenciamento de processo dinâmico, d. H. Os processos agora podem ser criados e excluídos em tempo de execução
  • acesso [paralelo] ao sistema de arquivos
  • comunicação unilateral
  • Especificação de interfaces de linguagem adicionais (C ++, Fortran 90), em que as interfaces de linguagem para C ++ foram marcadas como obsoletas desde MPI 2.2

Exemplo: Lendo uma matriz nx (n + 1) com entrada de arquivo paralela e processos de tamanho com a classificação de números = 0… tamanho-1. A coluna n + 1 contém o lado direito do sistema de equações A * x = b na forma da matriz estendida [A, b]. As linhas da matriz são distribuídas uniformemente pelos processadores. A distribuição ocorre ciclicamente (cada processador em uma linha, após a classificação das linhas de tamanho = 0 ser servida novamente) e não em blocos (cada processador obtém um bloco contíguo de linhas n / tamanho):

   ndims = 1;                /* dimensions          */
   aosi [0] = size * (n+1);  /* array of sizes      */
   aoss [0] = n+1;           /* array of subsizes   */
   aost [0] = rank * (n+1);  /* array of starts     */
   order = MPI_ORDER_C;      /* row or column order */
   MPI_Type_create_subarray (ndims, aosi, aoss, aost, order, MPI_DOUBLE, &ft);
   MPI_Type_commit (&ft);
   MPI_File_open (MPI_COMM_WORLD, fn, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);
   MPI_File_set_view (fh, sizeof (int), MPI_DOUBLE, ft, „native“, MPI_INFO_NULL);
   for (i = rank; i < n; i+=size)
   {   MPI_File_read (fh, rdbuffer, n+1, MPI_DOUBLE, &status);
       for (j = 0; j < n+1; j++)
       {   A [i / size] [j] = rdbuffer [j]; /* nur die dem Prozess zugeordneten Zeilen */
   }   }
   MPI_File_close (&fh);

A interface segue o padrão POSIX 1003.1 com pequenas alterações devido ao paralelismo. O arquivo é aberto para leitura comum com MPI_File_open. As aberturas (visualizações) para os processos individuais são definidas com MPI_File_set_view. A variável ft (tipo de arquivo) definida anteriormente é necessária aqui, na qual uma linha com n + 1 dobra é selecionada em um bloco de tamanho * (n + 1) dobra, começando no rank de posição * (n + 1). Assim, de todo o bloco, exatamente uma linha é atribuída sucessivamente a cada processo. Este tipo é definido com MPI_Type_create_subarray e tornado conhecido no sistema MPI com MPI_Type_commit. Cada processo lê "suas" linhas com os números i = classificação, classificação + tamanho, classificação + 2 * tamanho, ... até que toda a matriz tenha sido lida com MPI_File_read. O argumento tamanho do (int) leva em consideração o tamanho da matriz, que é armazenado como um int no início do arquivo.

Benefício: Em processadores de tamanho, uma matriz pode ser armazenada de forma distribuída que não teria mais nenhum espaço na memória de um único processador. Isso também justifica a convenção de especificar a soma da memória dos núcleos individuais e nós individuais como a memória de um sistema paralelo.

Formato de arquivo:

n
Zeile 0 (n+1) Zahlen für Prozess rank 0
Zeile 1 (n+1) Zahlen für Prozess rank 1
…
Zeile r (n+1) Zahlen für Prozess rank r
…
Zeile size-1 (n+1) Zahlen für Prozess rank size-1
Zeile size (n+1) Zahlen für Prozess rank 0
Zeile size+1 (n+1) Zahlen für Prozess rank 1
…
Zeile size+r (n+1) Zahlen für Prozess rank r
…
Zeile 2*size-1 (n+1) Zahlen für Prozess rank size-1
Zeile 2*size (n+1) Zahlen für Prozess rank 0
…
…
es folgen entsprechend der Zeilenzahl der Matrix ausreichend viele solcher Blöcke

A leitura real é feita com MPI_File_read. Cada processo lê sequencialmente apenas as linhas atribuídas a ele. A operação coletiva é que a biblioteca MPI pode otimizar e paralelizar a leitura. Terminada a leitura, o arquivo deve ser fechado normalmente. Isso é feito com MPI_File_close. MPI tem seus próprios tipos de dados MPI_Datatype ft e MPI_File fh para as operações. O tipo de arquivo é descrito com variáveis ​​C normais: int ndims; int aosi [1]; int aoss [1]; int aost [1]; ordem interna;

Mais em.

Implementações

C ++, C e Fortran

A primeira implementação do padrão MPI-1.x foi MPICH do Argonne National Laboratory e da Mississippi State University . MPICH2, que implementa o padrão MPI-2.1, agora está disponível. O LAM / MPI do Ohio Supercomputing Center foi outra versão gratuita, cujo desenvolvimento foi interrompido em favor do Open MPI.

A partir da versão 1.35 das Bibliotecas Boost existe Boost.MPI, uma interface amigável C ++ para várias implementações MPI. Outros projetos, como B. TPO ++ , oferecem esta possibilidade e são capazes de enviar e receber contêineres STL.

C #

Pitão

Java

Pérola

R.

Haskell

Veja também

literatura

  • Heiko Bauke, Stephan Mertens: Cluster Computing. Springer, 2006, ISBN 3-540-42299-4
  • William Gropp, Ewing Lusk, Anthony Skjellum: MPI - An Introduction - Portable Parallel Programming with the Message-Passing Interface . Munich 2007, ISBN 978-3-486-58068-6 .
  • M. Firuziaan, O. Nommensen: Parallel Processing via MPI & OpenMP . Linux Enterprise, 10/2002
  • Marc Snir , Steve Otto, Steven Huss-Lederman, David Walker, Jack Dongarra : MPI - A referência completa , Vol 1: O núcleo MPI. 2ª Edição. MIT Press, 1998
  • William Gropp, Steven Huss-Lederman, Andrew Lumsdaine, Ewing Lusk, Bill Nitzberg, William Saphir, Marc Snir: MPI-The Complete Reference , Vol. 2: The MPI-2 Extensions. The MIT Press, 1998.

Links da web

Evidência individual

  1. MPI Documentos ( Memento do originais de 6 de Novembro de 2006, no Internet Archive ) Info: O arquivo de ligação foi inserido automaticamente e ainda não foi marcada. Verifique o link original e o arquivo de acordo com as instruções e, em seguida, remova este aviso. @ 1@ 2Modelo: Webachiv / IABot / www.mpi-forum.org
  2. ^ O futuro de MPI . (PDF)
  3. Mudanças no MPI-4.0
  4. MPI-2: Extensões para a interface de passagem de mensagens ( Memento do originais de 21 de Setembro de 2007, na Internet Archive ) Info: O arquivo de ligação foi inserido automaticamente e ainda não foi marcada. Verifique o link original e o arquivo de acordo com as instruções e, em seguida, remova este aviso. @ 1@ 2Modelo: Webachiv / IABot / www.mpi-forum.org