Computadores de Programação (MAB353) Aula 19: Visão geral sobre otimização de programas 06 de julho de 2010
1 2 3
Características esperadas dos programas O primeiro objetivo ao escrever programas de computador deve ser fazê-lo funcionar corretamente em todas as possíveis condições Os códigos devem ser concisos (fazer sentido) e legíveis (simples de entender para futuras revisões) Há ocasiões em que fazer o programa executar mais rápido é também importante (ex., processamento de frames de vídeo ou pacotes de rede em aplicação de tempo real) simplicidade é complexidade resolvida (equipe Apple)
Etapas para a implementação de programas 1 Selecionar os algoritmos e estruturas de dados apropriados 2 Escrever código fonte que o compilador pode eficientemente otimizar 3 Dividir a tarefa em porções que podem ser computadas em paralelo (em máquinas multicores)
Escrever código que o compilador pode otimizar Para isso é importante conhecer as capacidades e limitações de otimização dos compiladores Algumas LPs são mais fáceis de otimizar que outras Pequenas variações no código fonte podem fazer grande diferença em quão bem o compilador pode otimizá-lo!
Escrever código que o compilador pode otimizar Idealmente, um compilador deveria ser capaz de pegar qualquer código que escrevemos e gerar o programa em linguagem de máquina mais eficiente posível Mas mesmo os compiladores mais eficientes não são capazes de lidar com aspectos do comportamento do programa que dependem do ambiente de execução Nesse caso, cabe ao programador auxiliar o compilador alterando o modo de escrever o código fonte!
Exemplo de limitação para possível otimização Ponteiros em C x=1000; y=3000; *q = y; *p = x; t1 = *q; O que podemos dizer sobre a dependência do valor final de t1 em relação às demais variáveis?
Exemplo de limitação para possível otimização Ponteiros em C O valor computado em t1 depende se os ponteiros p e q apontam para a mesma posição de memória (aliases) Se o compilador não pode determinar se os dois ponteiros são aliases, ele deve assumir que os dois casos são possíveis limitando as possibilidades de otimização
Exemplo de limitação para possível otimização Efeitos colaterais das chamadas de funções int cont = 0; int f() {return cont++; } int func1() { return f() + f() + f() + f(); } possível otimizaç~ao de func1: int func2() { return 4 * f(); }
Exemplo de limitação para possível otimização Efeitos colaterais das chamadas de funções A função f () tem o efeito colateral de modificar uma parte do estado global do programa (variável global cont) Mexendo no número de vezes que a função é chamada, o comportamento do programa é modificado Os compiladores em geral não tentam determinar se a função tem efeito colateral, e então consideram o pior caso e deixam a função da chamada intacta
Exemplo de limitação para possível otimização Possível alteração para func1 (por ex., usando o mecanismo de substituição inline) int func1in() { int t = cont++; //+0 t += cont++; //+1 t += cont++; //+2 t += cont++; //+3 return t; }
Exemplo de limitação para possível otimização Reproduz func1 para uma definição particular de f int func1ot() { int t = 4 * cont + 6; cont = cont + 4; return t; }
Trade-off entre simplicidade e desempenho Em geral há um trade-off entre quão fácil é implementar e manter um programa e quão rápido ele executa Ex., código que é executado repetidamente em ambiente crítico para desempenho requer otimizações
O primeiro passo é eliminar trabalho desnecessário (chamadas de funções, testes condicionais e referências à memória desnecessárias) essas otimizações não dependem da arquitetura da máquina alvo! Para otimizar o desempenho do programa, o compilador e o programador precisam conhecer o modelo da arquitetura da máquina alvo (como as instruções são processadas) Ex., decidir usar uma instrução de multiplicação ou combinações de shifts e adds
Computadores modernos usam técnica de pipeline (executar instruções em paralelo e possivelmente em ordem distinta que aparece no programa) programadores devem entender como esses processadores funcionam para organizarem seu programa de forma que permita máxima velocidade! um passo básico é reduzir as dependências de dados entre diferentes partes do programa
Abordagem para otimização de código Idéia básica: Tornar a otimização do código um processo linear com a aplicação de uma série de transformações do código, seguindo uma determinada ordem A melhoria do desempenho pode depender de vários detalhes do projeto do processador (muitas vezes não documentadados) Por isso, variações ou combinações de técnicas podem ter impactos distintos no desempenho final (requer experimentação/simulação de diferentes tentativas!)
Abordagem para otimização de código Estudo da representação em linguagem de montagem O estudo da representação em linguagem de montagem de um programa é um dos meios mais efetivos de compreender a operação do compilador e de como o código irá executar Podemos estimar o tempo para execução de um loop identificando o caminho crítico e as dependências de dados que se cria...depois voltar atrás e modificar o código fonte para tentar forçar o compilador a gerar código mais eficiente
Abordagem para otimização de código Resumo: Modificar iterativamente o código e analizar seu desempenho através de medições ou avaliando o código em linguagem de montagem gerado Comparada à alternativa de escrever código em linguagem de montagem, essa abordagem tem a vantagem que o código resultante ainda irá executar em outras máquinas (embora talvez não com a mesma eficiência)
Envolve identificar uma computação que é executada várias vezes mas que o resultado da computação não irá mudar Podemos então mover a computação para uma seção anterior do código e executá-la uma única vez (o compilador nem sempre é capaz de fazer isso pois deve levar em conta a possibilidade de efeitos colaterais)
Exemplo de otimização com eliminação de loops ineficientes
Impacto da função strlen()
Comparação do desempenho das duas implementações Figura: Prof. Silvana Fonte: Rossetto referência bibliográfica.
Um sistema embutido é uma combinação de hardware e software (e talvez outras partes mecânicas e elétricas) projetado para uma função específica (ex., forno microondas) A diferença para um PC (computador de propósito geral), é que o PC é projetado para executar diferentes aplicações
Normalmente, um sistema embutido é um componente dentro de um sistema maior Ex., Carros podem ter vários sistemas embutidos (controle de emissão, controle de travas, painel, etc.) Os sistemas embutidos podem ser conectados em rede (mas não é um requisito) Quando um sistema embutido é bem projetado, a existência do processador e do software deve ficar totalmente transparente para o usuário final
Histórico e futuro de sistemas embutidos Início com o microcontrolador Intel4004, projetado por encomenda para desenvolvimento de calculadoras A partir dos anos 80, crescimento expansivo, os sistemas embutidos passaram a fazer parte do nosso dia-a-dia ex., PDAs, controles remotos, TVs, câmeras digitais, celulares, fax, etc Tendência: cada vez mais aparecerem objetos novos ou processamento incorporado em objetos comuns do dia-a-dia
Disciplina eletiva Sistemas Embutidos I (MAB621) REQUISITOS: MAB355, MAB366, MAB240 EMENTA: Aplicações de sistemas embutidos e mercado de trabalho; revisão de aritmética inteira e de ponto fixo; conceitos básicos de eletricidade e eletrônica; programação de microcontroladores 8051 e PIC em C e Assembly; conceitos de E/S por interrupção, polling e DMA; uso de máquinas de estado finito (FSMs) na solução de problemas de programação; exercícios e trabalhos utilizando teclados, displays de cristal ĺıquido, leitores de código de barras, codificação e decodificação de infravermelho, comunicação de dados em série; transmissão de dados utilizando telefones celulares; Java para sistemas embutidos.
1 Computer Systems: A Programmer s Perspective, Randal E. Bryant and David R. O Hallaron, 2ed, Prentice Hall, 2010