Aplicação de técnicas para otimização serial em Fortran 90 Cleibson Aparecido de Almeida PPGMNE Programa de Pós Graduação em Métodos Numéricos em Engenharia Universidade Federal do Paraná (UFPR) CEP 81.531 980 Curitiba PR Brazil cleibson@ufpr.br Abstract. This document describes some of the techniques used to optimize programs written in Fortran. Among the various techniques used include the implementation of Lapack library for solving systems of linear equations, creating temporary variables in place of repetitive calculations, eliminating repetition loops, explicit declaration in small arithmetic operations and eliminate dependencies on the program flow. It used the Intel Fortran compiler and GNU Profiler for performance evaluation of the program. Resumo. Este documento descreve algumas das técnicas utilizadas para otimização de programas feitos em linguagem Fortran. Dentre as diversas técnicas utilizadas destacam se a implementação da biblioteca Lapack para resolver sistemas de equações lineares, criação de variáveis temporárias em substituição a cálculos repetitivos, eliminação de laços de repetição, declaração explícita em pequenas operações aritméticas e eliminação das dependências no fluxo do programa. É utilizado o compilador Intel Fortran e o GNU Profiler para avaliação de desempenho do programa. 1. Introdução Algumas vezes criamos programas sem nos atentar ao principal responsável pelo seu desempenho, o computador. A execução de instruções simultâneas e independentes permitem um melhor uso dos recursos oferecidos pelo nosso computador. Conhecimento da arquitetura onde acontecerá a execução do programa nos permite direcionar o melhor tipo de otimização em nosso código e algumas técnicas são indicadas para qualquer um dos casos. Computadores com multiprocessadores são cada vez mais comum e cabe ao programador otimizar adequadamente suas rotinas para serem processadas de forma eficiente. Além das técnicas onde há trabalho humano de quem programa, existem também técnicas por referenciamento das bibliotecas de alta performance e também técnicas que podem ser incluídas nos argumentos de compilação. No item 2 são apresentadas as ferramentas para otimização e avaliação de desempenho, no item 3 são descritas as técnicas utilizadas neste trabalho e no item 4 são feitas as considerações sobre os resultados obtidos.
2. Ferramentas utilizadas Em computação de alto desempenho existe uma notável preocupação com a compilação e medição do desempenho de programas. O desempenho na execução de um programa pode variar conforme o compilador utilizado e também as opções de compilação utilizadas. Mais importante do que isso é saber antecipadamente a estrutura de hardware onde será executado o programa. Conhecimento sobre essa estrutura é fundamental, pois há diferenças na otimização de programas que podem ser executados em um computador com vários ou um único processador. Neste trabalho é utilizado a seguinte configuração de hardware/software: Notebook Kennex U50SA, intel Core 2 Duo T5750, 2gb memória DDR2 667, vídeo ATI Radeon HD2400 256mb. Sistema Operacional OpenSuse 11.1, ambientex Gnome Compilador Intel Fortran 11.1[3] Ferramenta para medição de desempenho GNU Profiler Editor de códigos Gedit e interface de compilação bash Programa bizep24a.f90 e entrada de dados nosymm2k.txt 3. Otimização de códigos Otimizar códigos trata se de uma tarefa trabalhosa, complexa e intrigante. Trabalhosa porque requer um grande esforço mental e físico para atingir um bom padrão de desempenho. Complexa porque requer do programador algum grau de conhecimento teórico referente ao problema tratado em seu programa e grande habilidade com ferramentas, linguagens e abstração computacional. Intrigante porque nem todas as técnicas descritas na literatura podem ser a solução para melhorar o desempenho de seu programa, cabe ao programador implementar novas técnicas e avaliar o ganho de desempenho. 3.1. Biblioteca de alto desempenho (Lapack) Lapack é uma biblioteca escrita em Fortran cuja finalidade é resolver sistemas de equações lineares, problemas de métodos dos mínimos quadrados e autovalores/autovetores. São oferecidos pelo Lapack funções para soluções reais e complexas bem como precisão simples e dupla. Ao compilar 1 e executar 2 pela primeira vez o programa bizep24a.f90 podemos perceber que o tempo de execução é de 11m21.195s. Ao analizar o programa com o GNU Profiler 3 verificamos que a função SLNPD gasta 99.62% deste tempo. 1 ifort O3 pg o bizep24a bizep24a.f90 2 time./01bizep24a nosymm2k.txt nosaida2k.txt 3 gprof p bizep24a gmon.out
Figura 1. Desempenho inicial do programa Como esta função resolve um sistema de equações lineares podemos substituí la pela função equivalente oferecida pela biblioteca Lapack, neste caso SGESV. Temos então a seguinte troca no código 4 : será trocada por call SLNPD(NN2,IFAIL,IWR,A,XM) call SGESV(NN2,1,A,NMAX2,IPIV,XM,NMAX2,INFO) Após esta troca temos um ganho muito expressivo no desempenho do programa, ou seja, o tempo de execução cai para 30.897s. Também notamos que o problema deixa de ser o calculo matricial e passa a ser outras funções do programa. (figura 2) Figura 2. Desempenho do programa com Lapack Apenas com esta modificação o programa foi executado 20 vezes mais rápido do que inicialmente. O próximo passo é a otimização das funções FUNC e MATRX. 3.2. Otimizações aritméticas Apesar da simplicidade este é o erro mais comum quando estamos programando. Sem pensar no desempenho procuramos pela facilidade e comodidade inserindo dentro do nosso programa uma cascata de itens que poderiam ser otimizados. No programa abordado neste trabalho foram consideradas as seguintes modificações: Troca de exponenciais por multiplicações duplas 4 Também é necessário incluir o argumento llapack na compilação
Troca de divisões por multiplicações Grupos de operações repetidas foram fixadas em variáveis Pequenos cálculos foram trocados pelo seu valor já calculado Estas técnicas foram utilizadas dentro das funções FUNC, FENC e MATRX e o tempo de execução do programa baixou para 27.355s. O profiling desta técnica pode ser visto na figura 3. Figura 3. Desempenho do programa após otimizações aritméticas Podemos observar que houve inversão no tempo de execução entre as funções FUNC e MATRX. Isso deve se ao fato de que FUNC teve muito mais opções de melhorias aritméticas do que MATRX. 3.3. Desenrolamento de laços de repetição (loops) Desenrolar loops pode até ser uma tarefa fácil, porém requer atenção e exige muito trabalho. Como as funções FUNC e MATRX são, por enquanto, as que demandam maior parte do tempo de execução do programa elas continuam sendo alvo para a otimização do programa. Com exceção de um loop pertencente a FUNC todos os demais foram desenrolados. Este loop não foi desenrolado por causa de sua extensa abrangência e isso dispenderia muito tempo de trabalho. A função MATRX é mais complicada para fazer desenrolamentos de loops por causa de valores altos no comprimento e itens que não podem se comportar de forma independente. De forma global cerca de 90% dos loops dessas funções foram desenrolados e o tempo de execução do programa baixou aproximadamente 1 segundo após a medição com as otimizações aritméticas (26.698s). A figura 4 mostra o tempo gasto por estas funções após as otimizações.
Figura 4. Desempenho do programa após loop unrolling 3.4. Permutação nos índices de matrizes Esta técnica possibilita a inversão(reordenação) dos índices das matrizes quando não é possível desenrolar um loop e também quando realiza se operações entre matrizes. Neste trabalho foi aplicada essa inversão no primeiro loop da função MATRX e os resultados não foram satisfatórios. Talvez seja pelo fato desse loop ser apenas um construtor para uma matriz nula. 4. Considerações finais A linguagem Fortran mostrou se adequada para criação de programas otimizados já que possuí sintaxe simples, é robusta para fazer grandes cálculos e está terminantemente ligada aos recursos necessários para conseguirmos um bom desempenho em nossos programas. No programa bizep24a.f90 conseguimos boa otimização partindo de 11m21.195s para o ínfimo tempo de 26.698s. Esse desempenho foi conseguido em sua grande parte pela troca do solver 5 e pouco desempenho foi conseguido com as demais técnicas. Porém vale ressaltar que este pequeno desempenho atingido com otimizações aritméticas e desenrolamento de loops podem ter uma maior significância quando trabalharmos com problemas em grande escala. 5. Links bizep24a.f90 (versão original) http://www.cleibsonalmeida.blog.br/website/downloads/tc746/bizep24aori.f90 bizep24a.f90 (versão otimizada) http://www.cleibsonalmeida.blog.br/website/downloads/tc746/bizep24afin.f90 bizep24a.f90 (versão otimizada com comentários) http://www.cleibsonalmeida.blog.br/website/downloads/tc746/bizep24acom.f90 nosymm2k.txt (arquivo de entrada) http://www.cleibsonalmeida.blog.br/website/downloads/tc746/nosymm2k.txt 5 Solver: Função que resolve sistema de equações lineares