2.6 O Paradigma de Coordena¸c˜ao
2.6.6 Programa¸c˜ao Paralela Funcional e Coordena¸c˜ao
2.6.6.4 Delirium
dena¸c˜ao e o c´odigo de computa¸c˜ao das entidades, atrav´es do uso de uma linguagem sepa-
rada para coordena¸c˜ao de processos. Ao contr´ario, em Linda, primitivas de coordena¸c˜ao s˜ao implementadas como extens˜ao `a linguagem host, tornando-se embutidas dentro desta linguagem. Delirium adota a abordagem inversa, tornando a linguagem host embutida na linguagem de coordena¸c˜ao, atrav´es do uso de operadores. Estes tem portanto o mesmo papel das primitivas de Linda, ou seja, unir as entidades coordenadas ao meio de coor- dena¸c˜ao.
Basicamente, Delirium ´e uma linguagem funcional convencional, suportando fun¸c˜oes de alta ordem, recurs˜ao, let-bindings, e express˜oes condicionais. No entanto, n˜ao h´a nenhuma primitiva de computa¸c˜ao definida na linguagem. Computa¸c˜ao ´e especificada por meio de operadores definidos em outra linguagem, como C ou Fortran. Abstrai-se assim de forma completa a parte de coordena¸c˜ao da parte de especifica¸c˜ao da computa¸c˜ao realizada por cada entidade coordenada. Partindo do pressuposto de que, em geral, o processo de constru¸c˜ao de um programa paralelo inicia-se com base em uma vers˜ao sequencial deste, a partir do qual s˜ao identificadas partes que podem ser executadas em paralelo, Delirium oferece um ambiente de programa¸c˜ao bastante expressivo, permitindo que as
partes paralelas do programa sejam integradas utilizando o arcabou¸co de coordena¸c˜ao provido pela linguagem, evitando assim a reescrita de c´odigo.
O modelo de paralelismo de Delirium ´e determin´ıstico, tornando tal modelo satis- fat´orio para express˜ao de programas paralelos s´ıncronos, utilizando a no¸c˜ao de estruturas
de coordena¸c˜ao [158]. Entretanto, a grande cr´ıtica com rela¸c˜ao ao modelo de coordena¸c˜ao
adotado por Delirium ´e justamente sua dificuldade em expressar padr˜oes irregulares de paralelismo, sendo assim bastante restritivo. Experimentos mostraram a ineficiˆencia de implementa¸c˜oes de programas paralelos que aderem a padr˜oes comuns de paralelismo, como o modelo de trabalhadores replicados (farm) e fork-join. Entretanto, seus defen- sores arguem que s˜ao justamente esses padr˜oes irrestritos de intera¸c˜ao, os quais podem gerar programas n˜ao-determin´ısticos, que tornam os programas paralelos t˜ao dif´ıceis de manter e depurar.
Delirium tem sido implementada eficientemente sobre arquiteturas de mem´orias dis- tribu´ıdas, utilizando um esquema de avalia¸c˜ao de operadores baseado em fluxo de da- dos, atrav´es de um grafo de coordena¸c˜ao que modela as dependˆencias de dados entre as unidades paralelas do programa. Uma importante observa¸c˜ao relativa a esta imple- menta¸c˜ao ´e a baixa sobrecarga gerada pelo seu sistema em tempo de execu¸c˜ao. Isso pˆode ser confirmado em uma aplica¸c˜ao de modelagem de retina em quatro processadores, onde a sobrecarga correspondeu a 1% do tempo total de execu¸c˜ao.
O MODELO # PARA PROGRAMAC¸ ˜AO PARALELA
A necessidade por ferramentas de mais alto n´ıvel que tornem a tarefa de programa¸c˜ao par- alela mais simples e abstrata para o desenvolvimento de aplica¸c˜oes complexas foi discutida nos cap´ıtulos 1 e 2. Especificamente neste ´ultimo, foram discutidos aspectos relacionados `a tarefa de programa¸c˜ao paralela sobre arquiteturas distribu´ıdas, em especial clusters.ˆ
Enfase foi dedicada `as limita¸c˜oes das t´ecnicas atuais, motivando a exposi¸c˜ao do ponto de vista, adotado neste trabalho, a cerca das caracter´ısticas que devem ser suportadas por um ambiente de programa¸c˜ao paralela ideal, as quais visam tornar essa tarefa mais simples, aproximando seu n´ıvel de dificuldade `a tarefa de programa¸c˜ao seq¨uencial. O em- prego de formalismos para a an´alise de propriedades formais de programas, modelagem de desempenho e simula¸c˜ao, algo negligenciado nas ferramentas existentes atualmente, deve ainda ser suportado. O modelo de coordena¸c˜ao foi introduzido como um importante passo conceitual para a evolu¸c˜ao dos modelos de programa¸c˜ao paralela de forma a atender esses requisitos.
O modelo #, apresentado neste cap´ıtulo, surgiu como consequˆencia das id´eias ilustradas nos cap´ıtulos anteriores. Sua concep¸c˜ao e evolu¸c˜ao foi orientada pelo seguinte conjunto de premissas e suposi¸c˜oes:
• Em ferramentas de programa¸c˜ao paralela, o uso de mecanismos impl´ıcitos para
explora¸c˜ao transparente do paralelismo em programas tem produzido resultados modestos com rela¸c˜ao ao desempenho. A este fato atribui-se o dif´ıcil trato computa- cional caracter´ıstico dos algoritmos para solu¸c˜ao ´otima e generalizada dos problemas envolvidos no gerenciamento autom´atico do paralelismo, como o particionamento e o balanceamento de carga, quando existentes. Especificamente no problema de par- ticionamento, a determina¸c˜ao do grau ´otimo de granularidade ´e ainda dificultado devido `a dependˆencia com a pr´opria semˆantica da aplica¸c˜ao e de caracter´ısticas intr´ınsecas `a arquitetura alvo, as quais s˜ao dif´ıceis de serem modeladas satisfatori- amente por meios formais;
• O uso de mecanismos dinˆamicos para gerenciamento do paralelismo em tempo de
execu¸c˜ao tamb´em n˜ao tˆem produzido resultados animadores em casos gerais. Isso se deve `a necessidade do uso de sistemas de gerenciamento do paralelismo em tempo de execu¸c˜ao. Estes implementam algoritmos que executam concorrentemente `as computa¸c˜oes efetivas do programa, causando uma sobrecarga que soma-se `a sobre- carga de comunica¸c˜ao j´a existente. Para reduzi-la, esses sistemas devem idealmente ser implementados de forma muito eficiente, possibilidade que contradiz-se ao dif´ıcil trato computacional dos problemas gerais associados ao gerenciamento autom´atico do paralelismo. A solu¸c˜ao para esse problema tem sido a implementa¸c˜ao de al-
goritmos que se aplicam a instˆancias simplificadas do problema geral ou o uso de
heur´ısticas, as quais n˜ao possuem garantias de resultados ´otimos;
• Com a grande evolu¸c˜ao em termos de desempenho nas tecnologias de comunica¸c˜ao
em redes de computadores e arquiteturas de processadores seq¨uenciais, com a redu¸c˜ao dos custos associados a aquisi¸c˜ao destas tecnlogias, o uso de arquiteturas de mem´oria distribu´ıda tornou-se vi´avel em processamento de alto desempenho. Essas arquiteturas oferecem grande escalabilidade. A emergˆencia da tecnologia de
clusters [18], sobretudo compostos com computadores pessoais, tem tido um pa-
pel preponderante neste contexto, por estes oferecerem poder computacional com- par´avel a supercomputadores, por´em a um custo muito inferior;
• Programas paralelos de granularidade fina apresentam baixo desempenho quando
executados sobre arquiteturas de mem´oria distribu´ıda, apesar da r´apida evolu¸c˜ao da tecnologia de comunica¸c˜ao nessas arquiteturas observado na ´ultima d´ecada;
• No paralelismo expl´ıcito, a mistura do c´odigo sequencial (computa¸c˜oes) com
o c´odigo que lida com o gerenciamento do paralelismo dificulta a con- stru¸c˜ao e compreens˜ao de programas paralelos, inviabilizando o reuso de c´odigo e tornando-o pouco port´avel. Nessa abordagem, multiplica-se `a dificuldade inerente `a programa¸c˜ao sequencial a dificuldade associada ao gerenciamento do paralelismo. A an´alise formal de programas, uma possiblidade real devido a existˆencia de for- malismos consagrados para esse fim [115, 169, 170, 188], ´e impossibilitada de ser realizada automaticamente, uma vez que o paralelismo, embora expl´ıcito, encontra- se obscurecido no c´odigo. Este problema se agrava quando o c´odigo sequencial ´e escrito em uma linguagem imperativa, as quais j´a s˜ao de dif´ıcil trato formal em sua forma pura. No caso de linguagens paralelas que extendem linguagens pr´e- existentes, torna-se necess´ario construir novos compiladores e, em muitos casos, sistemas em tempos de execu¸c˜ao para gerenciamento do paralelismo. N˜ao h´a por- tanto um aproveitamento direto da tecnologia de compila¸c˜ao sequencial j´a existente, o que ´e importante na otimiza¸c˜ao de desempenho de programas de grossa e m´edia granularidade, onde a maior parte do tempo de execu¸c˜ao do programa ´e gasto no modo sequencial de execu¸c˜ao;
• N˜ao existem metodologias para engenharia de programas paralelos em seu caso geral. Atribui-se este fato `a diversidade de modelos de programa¸c˜ao e arquiteturas f´ısicas destinadas ao suporte ao paralelismo, dificultando a ado¸c˜ao de uma abordagem padr˜ao para engenharia de programas;
• Em aplica¸c˜oes paralelas de alto desempenho, sobretudo em computa¸c˜ao cient´ıfica
e engenharia, a estrutura topol´ogica e o padr˜ao de intera¸c˜ao entre os processos ´e geralmente regular e est´atica [186, 177, 28], sendo estas portanto suposi¸c˜oes realistas no projeto de uma linguagem voltada `a programa¸c˜ao paralela em computa¸c˜ao de alto desempenho.
Com base nas premissas e suposi¸c˜oes estabelecidas, o modelo # ´e est´atico, expl´ıcito, e fundamentado na no¸c˜ao de hierarquia de processos. Processos s˜ao programados uti- lizando uma linguagem sequencial (linguagem host). Estes s˜ao ent˜ao interligados em uma rede de comunica¸c˜ao descrita atrav´es de uma linguagem de configura¸c˜ao capaz de definir canais atrav´es dos quais os processos comunicam-se. As caracter´ısticas das lin- guagens de configura¸c˜ao, empregadas largamente em sistemas distribu´ıdos e descri¸c˜ao de hardware, favorecem o emprego de metodologias modulares de desenvolvimento de sistemas de grande escala [144].
No projeto do modelo #, a linguagem de configura¸c˜ao deve ser projetada de forma a manter capacidade expressiva, para a descri¸c˜ao de padr˜oes de intera¸c˜ao entre proces- sos, equivalente `as redes de Petri lugar/transi¸c˜ao [188], um disseminado formalismo com grande n´umero de ferramentas dispon´ıveis para o seu suporte. Podemos ent˜ao usar redes de Petri para permitir a an´alise de propriedades de programas descritos no modelo #. Embora n˜ao sejam equivalentes a m´aquinas de Turing, as quais s˜ao capazes de descrever quaisquer padr˜oes de intera¸c˜ao e organiza¸c˜ao topol´ogica que podem ser encontrados em programas paralelos, redes de Petri s˜ao suficientemente expressivas para aplica¸c˜ao den- tro do contexto de aplica¸c˜oes de alto desempenho, as quais em geral descrevem padr˜oes regulares e est´aticos de intera¸c˜ao de processos e organiza¸c˜ao topol´ogica. Redes de Petri podem ainda ser aplicadas para predi¸c˜ao de custos de execu¸c˜ao e comunica¸c˜ao de progra- mas, utilizando algumas de suas variantes de alto n´ıvel, como, por exemplo, redes de Petri estoc´asticas e temporizadas. Os aspectos relativos ao uso de redes de Petri em ambientes de desenvolvimento baseados no modelo # ser˜ao discutidos em detalhes no Cap´ıtulo 5.
Em programas #, a hierarquia de processos garante que a especifica¸c˜ao das com-
puta¸c˜oes, realizada por unidades sequenciais (processos) programadas com a linguagem host, encontra-se hierquicamente separada da especifica¸c˜ao da coordena¸c˜ao entre estas
por meio da linguagem de configura¸c˜ao. As vantagens resultantes devido ao suporte `a hierarquia de processos s˜ao destacadas a seguir:
• A avalia¸c˜ao de desempenho e an´alise de propriedades formais de um programa
paralelo podem ser realizadas em n´ıvel de coordena¸c˜ao, abstraindo-se quaisquer su- posi¸c˜oes a cerca da implementa¸c˜ao das computa¸c˜oes que caracterizam a funcional- idade das unidades sequenciais. De maneira independente, ´e tamb´em poss´ıvel re- alizar a an´alise de propriedades formais e avalia¸c˜ao de desempenho de cada unidade sequencial, em n´ıvel de computa¸c˜ao, utilizando formalismos possivelmente distin- tos daquele aplicado em n´ıvel de coordena¸c˜ao, por´em apropriados `a linguagem host empregada;
• Aproveitamento do estado da arte da tecnologia de compila¸c˜ao sequencial de pro-
gramas, uma vez que a compila¸c˜ao das unidades sequenciais pode ser realizada de maneira independente a sua configura¸c˜ao na rede de processos, utilizando um compilador sequencial pr´e-existente, sem necessidade de modific´a-lo. O uso de compiladores sequenciais eficientes tem impacto importante sobre o desempenho de programas #, uma vez que o modelo # favorece a descri¸c˜ao de programas paralelos de m´edia e grossa granularidade. Devido a essa caracter´ıstica, o tempo de execu¸c˜ao desperdi¸cado no modo sequencial ´e predominante. Uma biblioteca de passagens de
mensagens pode ser usada para gerenciamento do paralelismo. Neste trabalho, foi adotada MPI (Message Passing Library) [73], por esta ter se tornado um padr˜ao de
facto em cluster computing, sendo bem documentada e reconhecidamente eficiente.
Os construtores do modelo # tˆem tradu¸c˜ao direta para as primitivas de MPI; Por favorecer a constru¸c˜ao de programas paralelos de granularidade m´edia e grossa e a minimiza¸c˜ao da sobrecarga do gerenciamento do paralelismo em sua implementa¸c˜ao, o modelo # ´e apropriado para aplica¸c˜ao sobre clusters de computadores pessoais conecta- dos por interfaces de rede convencionais, como Ethernet. Nesses ambientes, a latˆencia de comunica¸c˜ao entre os n´os de processamento ´e um fator cr´ıtico que pode afetar o desem- penho de programas.
O estilo de programa¸c˜ao caracter´ıstico do modelo # emprega fortemente a no¸c˜ao de composi¸c˜ao hier´arquica de programas e o conceito de esqueletos [63], os quais poten- cializam o reuso de parte de programas no n´ıvel de coordena¸c˜ao e a portabilidade entre arquiteturas.
Nas se¸c˜oes que se seguem, descreve-se detalhadamente o modelo #, introduzindo-se as abstra¸c˜oes suportadas por este modelo, as quais capturam a estrutura essencial pre- sente na especifica¸c˜ao de programas paralelos sob a perspectiva do meio de coordena¸c˜ao. Posteriormente, descrevemos a linguagem Haskell#, uma materializa¸c˜ao do modelo #, a qual emprega a linguagem # para configura¸c˜ao de processos em n´ıvel de coordena¸c˜ao e a linguagem funcional Haskell para especifica¸c˜ao das unidades sequenciais (m´odulos fun- cionais), em n´ıvel de computa¸c˜ao. Respectivamente, introduziremos os construtores da linguagem #, sua tradu¸c˜ao para MPI, e alguns exemplos simples de programas. Exemp- los mais complexos, especialmente com o emprego de esqueletos e composi¸c˜ao hier´arquica ser˜ao ilustrados no cap´ıtulo 4 e apˆendices.
3.1 AS PEC¸ AS B´ASICAS (COMPONENTES)
Componentes s˜ao abstra¸c˜oes para as entidades # que implementam funcionalidades, as quais, quando compostas, descrevem as computa¸c˜oes realizadas pelo programa par- alelo. Idealmente, cada componente implementa uma funcionalidade espec´ıfica, sendo descrito unicamente pela sua interface, composta por argumentos e pontos de retorno (Figura 3.1).
...
...
pontos de retorno argumentos?
Figura 3.1. ComponenteCom rela¸c˜ao a implementa¸c˜ao, existem dois tipos de componentes: simples e com-
computa¸c˜oes sequenciais que caracterizam o meio de computa¸c˜ao. Componentes com- postos descrevem computa¸c˜oes paralelas, sendo programados por meio da linguagem #, caracterizando o meio de coordena¸c˜ao. Portanto, estes s˜ao constitu´ıdos a partir de out- ros componentes, simples ou compostos, descrevendo uma hierarquia possivelmente an- inhada. ´E f´acil observar que, nessa hierarquia, os componentes localizados nas folhas s˜ao simples, enquanto aqueles localizados em n´os intermedi´arios s˜ao compostos.
Um programa # ´e definido por um componente em particular, o componente de
aplica¸c˜ao, o qual implementa a funcionalidade da aplica¸c˜ao. Note que um componente
de aplica¸c˜ao simples descreve um programa # sequencial, enquanto um componente de aplica¸c˜ao composto descreve um programa # paralelo.