Apresentação no TDC2013 - Florianópolis da trilha Mobile e Embedded (25/05/2013). Apresenta algumas dicas, técnicas e sugestões de como melhorar o processamento e uso de memória no código.
4. Globalcode – Open4education
whoami
Osmar da Cunha Filho
Formado em Engenharia de Computação (UNIVALI)
Pós-graduado em Desenvolvimento de Produtos
Eletrônicos (IFSC)
Coordenador de desenvolvimento de Hardware (Specto)
Professor nos cursos de Ciências da Computação (IES)
e Engenharia Civil (IES)
5. Globalcode – Open4education
Otimização!? WTF!?
Otimizar
v.t.d. Ocasionar circunstâncias mais proveitosas para; retirar
o que há de melhor em; aprimorar, melhorar: otimizar o
desenvolvimento do produto; otimizar as condições de
trabalho.
Dar a (algo, uma máquina, uma empresa) um rendimento
ótimo, criando-lhe as condições mais favoráveis ou tirando
(dele ou dela) o melhor partido possível; tornar (algo) ótimo
ou ideal.
Estatística. Instituir o maior valor de uma grandeza.
Informática. Aperfeiçoar um programa para que o mesmo
seja melhor utilizado ou funcione mais rapidamente.
Fonte: http://www.dicio.com.br/otimizar/
8. Globalcode – Open4education
#define X const
Macros (#define) são resolvidas em tempo de
compilação
Consts NEM SEMPRE são resolvidas em tempo
de compilação
Alguns compiladores as traduzem para #defines
#defines são substituídas à medida que o código
vai sendo lido pelo compilador
Consts geram código e consomem memória de
programa
9. Globalcode – Open4education
Aritmética
Multiplicação/Divisão
Potência de dois
2, 4, 8, 16, 32, 64, 128, 256
21
, 22
, 23
, 24
, 25
, 26
, 27
, 28
Multiplicações/Divisões por potências de dois são
rotações de bits
Rotações de bits são operações lógicas!
Operações lógicas são mais rápidas que
aritméticas porque não possuem sinal!
11. Globalcode – Open4education
Condições
Curto-circuito
Curto-circuito ou avaliação preguiçosa (lazy
evaluation)
Sempre em um if de múltiplas condições
simultâneas, colocar a condição mais fácil de ser
testada antes, de forma que as condições
seguintes nem cheguem a ser testadas
A ideia é sair o quanto antes
13. Globalcode – Open4education
Condições
Eliminar “senão”
Pode ser menos custoso executar uma operação e
desfazê-la com próprio if
Elimina algumas instruções referentes ao um salto
condicional
14. Globalcode – Open4education
Condições
Eliminar “senão”
// Exemplo antes
if (condicao) {
executaCasoSe();
}
else {
executaCasoSenao();
}
// Exemplo depois
executaCasoSenao();
if (condicao) {
desfazCasoSenao();
executaCasoSe()
}
// Exemplo antes
if (condicao) {
variavel = 0;
}
else {
variavel++;
}
// Exemplo depois
variavel++;
if (condicao) {
variavel = 0;
}
15. Globalcode – Open4education
Laços
Loop jamming
Loop jamming
Agrupar códigos que irão repetir em um laço só
Principalmente se forem repetidas pela mesma
quantidade de vezes
16. Globalcode – Open4education
Laços
Loop jamming
// Exemplo antes
for ( i = 0; i < 100;
i++ )
{
fazAlgo();
}
for ( i = 0; i < 100;
i++ )
{
fazOutraCoisa();
}
// Exemplo depois
for (i = 0; i < 100;
i++ )
{
fazAlgo();
fazOutraCoisa();
}
17. Globalcode – Open4education
Laços
++ X --
Em vez de contadores progressivos até o limite
máximo, utilizar contadores regressivos
terminando em zero
Algumas arquiteturas possuem instruções que
testam condição de zero após decrementar
18. Globalcode – Open4education
Laços
++ X --
// Incremementando
for ( i = 0; i < 100 ; i++)
// O laco tem que comparar com um valor != 0
i – 100 == 0 ?
i++ e continua
// Decrementando
for ( i = 100; i-- ; )
// O laco tem que testar uma flag de zero da ULA
i == 0 ?
i-- e continua
19. Globalcode – Open4education
Para não chamar a
mesma função
inúmeras vezes,
passando como
parâmetro um
contador, criar uma
função com o contador
internamente
Laços
Contador como parâmetro
// Calcula passando parametro
i (antes)
for (i = 0; i < 100; i++) {
calcula(x,i);
}
// Modificando a funcao para
calcular dentro do laco
(depois)
void calcula (x) {
for(i = 0; i < 100; i++) {
//calcula no laço
}
}
20. Globalcode – Open4education
Laços
Fim
O laço precisa mesmo ir até o final?
Ele pode sair antes e retornar o valor?
Por exemplo em uma pesquisa de elementos!
for (i = 0 ; i < 100 ; i++ ) {
if (arrayExemplo[i] == 100 ) {
encontrado = i;
break;
}
}
21. Globalcode – Open4education
Laços
Loop unrolling
Desenrolar laços de
poucas repetições
O compilador não
precisa definir a
estrutura para
repetição nem calcular
índices
// Antes
for ( i = 0 ; i < 3; i++ )
{
arrayExemplo[i] = 2*i;
}
// Depois
arrayExemplo[0] = 0;
arrayExemplo[1] = 2;
arrayExemplo[2] = 4;
22. Globalcode – Open4education
Laços
Iterativo X Recursivo
Preferir algoritmos iterativos a recursivos
Pode causar estouro de pilha
Aumenta a passagem de parâmetros
Cuidado ao chamar funções no tratamento de
interrupções!
23. Globalcode – Open4education
Alocação
Local X Global
O compilador pode alocar variáveis locais
diretamente em registrador ou na pilha
Variáveis globais vão para a memória (RAM) e por
isso pode ser necessário mais bytes de endereço
para acessá-la
24. Globalcode – Open4education
Alocação
Tipos de dados - Tamanho
Utilizar o tipo mais adequado ao problema
char, int, long?
float, double?
Operações com ponto flutuante demoram mais que
operações em tipos inteiros
Consultar a unidade de ponto flutuante (FPU)!
25. Globalcode – Open4education
Alocação
Tamanho
Na dúvida, use a bitagem da arquitetura!
Em PCs x86, int é mais rápido que char e short
Char e short precisam ser reduzidos!
Int é padrão da arquitetura (seja ela 32 ou 64 bits)!
Em microcontroladores 8 bits, char é mais rápido
Unsigned char é mais rápido ainda
26. Globalcode – Open4education
Alocação
signed X unsigned
Tipos sem sinal são mais rápidos
unsigned char, unsigned int, unsigned long
Tipos com sinal passam por circuitos a mais na
ULA para estender o sinal
Número sem sinal: bit mais significativo é zero
Número com sinal: bit mais significativo é um
28. Globalcode – Open4education
Alocação
Inicialização X Atribuição
É preferível inicializar já com o valor do que
apenas declarar e inicializar depois
Ao inicializar na declaração, não há dois distintos
momentos (alocação e atribuição), ao alocar o
compilador já atribui o valor!
30. Globalcode – Open4education
Alocação
Arrays X Ponteiros
Em vez de usar arrays e índices, utilizar ponteiros!
Utilizando arrays, para acessar o índice n
Ler o endereço base do array
Ler n
Somar endereço base com n
Acessar o endereço calculado
31. Globalcode – Open4education
Alocação
Arrays X Ponteiros
Usando ponteiros:
Apontar o ponteiro para o início do array
Somar o índice ao ponteiro
Aritmética de ponteiros! :D
Recalcular os índices deixa de ser repetida a cada
iteração
Para varrer listas (uso comum), o ponteiro é
incrementado em somente uma unidade (INC)
32. Globalcode – Open4education
Alocação
Arrays X Ponteiros
// Antes
int arrayTeste[100];
for (i = 0; i < 100;
i++)
{
arrayTeste[i] = 0;
}
// Depois
int arrayTeste[100];
int *ponteiroArray;
ponteiroArray =
&arrayTeste[0];
for (i = 0; i < 100; i++) {
*ponteiroArray = 0;
ponteiroArray++;
}
33. Globalcode – Open4education
Alocação
Arrays multidimensionais
Localidade de referência
Valor ou local de armazenamento frequentemente
acessado
Localidade de referência espacial
Locais de armazenamento próximos
Arrays multidmensionais serão alocados em uma
memória unidimensional
34. Globalcode – Open4education
Alocação
Arrays multidimensionais
Atenção à ordem dos índices!
Acessar:
arrayTeste [ i ][ j ]
arrayTeste [ i ] [ j + 1]
é melhor que:
arrayTeste [ i + 1 ] [ j ]
35. Globalcode – Open4education
Alocação
Alinhamento (padding)
// Cabe em 20 bytes:
struct exemplo {
int a;
char b;
int c;
char d;
int e;
}
// Cabe em 16 bytes:
struct exemplo {
int a;
int c;
int e;
char b;
char d;
}
Alinhar o tipo a potências de 2!
36. Globalcode – Open4education
Alocação
Campos de bits (bitfields)
Para otimizar uso de
memória para
armazenar um valor
booleano, pode-se
utilizar campos de bits
struct campoDeBits {
unsigned bit0: 1;
unsigned bit1: 1;
unsigned bit2: 1;
unsigned bit3: 1;
unsigned bit4: 1;
unsigned bit5: 1;
unsigned bit6: 1;
unsigned bit7: 1;
}
37. Globalcode – Open4education
Alocação
Campos de bits (bitfields)
Alguns cuidados com os campos de bits:
Os bits não são endereçáveis diretamente (pelo
operador &), somente pela struct (no exemplo,
campoDeBits.bit0)
Custa mais processamento ler um bit do que um
unsigned char
Exige operações de teste bit a bit
38. Globalcode – Open4education
Parâmetros
Dependendo da arquitetura, os primeiros
parâmetros (4 para x86) são passados por
registradores
Os parâmetros seguintes são passados pela pilha
Ou seja, além do quarto parâmetro, custa ainda
mais acessar os parâmetros
Operações de acesso à pilha
39. Globalcode – Open4education
Parâmetros
É preferível passar structs por referência em vez
de por valor
Assim não há a cópia da struct toda para
registradores/pilha
42. Globalcode – Open4education
rand()
F**K OPTIMIZING
Quando não se quer que o compilador otimize uma
variável, basta declará-la como volatile
volatile unsigned char variavel;
Útil em casos que a variável é compartilhada
Interrupções
Timers
Threads
44. Globalcode – Open4education
Fronteira final!?
Otimização pelo compilador
Análise de algoritmo (big-O)
Buscar outros algoritmos
Otimizar em Assembly.
45. Globalcode – Open4education
Bora otimizar, então! #sqn
Não adianta otimizar o que ESTÁ ERRADO!
Primeiro preocupar-se com a corretude
Garantir a legibilidade do código
É tão necessário transformar tudo em ponteiros em
#defines?
46. Globalcode – Open4education
Bora otimizar, então! #sqn
Donald Knuth
premature optimization is the root of all evil
Tio Ben
With great powers come great responsabilities