Estudo e Avaliação do Problema de Otimização da Multiplicação de                        Cadeias de MatrizesEduardo de Luce...
 ferramentas e LPs a serem utilizadas.       Para tal, será apresentado o problema da Multiplicação de Cadeias de Matrize...
Figura 1 – Ilustração do fenômeno da localidade espacial.4. Análise e Detalhamento de Possíveis Soluções para o Problema d...
Por exemplo, para multiplicar uma cadeia de matrizes contendo três matrizesexistem duas parentizações possíveis. A Tabela ...
da Tabela 1, caso contrário, devem ser invertidas as linhas 1 e 2 da Tabela 1. Com essaverificação, o algoritmo sempre per...
alcançada com a divisão da cadeia. Para alcançarmos tanto a parentização ótima e aindaexplorar a capacidade máxima do proc...
b) Utilizando técnicas de PD, maximizando o cache miss;  c) Utilizando técnicas de PD, minimizando o cache miss;  d) Utili...
5. ConclusãoO objetivo do presente trabalho foi mostrar a importância de dominar técnicasrelacionadas a projeto de algorit...
Upcoming SlideShare
Loading in...5
×

Estudo e Avaliação do Problema de Otimização da Multiplicação de Cadeias de Matrizes

1,489

Published on

Abstract. Operations of matrix multiplications are widely used in scientific applications, and commonly have huge dimensions. Another problem derived of the first it’s the matrix-chain multiplications, which also has scientific applicability. Thus, efficient algorithms for matrix multiplications (or matrix-chains) are extremely useful, as also are new approaches or even distributed versions of already known algorithms. The present work aims at analyzing some approaches for the solution of the matrix-chain multiplications problem, implement it and measure their runtime to analyse the efficacy of the same.

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,489
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
20
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Estudo e Avaliação do Problema de Otimização da Multiplicação de Cadeias de Matrizes

  1. 1. Estudo e Avaliação do Problema de Otimização da Multiplicação de Cadeias de MatrizesEduardo de Lucena Falcão, Alisson Vasconcelos Brito, Alexandre Nóbrega Duarte Departamento de Informática – Universidade Federal da Paraíba (UFPB) {eduardolfalcao, alisson.brito, alexandrend}@gmail.com Abstract. Operations of matrix multiplications are widely used in scientific applications, and commonly have huge dimensions. Another problem derived of the first it’s the matrix-chain multiplications, which also has scientific applicability. Thus, efficient algorithms for matrix multiplications (or matrix- chains) are extremely useful, as also are new approaches or even distributed versions of already known algorithms. The present work aims at analyzing some approaches for the solution of the matrix-chain multiplications problem, implement it and measure their runtime to analyse the efficacy of the same.1. IntroduçãoDesde 1946, com a criação do primeiro computador eletrônico para fins genéricos (oENIAC), pode-se perceber a rápida evolução dos processadores ao longo de décadas[Koomey et al 2009]. A principal razão para tal é a evolução tecnológica que permitecada vez mais a construção de transistores sempre menores e mais baratos, de tal modoque mais ou menos a cada dois anos seu número dobrasse nos processadores, seguindouma tendência conhecida como Lei de Moore [Schaller 1997]. A rápida evolução dos processadores já é um fator que constantemente temtornado a execução de programas mais eficiente. Contudo, o aumento da velocidade dosprocessadores é apenas um dos fatores que podem elevar o desempenho de umprograma e, além disto, é limitado por outros fatores que têm influência direta nestamelhoria, dentre eles, a memória [Alted 2010]. De nada adianta ter processadores supervelozes, se a memória não é rápida o suficiente para fornecê-los dados paraprocessamento sem que eles fiquem ociosos. Deste modo, foi preciso adotar uma novaestratégia para diminuir o tempo de espera do processador: a memória cache. A memória cache é um tipo bastante rápido de memória que serve paraarmazenar os dados mais frequentemente usados pelo processador, evitando na maioriadas vezes que ele tenha que recorrer à “lenta” memória RAM (Random AccessMemory). É interessante perceber o funcionamento da memória cache com o objetivode usá-las da maneira mais eficiente possível, e.g. tentar minimizar o cache miss. Além de aspectos de hardware como frequência do processador e tamanho damemória, é importante utilizar as estruturas de dados e técnicas de algoritmos que maisse adéquam ao estilo de problema a ser resolvido. Adicionalmente, podemos perceberque as escolhas de ferramentas, Linguagens de Programação (LP), e APIs (ApplicationProgramer Interface), também podem ter certo impacto no desempenho da solução. O objetivo do presente trabalho é tornar evidentes os vários fatores que podeminfluenciar no desempenho de um programa:  utilizar a memória cache de maneira inteligente;  estruturas de dados e técnicas de programação mais adequados ao problema;
  2. 2.  ferramentas e LPs a serem utilizadas. Para tal, será apresentado o problema da Multiplicação de Cadeias de Matrizesexplicado no tópico abaixo, avaliando seu tempo de execução quando projetado dediferentes modos.2. O Problema da Multiplicação de Cadeias de MatrizesNo problema da multiplicação de cadeias de matrizes, recebe-se como entrada umacadeia de n matrizes, e retorna-se o produto delas. É fácil perceber,que por motivos da lógica da multiplicação de matrizes que a matriz deve ter númerode linhas igual ao número de colunas da matriz . O problema em sua essência é trivial, pois se multiplicarmos sequencialmente asn matrizes obteremos facilmente o resultado esperado. O maior desafio que reside nesteproblema é otimizar o desempenho do programa que o resolve. Para tal, podemosexplorar técnicas de programação aplicadas ao problema específico, além de buscarsempre explorar o processamento máximo do computador de maneira inteligente.3. O Problema do Cache Miss O cache miss acontece quando o processador necessita de um dado, e este nãoestá na memória cache. Tal fato obriga o processador a buscar um bloco de dados –constituído por um número fixo de palavras - diretamente na memória RAM, trazendo-os para a memória cache e em seguida fornecendo a palavra requerida ao processador. Em razão do fenômeno da localidade espacial, quando um bloco de dados étrazido para a memória cache para satisfazer uma dada referência à memória, é provávelque futuras referências sejam feitas para outras palavras desse bloco (Figura 1)[Stallings 2010]. Sendo assim, é fácil perceber que quando acontece vários cache missna execução de um programa, seu desempenho tenderá a cair. Os programadores podemutilizar a propriedade da localidade espacial dentre outras relacionadas aofuncionamento da memória cache no intuito de minimizar os cache miss e tornar aexecução dos programas mais rápidos. Um exemplo simples que comprova tal fato é o problema da soma de todos oselementos de uma matriz. Se para somar todos os elementos de uma matriz o algoritmopercorrer as colunas ao invés das linhas, haverá maior probabilidade de ocorrer o cachemiss. Para comprovar este fato, foi implementado um programa simples na LP Java, quemede o tempo de execução das duas formas de se percorrer uma matriz quadrada detamanho 10000. Ao percorrer as colunas o programa executou em 2886 milissegundos,e ao percorrer as linhas o programa executou em 53 milissegundos. Podemos perceberque quando minimizamos o cache miss tivemos um speedup superior a 50 vezes. A Figura 1 ilustra o fenômeno da localidade espacial ocorrendo no problema dasoma dos elementos de uma matriz. Quando o primeiro elemento da matriz ( ) ébuscado para efetuar a soma, o processador buscará um bloco de dados sequencial (umalinha do array, ou parte dela) para a memória cache. Se forem percorridas as linhas damatriz, provavelmente os próximos elementos a serem somados (representados atravésda cor verde e amarela na Figura 1) estarão na memória cache, o que ocasiona um cachehit, tornando o acesso ao dado mais rápido. Se forem percorridas as colunas, há maiorprobabilidade de que os próximos elementos a serem somados (vermelho) não estejamna memória cache, ocorrendo um cache miss.
  3. 3. Figura 1 – Ilustração do fenômeno da localidade espacial.4. Análise e Detalhamento de Possíveis Soluções para o Problema de Multiplicação de Cadeias de MatrizesNeste tópico serão descritas algumas abordagens possíveis para a solução desteproblema, que em alguns casos são complementares e em outros são antagônicas.4.1. Abordagem SequencialNa abordagem sequencial multiplicam-se sequencialmente as n matrizes para obter seuproduto. Por exemplo, para uma cadeia com quatro matrizes a ordem de multiplicaçãoseria a seguinte: . O código da Tabela 1 recebe duas matrizes A e Bcomo entrada, e retorna a matriz C como resultado da multiplicação entre A e B. Apartir da Tabela 1 pode-se perceber que a complexidade para realizar a multiplicaçãodessas duas matrizes é , sendo n relativo ao tamanho das matrizes (linhas ecolunas). Logo, para t matrizes tem-se que a complexidade é . Tabela 1 – Código para multiplicação de duas matrizes. 1 for(int i=0; i<a.length ;i++){ 2 for(int j=0; j<b[0].length ;j++){ 3 c[i][j] = 0; 4 for(int k=0; k<a[0].length ;k++) 5 c[i][j] += a[i][k] * b[k][j]; 6 } 7 }4.2. Abordagem com Programação Dinâmica Analisando mais cuidadosamente o código da Tabela 1, pode-se perceber que onúmero de multiplicações escalares relacionadas à multiplicação de duas matrizesrespeita o cálculo exibido na Figura 2. O referente à multiplicação pode serdescrito de maneira mais detalhada por . Sendo assim, pode-se observar que a ordem com que as matrizes sãomultiplicadas pode tornar o programa mais eficiente, ou seja, reduzir o número demultiplicações. Figura 2 – Quantidade de multiplicações escalares para a multiplicação de duas matrizes. Adaptado de [Cormen et al 2002].
  4. 4. Por exemplo, para multiplicar uma cadeia de matrizes contendo três matrizesexistem duas parentizações possíveis. A Tabela 2 exibe as possíveis parentizações paraa seguinte cadeia com três matrizes: . Tabela 2 – Possíveis ordens de multiplicação para uma cadeira com três matrizes. 1 2 A partir do cálculo fornecido pela Figura 2, é possível verificar que a ordem demultiplicação das matrizes da linha 1 da Tabela 2 realiza 75000 multiplicaçõesescalares, ao passo que a ordem da linha 2 resulta em apenas 7500. Deste modo, Pode-se perceber que para a multiplicação da cadeia já citada, apenas a ordem demultiplicação das mesmas pode gerar um speedup de 10 vezes. É interessante perceberque para o exemplo anterior a abordagem sequencial (4.1) é a mais rápida. Mas, deveser ressaltado que isso foi apenas uma coincidência, e que a probabilidade daabordagem sequencial ser a mais rápida torna-se bastante remota quando o número dematrizes da cadeia aumenta, o que proporciona um ganho expressivo quando se utiliza aabordagem com a parentização otimizada. Mas como proceder para encontrar a parentização otimizada? Através da forçabruta, o número de soluções seria exponencial em n ( ), sendo n o número demultiplicações, tornando essa verificação inviável [Cormen et al 2002]. Uma alternativaviável para este problema é a utilização da estratégia de Programação Dinâmica. A Programação Dinâmica (PD) geralmente é aplicada a problemas deotimização, ou seja, problemas que possuem várias soluções, mas deseja-se encontraruma solução ótima, como é o caso do corrente problema. Para aplicar a PD ao problemada multiplicação de cadeias de matrizes são necessárias quatro etapas: caracterizar aestrutura de uma solução ótima, que nesse caso é a estrutura de uma colocação ótimados parênteses; definir recursivamente o valor de uma solução ótima para o problema;calcular o valor de uma parentização ótima; construir a solução ótima a partir dasinformações coletadas. Mais detalhes sobre descrição e implementação desse problemaatravés da PD são fornecidos em [Cormen et al 2002].4.3. Abordagem com Minimização de Cache MissO tópico 3 explicou alguns detalhes quanto a ocorrência de cache miss. Com relação aoproblema de multiplicação de matrizes, deve-se primeiramente ressaltar que a próprianatureza de seu algoritmo o faz mais suscetível à ocorrência de cache miss. Pois ésabido que para multiplicar duas matrizes, deve-se percorrer a linha da primeira e acoluna da segunda, e quando se percorre a coluna de uma matriz a probabilidade deocorrência do cache miss aumenta (vide Tópico 3). A Tabela 1 exibe o código referente a um algoritmo tradicional paramultiplicação de matrizes. Nesse código o algoritmo sempre preencherá linha por linhada matriz resultante. Este comportamento do algoritmo requer que o processador faça amultiplicação de uma linha da primeira matriz com todas as colunas da segunda matriz. Baseado no funcionamento do algoritmo, observou-se que é possível minimizara ocorrência do cache miss invertendo as linhas 1 e 2 da Tabela 1 (quando pertinentes),com o objetivo de que o programa reutilize dados previamente armazenados namemória cache. Pensou-se o seguinte (Tabela 3): se a quantidade de linhas da primeiramatriz é maior que a quantidade de linhas da segunda matriz, deve-se manter o código
  5. 5. da Tabela 1, caso contrário, devem ser invertidas as linhas 1 e 2 da Tabela 1. Com essaverificação, o algoritmo sempre percorrerá a “maior linha possível”, o que minimiza ocache miss. Tabela 3 – Código proposto para minimização do cache miss. if(a.length > b.length) <Código da Tabela 1> else <Código da Tabela 1 com linhas 1 e 2 invertidas> Outra maneira de se reduzir o cache miss para o problema da multiplicação dematrizes seria multiplicar a primeira matriz pela matriz transposta da segunda. Pode-seperceber que para isto seria necessário mudar o código relativo à multiplicação dasmatrizes: ao invés de multiplicar linhas da primeira matriz por colunas da segunda,multiplicar-se-iam linhas da primeira matriz por linhas da segunda (Figura 3), o queimplicaria numa redução significativa do cache miss. Para evitar um custo adicionalpara o cálculo da transposta da segunda matriz, poderia apenas ser alterado o método decriação das mesmas para já criá-las como sendo suas próprias transpostas. A Figura 3 exemplifica a multiplicação tradicional com uma matrizconvencional, e a multiplicação proposta com a matriz transposta. As linhas coloridasrepresentam os cálculos relativos à primeira linha da matriz resultante:  Linhas vermelhas: multiplicar linha 1 da primeira matriz com colunas 1, 2, ..., n da segunda matriz;  Linhas azuis: multiplicar linha 1 da primeira matriz com linhas 1, 2, ..., n da segunda matriz. Figura 3 – Multiplicação convencional, e multiplicação com matrizes transpostas .4.4. Abordagem Distribuída com ThreadsA abordagem distribuída utilizando threads visa explorar a potencialidade máxima dosprocessadores atuais, que geralmente possuem mais de um núcleo físico e/ou lógico.Contudo, será explicado adiante o porquê da abordagem distribuída com threadsutilizada no presente trabalho não caracterizar uma solução ótima, apesar de explorar acapacidade máxima do hardware. A estratégia utilizada para esta abordagem divide a cadeiapelo número de threads a serem criadas. Desse modo, cada thread fica encarregada derealizar a multiplicação de uma sub-cadeia, e ao final, quando todas terminarem suaexecução, a thread principal realizará a multiplicação das matrizes resultantes. Comoexemplo, considere uma cadeia com doze matrizes ( ) utilizando aabordagem distribuída com duas threads. Esta cadeia seria quebrada ao meio em duassub-cadeias e , e depois passaria pelo processo dese encontrar a parentização ótima através da estratégia de PD. Porém, é fácil perceberque a parentização ótima para a cadeia muito dificilmente será
  6. 6. alcançada com a divisão da cadeia. Para alcançarmos tanto a parentização ótima e aindaexplorar a capacidade máxima do processador outra estratégia deve ser utilizada, comopor exemplo, a abordagem distribuída utilizando a biblioteca OpenMP.4.5. Abordagem Distribuída com OpenMPA abordagem distribuída utilizando a biblioteca OpenMP (Open Multi-Processing) nãodivide a cadeia de matrizes em sub-cadeias, e portanto, mantém a parentizaçãootimizada encontrada através da abordagem por PD. Ao invés disso, utilizam-sediretivas em trechos de código que são interpretadas pelo compilador, e que ao executaro programa, ativam as threads dos processadores de acordo com as mesmas. Portanto, otrecho de código que se pretende distribuir deve ser minuciosamente estudado para quenenhuma violação lógica ou física seja cometida. Para o problema da multiplicação de matrizes, foi percebido que os elementos damatriz resultante não possuem interdependências, o que possibilita a paralelização dessetrecho de código, mais especificamente do loop for da linha 1 na Tabela 1. Deste modo,o código ficaria como apresentado abaixo na Tabela 4. Tabela 4 – Paralelizando com a biblioteca OpenMP. #pragma omp parallel for <Código da Tabela 1> A biblioteca OpenMP usa o modelo de paralelismo fork-and-join, que ramifica athread principal em threads paralelas, e quando estas terminam de executar, a threadprincipal reassume o controle do programa [Chandra et al 2001]. Existem diversasdiretivas da biblioteca OpenMP que permitem os programadores tornarem seusprogramas distribuídos. A diretiva que foi utilizada na Tabela 4 atua de forma simples,ela subdivide a quantidade total de iterações no loop for pelo número de threads a seremutilizadas, e cada thread executará uma parte das iterações que antes eram executadaspor apenas uma thread. No problema da multiplicação de matrizes, se a matrizresultante tiver 10 linhas, e for especificado que o processador deve trabalhar com duasthreads, a primeira computará o produto das 5 primeiras linhas da matriz resultante, e asegunda computará as linhas restantes (Figura 4). Figura 4 – Multiplicação com abordagem não-distribuída e distribuída.5. ResultadosPara avaliar algumas das abordagens supracitadas pensou-se em realizar cincoexperimentos, aliando diferentes algoritmos e técnicas de programação. As cincoestratégias são citadas abaixo, visando a cada novo experimento implementadomelhorar o desempenho do programa.1. Linguagem de Programação Java: a) Abordagem sequencial, maximizando o cache miss;
  7. 7. b) Utilizando técnicas de PD, maximizando o cache miss; c) Utilizando técnicas de PD, minimizando o cache miss; d) Utilizando técnicas de PD, minimizando o cache miss, além de tornar a lógica do algoritmo distribuída: i. Em 2 Threads; ii. Em 4 Threads; “Maximizar o cache miss” tem o objetivo de tornar mais evidente a ocorrênciado mesmo, e prover uma noção de tempo desperdiçado quando o mesmo ocorre. Paratal, as linhas 1 e 2 da Tabela 1 devem ser invertidas com a lógica inversa da Tabela 3.Para minimizar o cache miss foi utilizada o código presente na Tabela 3. E para tornar alógica do algoritmo distribuído foi utilizada a abordagem explanada no tópico 4.4. Parafins de padronização as matrizes foram preenchidas com 1’s. Para tais experimentos, foi utilizado um notebook Dell Vostro 3450, SistemaOperacional Windows 7 Professional Service Pack 1 de 64 Bits, 4 GB de memóriaRAM, processador Intel® Core™ i5-250M de 2.5 GHz. A cadeia de matrizes escolhida para os experimentos foi a seguinte:<7000,50,30,5000,32,40,5000,80,20,4000,20,10,1000,50>, o que equivale às matrizes . Pode-se perceber que todas as matrizes dacadeia possuem o número de linhas muito superior ao número de colunas, ou justamenteo inverso, pois a ocorrência de cache miss torna-se mais acentuada nesses casos. A Figura 5 exibe o gráfico com o resultado dos experimentos propostos. Alegenda na direita corresponde aos experimentos descritos anteriormente. 36,7 1.a 40 1.b 20 10,9 1.c 6,2 6,6 6,4 1.d 0 Figura 5 – Resultados do experimento na LP Java. Pode-se observar que a diferença de desempenho da abordagem que usa PD paraa sequencial é deveras significante (25.8 segundos), um fato esperado e descrito nostópicos 4.1 e 4.2 do tópico. Analisando o resultado dos experimentos 1.b e 1.c, pode-senotar que quando é utilizada uma estratégia de minimização de cache miss (descrita notópico 4.3) para o problema, obteve-se 4.7 segundos de speedup, que representa umaevolução de quase 50%. É importante ressaltar que quando o tamanho da cadeiaaumenta, essa disparidade também tende a aumentar. Por último, ao analisar a estratégiadistribuída (descrita no tópico 4.4), pode-se perceber que tanto a 1.d quanto 1.e,utilizando 2 e 4 threads respectivamente, apresentaram perda de desempenho. No tópico4.4, já se havia cogitado a possibilidade dessa ocorrência devido à perda de parentizaçãoótima. Porém, é de se esperar que esta abordagem apresente ganho de desempenho paradeterminadas cadeias de matrizes, principalmente quando o número de matrizes cresce.
  8. 8. 5. ConclusãoO objetivo do presente trabalho foi mostrar a importância de dominar técnicasrelacionadas a projeto de algoritmos, e também conceitos de arquitetura decomputadores para obter melhor desempenho do software e hardware. Ao utilizar atécnica de PD aliada à minimização de cache miss, obteve-se um speedup de 6x emrelação ao desempenho da solução mais simples (sequencial). É interessante perceberque todos os algoritmos estão na mesma ordem de complexidade de tempo ( ), emesmo assim foram obtidos ganhos de desempenho. Destes resultados, pode-se colher como aprendizado, que ao receber umproblema é necessário estudá-lo, visualizá-lo de diferentes perspectivas para adotar aestratégia de solução mais eficiente. Para tal, devem ser analisados os algoritmospertinentes, ferramentas (APIs, bibliotecas, etc.) e LPs a serem utilizadas, além deconceitos sobre funcionamento de software/hardware, de sistemas operacionais e daarquitetura do computador de uma forma generalizada.7. Trabalhos FuturosComo possibilidades para trabalhos futuros, pode ser considerada a implementação dasabordagens já citadas na LP C++, uma vez que geralmente os programas escritos nessaLP tendem a ter melhor desempenho que em Java. Além disso, a abordagem descrita notópico 4.5 parece ser a mais eficiente. O fato de aproveitar o desempenho da LP C++,realizando a distribuição do algoritmo em quantas threads desejar, mantendo aparentização ótima alcançada pela PD, e minimizar a ocorrência de cache miss com aabordagem da matriz transposta, aparenta ser a melhor solução analisada no presentetrabalho. Outra tarefa interessante seria implementar os algoritmos para multiplicaçãode matrizes desenvolvidos por Strassen , que possui complexidade de , ou odesenvolvido por Coppersmith e Winograd com ordem de complexidade ,aliando à alguma abordagem de minimização de cache miss para comparação dosresultados [Robinson 2005].ReferênciasKoomey, J. G., Berard, S., Sanchez, M., Wong, H. (2009) “Assessing Trends in the Electrical Efficiency”. Final report to Microsoft Corporation and Intel Corporation.Schaller, R. R. “Moores law: past, present and future”. (1997) IEEE Spectrum, Vol 34, pp. 52-59.Alted, F. “Why Modern CPUs are Starving and what can be done about it”. (2010) Computing in Science & Engineering, pp. 68–71.Stallings, W. “Arquitetura e Organização de Computadores”. (2010) Editora Prentice Hall, pp. 122-144.Cormen, T. H., Leiserson, C. E., Rivest, R. L., Stein, C. “Algoritmos: Teoria e Prática”. (2002) Editora Campus, pp. 259-295.Chandra, R., Dagum, L., Kohr, D., Maydan, D., McDonald, J., Menon, R. “Parallel Programming in OpenMP”. (2001) Editora Morgan Kaufmann.Robinson, S. “Toward an Optimal Algorithm for Matrix Multiplication”. (2005) Society for Industrial and Applied Mathematics. Vol. 38, Nº 9.

×