Técnicas de Computação Paralela
Capítulo III
Design de Algoritmos Paralelos
José Rogado
jose.rogado@ulusofona.pt
Resumo do Capítulo
Introdução aos Algoritmos Paralelos
• Decomposição em Tarefas • Mapeamento para Processos • Processos e Processadores Técnicas de Decomposição • Decomposição Recursiva • Decomposição de Dados • Decomposição de Dados • Decomposição Exploratória • Decomposição Híbrida
Características das Tarefas e das Interacções
• Geração de Tarefas, Granularidade e Contexto • Características das Interacções inter-tarefas
Decomposição e Grafos de Dependência
O primeiro passo para desenvolver um algoritmo paralelo é
decompor o problema em tarefas que possam ser executadas concorrentemente
• Tarefa: unidade sequencial de execução
Um dado problema pode ser decomposto em tarefas de várias
formas distintas
• Diferentes metodologias e desempenho
Uma decomposição pode ser ilustrada sob forma de um grafo
direccionado com os nós representando tarefas e os arcos
indicando que o resultado de uma tarefa é um requisito de entrada para a seguinte
Granularidade da Decomposição
O número de tarefas em que um problema é decomposto determina a sua granularidade
• Número elevado de tarefas => decomposição fina • Número baixo de tarefas => decomposição grosseira
Exemplo: a multiplicação de uma matriz por um vector pode ser decomposta de uma forma fina numa linha por tarefa :
Grau de Concorrência
O número de tarefas que podem ser executadas em paralelo determina o
grau de concorrência de uma decomposição
Como esse número pode variar ao longo da execução de uma tarefa, define-se:
• Grau de concorrência máximo: número máximo de tarefas que podem correr em paralelo num dado instante da execução do algoritmo
• Grau de concorrência médio: número de tarefas médio que podem correr em paralelo ao longo da execução do algoritmo
correr em paralelo ao longo da execução do algoritmo
O grau de concorrência aumenta quando a decomposição se torna mais fina e vice-versa
• O grau de concorrência médio é determinado relacionando o valor total do custo de execução e o comprimento do caminho crítico de uma certa decomposição (ver próximo slide)
Comprimento do Caminho Crítico
Um caminho directo no grafo de dependências representa a
sequências de tarefas que devem ser processadas sequencialmente
• A cada nó do grafo (tarefa) está associado um peso, que é uma medida do trabalho a realizar ou do tempo de execução sequencial previsto dessa tarefa
O caminho directo mais longo desse grafo condiciona o valor mínimo
do tempo de execução
• A soma dos pesos de todos os nós ao longo desse caminho é • A soma dos pesos de todos os nós ao longo desse caminho é
designado pelo comprimento do caminho crítico • CP = ∑ Wi (i: nós do CC)
O grau de concorrência médio é determinado através do quociente
entre o valor do custo de execução total e o comprimento do caminho crítico, e mede a eficácia de uma decomposição
• WT = ∑ Wi (i: todos os nós)
Ex: Processamento de Queries a uma BD
Consideremos a execução da query: MODEL = ``CIVIC'' AND YEAR = 2001 AND
(COLOR = ``GREEN'' OR COLOR = ``WHITE) Na tabela de base de dados seguinte:
Ex: Processamento de Queries a uma BD
A execução da query pode ser decomposta em sub-tarefas de várias maneiras
Cada tarefa irá gerar uma tabela intermédia que resulta da aplicação de uma dada cláusula
O gráfico de dependência da execução pode ser o seguinte:
intersection union
Ex: Decomposição e Grafo Alternativos
Grafos de Dependências
Consideremos os dois grafos de dependência das duas decomposições do processamento da query à tabela de dados
• Os números dentro de cada nó representam de forma simplificada os custos de execução de cada tarefa
Trabalho total: WT= 63 Caminho Crítico:CP = ∑ Wi = 27 Concorrência média: AV= WT/ CP = 2.3 Trabalho total: WT = 64 Caminho Crítico:CP = ∑ Wi= 34 Concorrência média: : AV = WT / CP = 1.9
Caminho crítico Caminho crítico
A primeira decomposição conduz portanto a um grau de concorrência médio superior à segunda: mais eficaz
Tarefas, Processos e Mapeamento
Um processo é uma unidade de execução abstracta que pode
corresponder a uma ou mais tarefas
• A solução que consiste em atribuir cada tarefa a um processo diferente não é sempre a mais adequada, pois as dependências podem impedir a sua execução
O número de processos de uma decomposição é portanto inferior ou
igual ao número de tarefas
• A operação que consiste em atribuir tarefas a diferentes processos designa-se por mapeamento
• O mapeamento deve ser realizado com base no grafo de
dependências, que também representa as interacções existentes entre as tarefas
Mapeamento de Processos
O mapeamento de tarefas em processos é uma operação crítica para a optimização de desempenho
Um mapeamento óptimo deve minimizar o tempo de execução total Regras básicas:
1. Atribuição de tarefas independentes a processos diferentes
2. Repartição do trabalho de forma equitativa entre todos os processos 3. A interacção entre os processos deve ser a menor possível
4. Tarefas apresentando interacções elevadas devem ser executadas 4. Tarefas apresentando interacções elevadas devem ser executadas
pelo mesmo processo
5. Atribuição das tarefas do caminho crítico aos processos assim que estejam reunidas as condições de execução
Processo livre ou dados disponíveis
Nota: estes critérios podem ser por vezes contraditórios. Por exemplo o
mapeamento de todas as tarefas num só processo (ou ausência de
decomposição) minimiza as interacções… mas não garante aumento de desempenho
Exemplo de Mapeamento de Processos
O mapeamento mais eficaz das duas decomposições da query anterior é obtido através das seguintes considerações
Técnicas de Decomposição
Decomposição de algoritmos em sub-tarefas:
Embora não exista uma receita única para todos os problemas,
existem uma série de metodologias que permitem resolver uma grande classe de problemas
Nomeadamente: Nomeadamente: • Decomposição Recursiva • Decomposição de Dados • Decomposição Exploratória • Decomposição Especulativa
Decomposição Recursiva
Técnica adaptada para algoritmos que possam ter uma estratégia de
resolução de tipo “dividir e conquistar”
O problema inicial é decomposto num conjunto de sub-problemas de
resolução independente, e de tratamento idêntico ao inicial
Estes por sua vez são decompostos recursivamente até que seja
atingida a granularidade pretendida
O paralelismo é obtido pela possibilidade de resolver
simultaneamente os vários sub-problemas
O resultado do problema é obtido pela combinação dos resultados
Exemplo de Decomposição Recursiva - i
O Quicksort é um exemplo clássico de um algoritmo de tipo “dividir e conquistar” em
que se pode aplicar a decomposição recursiva
• O grafo de dependência das tarefas da decomposição da ordenação de uma lista de 12 números pode ser o seguinte:
A lista inicial é dividida em torno de um elemento pivot em duas sublistas uma com
todos os elementos inferiores ao pivot, e outra com todos os outros
• O algoritmo é de novo aplicado recursivamente a cada sub-lista • O tratamento de cada sub-lista pode ser realizado em paralelo
Exemplo de Decomposição Recursiva - ii
O cálculo do mínimo de uma lista de números também pode ser assimilado a um problema deste tipo e ser decomposto utilizando este método
Um algoritmo série para calcular o mínimo pode ser o seguinte:
1. procedure SERIAL_MIN (A, n) 2. begin
3. min = A[0];
4. for i := 1 to n − 1 do 4. for i := 1 to n − 1 do
5. if (A[i] < min) min := A[i];
6. endfor; 7. return min;
Exemplo de Decomposição Recursiva - iii
Se aplicarmos o mesmo método de decomposição, podemos dividir o problema em dois sub-problemas, em que cada um calcula o mínimo de metade dos
elementos da lista, e prosseguir recursivamente
O algoritmo recursivo para esse caso pode ser o seguinte:
1. procedure RECURSIVE_MIN (A, n) 2. begin 3. if ( n = 1 ) then 4. min := A [0] ; 5. else 5. else 6. lmin := RECURSIVE_MIN ( A, n/2 );
7. rmin := RECURSIVE_MIN ( &(A[n/2]), n - n/2 );
8. if (lmin < rmin) then
9. min := lmin; 10. else 11. min := rmin; 12. endelse; 13. endelse; 14. return min; 15. end RECURSIVE_MIN
O processo termina quando houver um só elemento em cada uma das sub-listas
O grau de paralelismo pode ser levado ao extremo, em que cada processo só
Exemplo de Decomposição Recursiva - iv
Decomposição do cálculo do mínimo dos números {4, 9, 1, 7, 8, 11, 2, 12}
Cada nó na arvore representa a tarefa que consiste em calcular o mínimo de uma lista de números através do mesmo método invocado recursivamente
min (4,9,1,7) min (8,11,2,12) min (4,9,1,7,8,11,2,12)
min (4,9) min (1,7) min (8,11) min (2,12)
min (4,1) min (8,2)
Decomposição Baseada nos Dados
Este tipo de decomposição é baseado na identificação dos dados
que são objecto de computação
• Dados de entrada • Dados intermédios • Dados de saída
Os dados de computação são particionados em subconjuntos
Essa partição é utilizada para realizar uma decomposição do Essa partição é utilizada para realizar uma decomposição do
trabalho a realizar, em que cada tarefa é responsável pelo subconjunto de dados que lhe é atribuído
É uma das decomposições mais utilizada no caso de tratamento de
grandes quantidades de dados
• A forma como os dados são particionados condiciona o desempenho da solução
Muitas vezes, os dados de saída são calculados exclusivamente a
partir dos dados de entrada
A decomposição é realizada através da atribuição de uma tarefa ao
cálculo de cada subconjunto da partição dos dados
Exemplo
• Multiplicação de Matrizes
Partição dos Dados de Saída
A decomposição mais simples é particionar a matriz resultado em
Dados de Saída: Exemplo
Uma dada partição dos dados de saída não implica uma
decomposição única do problema em tarefas
A partição de dados anterior pode originar outras decomposições,
através de mapeamentos diferentes do tratamento a tarefas:
Partição dos Dados de Entrada
Muitas vezes, não é possível determinar previamente os dados de
saída, ou existe um único valor final
• Ex.: ordenações ou cálculo de valores extremos
Nesse caso a solução é particionar os dados de entrada e atribuir
uma tarefa a cada partição
Se os dados de saída não forem uma função directa dos dados de
entrada, é ainda necessário combinar os vários resultados intermédios para obter os resultados finais
• Exemplo: no cálculo do mínimo de n valores, dividido em duas partições de n/2 valores, e necessário calcular o mínimo dos dois valores intermédios
Dados de Entrada: Exemplo
Consideremos o problema da contagem das referências a certos itens de uma base de dados no registo das suas transacções
O registo das transacções e os itens são os inputs do problema
As frequências de ocorrência são os outputs O conjunto das transacções é dividido em 2 subconjuntos e a contagem das ocorrências subconjuntos e a contagem das ocorrências em cada um são atribuídas a duas tarefas distintas
Para obter o resultado final, é necessário somar termo a termo os resultados de cada tarefa
Partição dos Dados de Entrada e Saída
Por vezes, podem-se combinar as partições dos dados de entrada e saída de forma a obter um maior grau de concorrência
No exemplo anterior, realiza-se a partição das transações e das ocorrências, obtendo a seguinte decomposição:
Cada tarefa calcula uma partição dos resultados
resultados
Para obter o resultado final, é necessário somar os resultados da partição de entrada,
Partição dos Dados Intermédios
Muitas vezes, uma computação pode ser encarada como uma sequência de transformações sucessivas sobre os dados de entrada para obter os dados de saída
• A partição dos dados intermédios pode levar a graus de paralelismo mais elevados pois pode não ser possível prever todas as etapas intermédias a partir dos dados iniciais ou finais
Exemplo: o produto C de duas
matrizes A e B pode ser considerada matrizes A e B pode ser considerada como a soma de duas matrizes D intermédias obtidas por multiplicação de partes das matrizes iniciais
O particionamento é feito a partir dos dados de saída das matrizes
Exemplo: Dados Intermédios
Etapa 1: cálculo dos elementos das duas matrizes intermédias Etapa 2: soma dos elementos
para obter a matriz final
Esta abordagem pode trazer melhores resultados no caso em que o número de elementos das matrizes é muito elevado e em que uma decomposição simples baseada nos
resultados não introduz o grau de paralelismo adequado à plataforma
“The Owner Computes Rule”
As decomposições baseadas nos dados de entrada ou saída são
geralmente designadas pela regra “The Owner Computes Rule”
• “O dono é que trata”
Essa regra estabelece que geralmente o processo ao qual é
atribuído um subconjunto de dados é responsável por toda a computação associada
Utilizando esta regra, torna-se simples realizar o mapeamento de
dados a tarefas
No caso de decomposição baseada nos dados de entrada, a tarefa à
qual é atribuída uma dada partição de dados, é responsável por todo o tratamento desses dados
• Idem para os casos de decomposições baseadas nos dados de saída ou intermédios
Decomposição Exploratória
Em certas classes de problemas, a decomposição está associada a
certas fases da execução do algoritmo, e não a um conjunto de dados em especial
É o caso em problemas em que a solução envolve a exploração de
espaços de possíveis soluções
Exemplos de problemas deste tipo:
• Análise combinatória
• Problemas de optimização discreta • Prova de teoremas
• Jogos
Uma aplicação simples de decomposição exploratória é a que permite descobrir o conjunto de jogadas que permite chegar à resolução de um puzzle de 15 peças móveis
Decomposição Exploratória: Exemplo
A sequência {a, b, c, d} conduz à solução do puzzle
Para descobrir esta sequência de forma programática, uma solução consite em testar todas as possibilidades que existem na configuração (a) e
escolher aquela que corresponde a um estado mais próximo da solução http://www.thepcmanwebsite.com/media/tile_puzzle
Exploração de Espaços Combinatórios
A decomposição paralela é feita gerando um primeiro nível de soluções possíveis e
atribuindo cada solução a uma tarefa que realiza a exploração do respectivo espaço
Quando uma solução intermédia é encontrada por uma das tarefas, as que não
tiveram êxito devem ser interrompidas e atribuídas à exploração de novos espaços gerados a partir do novo estado
Em muitos casos de decomposição exploratória, a partição dos espaços de exploração
pode levar a grandes diferenças na quantidade de computação necessária à descoberta da solução
Podem resultar em ganhos anómalos nos tempos de execução Exemplo: cada espaço combinatório tem m elementos
Influência da Decomposição
No caso (a) a solução encontra-se no início do 3º espaço exploratório
No caso (b) encontra-se no fim do primeiro espaço e não há ganhos no tempo de execução
Decomposição Especulativa
Nalgumas aplicações específicas, as dependências entre as várias tarefas não são conhecidas à priori
• Dependem dos resultados de execução intermédios
• Nesses casos, é impossível identificar tarefas independentes
Podem ser utilizadas duas aproximações
• Aproximação conservadora: só considerar tarefas independentes quando há garantia de não haver dependências
• Aproximação optimista: criação de tarefas independentes mesmo • Aproximação optimista: criação de tarefas independentes mesmo
quando não existe certeza antecipada, confiando num mecanismo de avaliação a posteriori das dependências
No primeiro caso podem-se obter níveis de concorrência reduzidos
No segundo caso, é necessário estabelecer mecanismos de controle e roll-back para eventualmente desfazer trabalho efectuado por antecipação que
Decomposição Especulativa: Exemplo
Consideremos o caso de uma aplicação de simulação de um sistema real constituído
por vários nós de execução ligados por um conjunto de conectores direccionais
• Pode ser uma rede de computadores ou uma linha de montagem de uma fábrica O valor do output de um nó pode condicionar o caminho a seguir para o
processamento nos nós seguintes
• O processamento dos nós {C, D, E} e {E, F} é realizado alternadamente em função dos valores de saída dos nós A e B
É possível antecipar por exemplo o processamento do nó E com valores
simulados antes de se saber se será efectivamente a escolha certa, pois a sua probabilidade de escolha é maior
Decomposição Híbrida
Na maioria dos casos, é utilizada uma mistura das várias técnicas apresentadas para
decompor eficazmente um problema, ao longo de várias etapas de decomposição
Exemplos:
• No algoritmo Quicksort apresentado, a utilização exclusiva da recursividade não é adequada, pois pode levar a um número de tarefas exageradamente elevado face às capacidades do sistema (nº de processadores, pilha, ...)
Nesse caso foi utilizado primeiro uma partição dos dados de entrada e depois
recursividade
• No caso do exemplo de simulação anterior, pode ser utilizada decomposição • No caso do exemplo de simulação anterior, pode ser utilizada decomposição
especulativa e partição dos dados de entrada
• Mesmo para problemas simples como a de encontrar o mínimo de uma lista de números a utilização de partição de dados e recursividade é adequada
Trabalho Prático
Utilizar um dos algoritmos sugeridos na teórica e utilizá-lo uma ou
duas técnicas de decomposição apresentadas num caso prático
1 2 3 4
5 6 7 8
Sugestão
• Resolução de um slide puzzle de 4x4
• Representação: vector de 16 chars que podem tomar os valores de 0x0 a 0xF
9 A B C
D E F 0
a 0xF
• A casa vazia é representada pelo valor 0
• Os movimentos possíveis para a casa vazia i são os seguintes
i+1 => i i-1 => i i+4 => i i-4 => i