Você está na página 1de 10

06/05/20

DICAS SOBRE OTIMIZAÇÃO DE


CÓDIGO

JCMetrolho,

NOTA PRÉVIA

• Estes slides são adaptação e/ou tradução de informação disponibilizada pelos autores
do seguinte livro:
• Computers as Components – Principles of Embedded Computing System Design, 4
edição, Marilyn Wolf, ISBN: 9780128053874, Morgan Kaufmann, 2016,
• Estes apontamentos não dispensam a consulta do livro referido anteriormente,
que érecomendado aos alunos como complemento ao apresentado nas aulas.
• Além do anteriormente referido, são usadas ainda outras fontes (livros, artigos,
documentos web, etc.) que serão oportunamente citadas ou disponibilizados no
moodle.

1
06/05/20

ASSEMBLY E LINKING

HLL
HLL assembly
HLL compile assembly
assembly assemble

assembly
assembly
object

load executable link

ASSEMBLERS

• Principais tarefas:
• gerar binário para instruções simbólicas;
• traduzir labels em endereços;
• lidar com pseudo-ops (dados, etc.).

2
06/05/20

LINKING

• Combina vários módulos de objeto em um único módulo executável.


• Tarefas:
• colocar os módulos em ordem;
• resolver labels entre módulos.

SIMPLIFICAÇÃO DE EXPRESSÕES

• A simplificação de expressão é uma área útil para transformações independentes da


máquina. Podemos usar as leis da álgebra para simplificar expressões. Considere a
seguinte expressão: a * b + a * c
• Podemos usar a lei distributiva para reescrever a expressão como a * (b + c)
• Como a nova expressão possui apenas duas operações em vez de três para a forma
original, é quase certamente mais otimizada, porque é mais rápida e menor. Tais
transformações fazem algumas suposições amplas sobre o custo relativo das
operações. Em alguns casos, generalizações simples sobre o custo das operações
podem ser enganosas. Por exemplo, uma CPU com uma instrução de multiplicar e
acumular pode ter 4 bytes, capaz de fazer uma multiplicação e adição o mais barato
possível. No entanto, essas situações geralmente podem ser resolvidas na geração
de código.

3
06/05/20

SIMPLIFICAÇÃO DE EXPRESSÕES

• Constante:
• 8+1=9

• Algébrico:
• a * b + a * c = a * (b + c)
• Redução de strength:
• a * 2 = a << 1

ELIMINAÇÃO DE CÓDIGO INÚTIL

• O código que nunca será executado pode ser removido com segurança do
programa. O problema geral de identificar código que nunca será executado é
difícil, mas há alguns casos especiais importantes em que isso pode ser feito.

4
06/05/20

ELIMINAÇÃO DE CÓDIGO INÚTIL

• Código inútil: 0
#define DEBUG 0 0

if (DEBUG) dbg(p1); 1
• Pode ser eliminado pela análise do fluxo
de controlo, dobragem constante. dbg(p1);

INLINING DE PROCEDIMENTOS

• Outra transformação independente da máquina que requer um pouco mais de


avaliação é o inlining de procedimentos. Um procedimento inline não possui um
corpo de procedimento e uma linkagem de procedimento separados; em vez disso,
o corpo do procedimento é substituído pela chamada de procedimento
• A linguagem de programação C ++ fornece um construct próprio que informa ao
compilador para gerar código inline para uma função. Nesse caso, um procedimento
inline é gerado em formato expandido sempre que possível. No entanto, inlining
nem sempre é a melhor opção a fazer. Embora elimine as instruções de linkagem
do procedimento, quando um cache está presente, ter várias cópias do corpo da
função pode atrasar as buscas dessas instruções. Inlining também aumenta o
tamanho do código, e a memória pode ser preciosa.

10

5
06/05/20

INLINING DE PROCEDIMENTOS/FUNÇÕES

• Elimina a sobrecarga de linkagem do procedimento :

int foo(a,b,c) { return a + b - c;} (definição da função)

z = foo(w,x,y); (chamada da função)


!
z = w + x + y; (resultado do inlining)

11

TRANSFORMAÇÃO DE CICLOS

• Os ciclos são estruturas importantes do programa - embora sejam descritos de


maneira compacta no código fonte, eles costumam usar uma grande fração do
tempo de computação. Muitas técnicas foram projetadas para otimizar ciclos.

12

6
06/05/20

TRANSFORMAÇÃO DE CICLOS

• Objetivos:
• reduzir a sobrecarga do ciclo;
• aumentar as oportunidades de pipelining;
• melhorar o desempenho do sistema de memória.

13

UNROLLING DE CICLOS

• Reduz a sobrecarga do ciclo, permite algumas outras otimizações.


for (i=0; i<4; i++)
a[i] = b[i] * c[i];

!
for (i=0; i<2; i++) {
a[i*2] = b[i*2] * c[i*2];
a[i*2+1] = b[i*2+1] * c[i*2+1];
}

14

7
06/05/20

FUSÃO E DISTRIBUIÇÃO DE CICLOS

• Combina dois ciclos num:


for (i=0; i<N; i++) a[i] = b[i] * 5;
for (j=0; j<N; j++) w[j] = c[j] * d[j];
! for (i=0; i<N; i++) {
a[i] = b[i] * 5; w[i] = c[i] * d[i];
}

• A distribuição divide um ciclo em dois.


• Alterações de otimizações no corpo do ciclo.

15

OTIMIZAÇÃO

i=0; Xi=0;
= N*M

for (i=0; i<N*M; i++) N


i<N*M
i<X
z[i] = a[i] + b[i]; Y

z[i] = a[i] + b[i];

i = i+1;

16

8
06/05/20

ESCOLHA ADEQUADA DE INSTRUÇÕES

• Selecionar as instruções a serem usadas para implementar cada operação não


é trivial. Pode haver várias instruções diferentes que podem ser usadas para
atingir o mesmo objetivo, mas elas podem ter tempos de execução diferentes.
Além disso, o uso de uma instrução para uma parte do programa pode afetar
as instruções que podem ser usadas no código adjacente.

17

ESCOLHA ADEQUADA DE INSTRUÇÕES

• Pode haver várias maneiras de implementar uma operação ou sequência de


operações.
• Represente operações como grafos, combine possíveis sequências de instruções no
grafo.

+ +
* +

* MUL ADD *
expression
templates MADD

18

9
06/05/20

MELHOR USO DO COMPILADOR

• Entender os vários níveis de otimização (-O1, -O2, etc.)


• Observar a saída mista do compilador/assemblador.
• Modificar a saída do compilador requer cuidados:
• correção;
• perda de código ajustado manualmente.

19

10

Você também pode gostar