Criar um Cluster de Processamento Paralelo MPI com Raspberrys

Introdução

O Raspberry foi um sucesso desde o seu lançamento e continua a fascinar programadores, makers, hackers, estudantes e até cientistas, pela sua performance e baixo custo.

São sistemas SoC (System on a Chip), de baixo custo, baseados em arquitectura ARM, com muito potencial por explorar e pelo seu baixo consumo energético tornam-se equipamentos de eleição para pequenos e grandes projectos.

Processamento paralelo

Nos últimos anos a evolução dos processadores foi confrontada com as limitações ao aumento da frequência do ciclo do relógio. Com efeito, cada vez que se aumenta a frequência do relógio, aumenta o consumo de energia e o calor produzido de forma proporcional, o que sugere a aproximação de limites físicos dos circuitos.

Assim, como resultante do melhoramento do processo de fabrico dos circuitos integrados, em consonância com a Lei de Moore que estabelece que o número de transístores duplica cada dois anos, a resposta no mercado dos processadores passou por introduzir mais processadores no mesmo chip (multi-núcleo), aumentando a capacidade de processamento do chip, sem sofrer os problemas de eficiência energética e controlo de temperatura associados ao aumento da frequência do ciclo de relógio dos processadores “convencionais”. Esta alternativa engenhosa, de aumentar o desempenho do processamento, pela via do paralelismo por hardware tem vindo a impor-se tanto no mercado doméstico, como no das máquinas de elevada exigência.

O paralelismo oferece a grande vantagem de reduzir o tempo de processamento de grandes volumes de dados e cálculos matemáticos complexos, pela via do processamento paralelo com recurso a múltiplos nós, com um ou mais processadores por nó.

O tempo de processamento de um determinado input é normalmente proporcional à quantidade de dados de entrada, podendo tornar-se um factor limitativo quando existem cálculos computacionalmente intensivos ou com grandes volumes de dados. Assim, tendo em conta a consolidação das tecnologias associadas ao paralelismo ao longo dos últimos anos e a existência de sistemas de computação paralela acessíveis à comunidade, pode considerar-se inevitável o recurso ao paralelismo para minimizar o tempo consumido no processamento de dados. 

O processamento paralelo é particularmente útil quando o volume de dados a serem processados não depende recursivamente dos outputs uns dos outros, podendo ser divido em blocos e estes, processados simultaneamente. Este tipo de problema, conhecido como embaraçosamente paralelo, consiste na divisão de trabalhos entre todas as “entidades” de processamento disponíveis, no processamento independente do trabalho enviado para cada “entidade” e por fim na junção dos resultados para obtenção do output final.

Cluster Raspberry Pi: sequencial vs paralelo
Figura 1: Diagrama ilustrativo das diferenças entre o processamento sequencial e paralelo. descrição

Quando um mesmo problema tem a oportunidade de ser executado com o dobro dos recursos computacionais é expectável que o tempo de execução total seja reduzido para a metade, no entanto, isto só é verdade em casos muito específicos explicados mais à frente. 

Segundo a Lei de Amdahl, o tempo total de execução T, utilizando N entidades de processamento, pode ser reduzido para o limite teórico T(N) depende da fracção B do problema que não pode ser computada em paralelo, de acordo com a seguinte equação:

T(N) = T(1) (B + 1/N (1 – B))

Não obstante à melhoria máxima teórica prevista pela Lei de Amdahl, o ganho oferecido pelo paralelismo pode ser limitado por vários outros factores. Um dos principais factores limitativos do ganho de desempenho através do paralelismo é a largura de banda de acesso aos dados, uma vez que a capacidade de cálculo dos processadores atuais supera habitualmente a largura de banda de carregamento de informação, quer estejam na memória, em discos ou na rede.

O desfasamento da velocidade do processador em comparação com os dispositivos de armazenamento é tão grande que em muitos tipos de problema não é possível manter as unidades de processamento ocupadas durante todo o tempo, porque mesmo com grandes optimizações nos padrões de acesso à memória, com intuito de maximizar a utilização dos vários níveis de memória cache, e com esforços para maximizar a largura de banda dos sistemas de discos rígidos, os processados acabam por passar a maior parte do tempo ociosos a espera de receber dados para processar. 

A situação é agravada quando os acesso os dados estão em sistemas de armazenamento permanente em discos magnéticos comuns, tais como o IDE, SCSI, SAS, SATA, mesmo quando ligados em RAID. A investigação em entrada/saída de dados tem vindo a proporcionar avanços significativos nos sistemas de armazenamento de informação.

Aos factores acima referidos deve-se acrescentar a sobrecarga em tempo de processamento resultante da execução de código associado à gestão do paralelismo que pode ser tanto mais relevante quanto menor for a granularidade do paralelismo. Por outras palavras, devem ser tidas em conta as possíveis perdas resultantes da implementação do paralelismo, ou seja, na generalidade dos casos é preferível aumentar o grão da secção paralela, por oposição ao paralelismo de grão-fino. 

Outros factores relevantes surgem quando a zona paralela contém sincronizações, seja por limitações da implementação, ou por requisitos do problema que vêm a traduzir-se em “engarrafamentos” no desempenho, impedindo assim a obtenção de resultados mais próximos dos que seriam os teoricamente expectáveis, segundo a lei de Amdahl.

MPI (Message Passing Interface)

O MPI é um modelo de programação paralela para multiprocessamento baseado em message-passing, passagem-de-mensagem. Resumidamente consiste num conjunto de chamadas a bibliotecas que permitem aos multi-processos comunicarem entre si. Existem diversas implementações de MPI, no entanto na configuração que é apresentada abaixo apenas é referida a implementação MPICH.

As principais vantagens do MPI residem na escalabilidade, compatibilidade, mesmo em sistemas de memória partilhada, disponibilidade ampla e portabilidade. Como não existe “bela sem senão”, as desvantagens do MPI centram-se na curva de aprendizagem que tende a ser longa e no facto de não permitir paralelização incremental.

Só para contextualização histórica, o MPI começou a ser desenvolvido em finais da década de oitenta do século passado, e só tomou alguma “expressão maior” em Novembro de 1992, aquando da reunião do grupo de trabalho criado para dar continuidade ao processo de padronização de Message-Passing em ambientes de memória distribuída. Nessa reunião foi apresentado o primeiro esboço da interface de message-passing MPI1 e criado o MPI Fórum. Cerca de ano e meio mais tarde em 1994 foi disponibilizado para domínio público uma versão do padrão MPI

Tem vindo a ser desenvolvido o padrão e desenvolvidas diversas implementações de MPI, para uma grande variedade de plataformas e arquitecturas de computador, no entanto essa discussão sai do âmbito deste artigo.

Publicado na edição 48 (PDF) da Revista PROGRAMAR.