Vous êtes sur la page 1sur 60

Optimisation de code

Brique ASC
Samuel Tardieu
sam@rfc1149.net
cole Nationale Suprieure des Tlcommunications

Samuel Tardieu (ENST)

Optimisation de code

1 / 77

But

Loptimisation cherche
amliorer les performances
rduire lencombrement du code
rduire lencombrement mmoire lexcution
Ces contraintes sont souvent contradictoires.

Samuel Tardieu (ENST)

Optimisation de code

2 / 77

Phases doptimisation

lcriture du code :
choix dun meilleur algorithme

Sur larbre intermdiaire :


limination du code mort
optimisation des sous-expressions
optimisation des boucles

Sur le gnrateur de code :


choix des instructions
ordonnancement des instructions

Samuel Tardieu (ENST)

Optimisation de code

3 / 77

Optimisation algorithmique

la louche : 90% du temps est pass dans 10% du code


Optimiser ces 10% est primordial
Loptimisation des 90% restants est pnible et frustrante

Samuel Tardieu (ENST)

Optimisation de code

4 / 77

Exemples doptimisations

Dans certains cas (seulement), des optimisations simples peuvent


amliorer grandement les performances :
Remplacer un algorithme de tri par un autre
Utiliser un tableau plutt quune liste chane
Utiliser lallocation sur la pile (alloca()) plutt que dans le tas
(malloc())
Faire calculer le plus de choses possibles la compilation (Forth,
C++)

Samuel Tardieu (ENST)

Optimisation de code

5 / 77

Mesure de performance

void f () {
unsigned int i;
for (i = 0; i < 10000000; i++) {
free (malloc (10000));
}
}

Les temps sur un Pentium III 650 (FreeBSD) sont :


avec malloc() : 3,62 secondes
avec alloca() : 0,03 secondes

Samuel Tardieu (ENST)

Optimisation de code

7 / 77

Outils dvaluation

Horloge au mur : time commande sous Unix


Profiler : gprof
donne les temps dexcution et le nombre de passages dans chaque
fonction
indique les graphes dappel et les cycles

Samuel Tardieu (ENST)

Optimisation de code

8 / 77

Reprsentation du programme

Pour loptimisation, on prfre travailler sur un graphe :


Les nuds sont les instructions lmentaires
Une arte de A vers B reprsente un rfrencement de B par A :
fin du programme 0 dpart
branchement 1 ou plusieurs dparts
pointeur sur fonction 1 dpart supplmentaire
instruction normale 1 dpart

Samuel Tardieu (ENST)

Optimisation de code

9 / 77

Dcoupage en blocs

Les nuds peuvent tre regroups en bloc :


Les nuds dun bloc, sauf le premier, nont quune arte provenant du
nud prcdent du bloc
Les nuds dun bloc, sauf le dernier, nont quune arte vers le nud
suivant du bloc
Les blocs les plus longs possibles sont constitus

Samuel Tardieu (ENST)

Optimisation de code

10 / 77

Exemple : une boucle

Entte de boucle

(do . . .while)

Test ngatif

Test de boucle

Corps de boucle
Sortie par break

Aprs la boucle
Samuel Tardieu (ENST)

Optimisation de code

11 / 77

Optimisations du graphe

Les optimisations se rangent en deux catgories :


les optimisations locales, lintrieur dun bloc unique
les optimisations globales, impliquant plusieurs blocs conscutifs

Samuel Tardieu (ENST)

Optimisation de code

12 / 77

limination du code mort

Un bloc auquel narrive aucune arte est du code mort et peut tre
limin (ainsi que les artes qui en partent) sans altration smantique
Llimination du code mort peut faire apparatre du nouveau code
mort
Lapplication dautres optimisations peut faire apparatre du code
mort
if (debugFlag) { ...code mort... }

Samuel Tardieu (ENST)

Optimisation de code

14 / 77

Code vivant

Le point dentre dun sous-programme export est vivant :


ce sous-programme peut tre appel par du code se trouvant dans un
autre fichier
main() en C est un exemple
les fonctions static en C ne sont pas exportes et peuvent tre
limines

Samuel Tardieu (ENST)

Optimisation de code

15 / 77

Sous-expressions communes

Souvent, des expressions ou sous-expressions sont calcules plusieurs fois


dans un mme bloc sans que les paramtres changent. Ces expressions
peuvent tre implicites, et non optimisables par le programmeur.
int t[10], u[10];
...
for (i = 0; i < 10) {
u[i] = t[i] + 1; /* double calcul de i*4 */
}

Samuel Tardieu (ENST)

Optimisation de code

17 / 77

Exemple

lintrieur du corps de la boucle, on a :


r1 i 4
r2 [t + r1 ]
r3 r 2 + 1
r4 i 4
r5 u + r 4
[r5 ] r3
r4 peut tre limin et remplac par r1

Samuel Tardieu (ENST)

Optimisation de code

18 / 77

Exemple avec optimisation

lintrieur du corps de la boucle, on a maintenant :


r1 i 4
r2 [t + r1 ]
r3 r 2 + 1
r5 u + r 1
[r5 ] r3
Gain : 1 instruction sur 6

Samuel Tardieu (ENST)

Optimisation de code

19 / 77

GCSE

GCSE : Global Common Sub-Expression Elimination


Extension de llimination de sous-expressions communes un
ensemble de blocs
Ncessite dexaminer les chemins de donnes entre les blocs
Existe en deux variantes : classique et PRE (Partial Redundancy
Elimination)

Samuel Tardieu (ENST)

Optimisation de code

20 / 77

Situation de dpart

Plusieurs blocs calculent a + b. Quels calculs redondants supprimer ?

a+b

a+b

a+b

Samuel Tardieu (ENST)

Optimisation de code

21 / 77

GCSE classique
On peut supprimer un calcul, car a + b a dj t calcul sur le chemin :

a+b

a+b

a+b

Le second ne peut pas tre supprim.

Samuel Tardieu (ENST)

Optimisation de code

22 / 77

GCSE avec PRE


On rajoute un calcul sur lautre chemin :

a+b

a+b

Ajout en
queue de bloc

a+b

a+b

Cest de toute faon plus efficace.

Samuel Tardieu (ENST)

Optimisation de code

23 / 77

Inconvnients du GCSE

La dure de vie des registres contenant les sous-expressions est


allonge : problme avec certaines architectures CISC
Plus de code peut tre gnr (PRE) si le calcul doit tre ajout dans
plusieurs blocs. Toutefois, on peut gnrer un bloc supplmentaire
ddi au calcul de cette expression

Samuel Tardieu (ENST)

Optimisation de code

24 / 77

Affectations multiples

lintrieur dun bloc, une affectation une variable (ou registre) cible
peut tre supprime si les conditions suivantes sont vrifies
simultanment :
la variable est affecte une seconde fois ou elle atteint sa limite de
dure de vie dans le bloc (dans ce cas, une affectation fictive est
suppose en fin de bloc)
entre les deux affectations, la variable nest pas utilise en lecture

Samuel Tardieu (ENST)

Optimisation de code

25 / 77

Propagation des copies

Ide : lorsquune copie est faite et utilise, on utilise loriginal plutt


que la copie
But : pouvoir liminer laffectation par la suite
Considrons le code :
x

r1

. . . (code nutilisant pas r1 )


x

Samuel Tardieu (ENST)

x +1

Optimisation de code

26 / 77

Rsultat de la propagation

r1

. . . (code nutilisant pas r1 )


x

r1 + 1

tape suivante : (affectations multiples)


. . . (code nutilisant pas r1 )
x

Samuel Tardieu (ENST)

r1 + 1

Optimisation de code

27 / 77

Simplification dexpressions

Il est possible de simplifier certaines expressions :


en prcalculant certaines valeurs
en utilisant les identits remarquables

Samuel Tardieu (ENST)

Optimisation de code

28 / 77

Prcalcul de valeurs

Il est possible de prcalculer certaines valeurs (fonctions standards,


oprations arithmtiques sur constantes, etc.)
Le rsultat doit tre quivalent ce qui aurait t calcul lexcution
Une solution existe pour ne pas interprter le code : compiler
lexpression et prendre lvaluation

Samuel Tardieu (ENST)

Optimisation de code

29 / 77

Identits remarquables

x 0

x 1

x 2

x +x

x x

x +0

x C

x + (C )

x x

0/x

...

Samuel Tardieu (ENST)

Optimisation de code

30 / 77

Exemple
Le code :
int x;
int g () {
return (3*4 + x*7 - 5) / 7;
}
gnre avec GCC sur IA32 :
g:
movl x,%eax
incl %eax
ret

Samuel Tardieu (ENST)

Optimisation de code

32 / 77

Structure dune boucle

Entte de boucle

(do . . .while)

Test ngatif

Test de boucle

Corps de boucle
Sortie par break

Aprs la boucle
Samuel Tardieu (ENST)

Optimisation de code

33 / 77

Optimisations de boucles

Les boucles reprsentent en gnral une part importante du temps


consomm dans un programme. Les optimisations sont :
Dplacement de code
Optimisation des variables induites
limination du code mort

Samuel Tardieu (ENST)

Optimisation de code

34 / 77

Dplacement de code
Ide : sortir du code invariant de la boucle
Solution : le placer dans lentte
for (i = 0; i < limit*2; i++) {
...
}
devient
int j = limit*2;
for (i = 0; i < j; i++) {
...
}

Samuel Tardieu (ENST)

Optimisation de code

36 / 77

Variables induites

Soit une boucle dindice i. Une variable j est directement induite si :


i est incrment dune valeur constante chaque tour de boucle
j est affect dans la boucle avant toute lecture
j est de la forme i C , o C est un invariant de la boucle

Samuel Tardieu (ENST)

Optimisation de code

37 / 77

Induction indirecte

Soit une boucle et une variable induite j. Une variable k est indirectement
induite si :
k est affect dans la boucle avant toute lecture
k est de la forme j + C o C est un invariant de la boucle

Samuel Tardieu (ENST)

Optimisation de code

38 / 77

Strength reduction

Ide : soit une boucle dindice i et dincrment , optimiser une


variable induite k
Solution :
k est de la forme i A + B o A et B sont des invariants de la boucle
on place k i0 A + B dans lentte de la boucle
on place k k + A la fin du corps de la boucle

Dans certains cas, A est mme constant

Samuel Tardieu (ENST)

Optimisation de code

39 / 77

Exemple

Soit le code Ada :


with F;
procedure Strength is
begin
for I in 1 .. 10 loop
F (I*17+3);
end loop;
end Strength;

Samuel Tardieu (ENST)

Optimisation de code

41 / 77

Exemple (suite)

Le code devient, sur IA32 :


movl $1,%esi
movl $20,%ebx
.align 4
.L5:
[...]
addl $17,%ebx
incl %esi
cmpl $10,%esi
jle .L5

Le compilateur aurait pu mieux faire.

Samuel Tardieu (ENST)

Optimisation de code

43 / 77

Inversion du sens de la boucle


Lorsque lindice de boucle nest pas utilis, le compilateur peut inverser la
boucle.
for I in 1 .. 10 loop
null;
end loop;
est compil, sur IA32, comme :
movl $9,%eax
.align 4
.L5:
decl %eax
jns .L5

Samuel Tardieu (ENST)

; jump if no sign

Optimisation de code

45 / 77

Droulement
Il est parfois possible de drouler une boucle, notamment lorsque le
nombre ditrations est constant.
Exemple :
int a;
void f()
{
int i;
for (i = 0; i < 4; i++) {
a++;
}
}

Samuel Tardieu (ENST)

Optimisation de code

47 / 77

Exemple de droulement

f:
movl $3,%ecx
.L6:
incl a
decl %ecx
jns .L6
ret

devient, aprs droulement : (IA32)


f:
addl $4,a
ret

Samuel Tardieu (ENST)

Optimisation de code

49 / 77

Rcursion terminale

Dans certains cas, un sous-programme peut se rappeler rcursivement sans


passer par un appel de sous-programme :
la valeur retourne est le rsultat direct dun appel de sous-programme
aucun destructeur ne doit tre excut la sortie du sous-programme
aucune exception ne peut tre rattrape dans le sous-programme

Samuel Tardieu (ENST)

Optimisation de code

50 / 77

Exemple

Le code suivant peut bnficier de la rcursion terminale :


unsigned int
tail (unsigned int n)
{
if (n % 2 == 0)
return tail (n/2);
return n;
}

Samuel Tardieu (ENST)

Optimisation de code

52 / 77

Exemple : code gnr

tail:
movl 4(%esp),%eax
.L4:
testb $1,%al
jne .L3
shrl $1,%eax
jmp .L4
.L3:
ret

Le paramtre est plac dans %eax au dbut (prologue), et on y retourne.

Samuel Tardieu (ENST)

Optimisation de code

54 / 77

Inlining

Principe : remplacer les appels des sous-programmes courts par le


code du sous-programme lui-mme
Avantages :
conomise le cot de lappel
permet une meilleure optimisation et utilisation des registres

Inconvnients :
gnre du code plus volumineux
peut casser une ligne de cache

Samuel Tardieu (ENST)

Optimisation de code

55 / 77

Inlining : exemple

int square (int n) { return n*n; }


int f (int n) { return square(n)*2; }

gnre (IA32)
f:
movl 4(%esp),%eax
imull %eax,%eax
addl %eax,%eax
ret

Samuel Tardieu (ENST)

Optimisation de code

57 / 77

Conclusion partielle

Les optimisations au niveau des blocs de code sont nombreuses :


limination du code mort
limination des sous-expressions communes (locale et globale)
propagation des copies et simplification dexpressions
optimisation des boucles
rcursion terminale, inlining

Samuel Tardieu (ENST)

Optimisation de code

59 / 77

Optimisation : gnration

La gnration de code proprement dite donne lieu plusieurs familles


doptimisations :
choix des instructions machines
choix des registres
optimisation du code assembleur
ordonnancement des instructions

Samuel Tardieu (ENST)

Optimisation de code

60 / 77

Choix des instructions

Principe : faire correspondre les nuds aux instructions


Optimisation : runir des nuds successifs dun mme bloc :
code plus petit
code plus rapide

Deux techniques possibles :


une opration de base, une instruction
recherche de couverture optimale partir dune description du
processeur

Samuel Tardieu (ENST)

Optimisation de code

61 / 77

Lapproche de GCC

Pour chaque architecture supporte, un fichier dcrit (entre autres) :


pour chaque opcode de la cible :
les contraintes sur ses arguments et leur type
les effets dans un pseudo-langage propre GCC
des attributs de description de leffet (mmoire, delay slots, etc.)

comment construire le prologue et lpilogue

Samuel Tardieu (ENST)

Optimisation de code

62 / 77

Couverture optimale

But : trouver un ensemble dinstructions sexcutant en un temps


minimal
Mthode : essayer les diffrentes combinaisons possibles permettant
dliminer les conflits de registres
Aides : dans GCC, certaines fonctionnalits peuvent tre nommes
pour faire correspondre des oprations donnes du code machine

Samuel Tardieu (ENST)

Optimisation de code

63 / 77

Peepholes

But : remplacer une suite dinstructions assembleur par des squences


codes en dur plus efficaces
Mthode : regarder le code gnr travers une fentre
Exemples :
un dcalage de pile suivi dun push
substract one and jump if non zero instruction sur le 1750a

Samuel Tardieu (ENST)

Optimisation de code

65 / 77

Ordonnancement

But : ordonner les instructions pour que lexcution soit plus rapide
sans perturber la smantique
Mthode :
utiliser les attributs dunits fonctionnelles et de delay slots
correspondant au processeur
gnrer des prefetch et des streaming stores pour mieux contrler le
cache

Samuel Tardieu (ENST)

Optimisation de code

66 / 77

Conclusion partielle

Loptimisation au niveau du gnrateur de code


est trs lie larchitecture
demande normment de tests du compilateur pour comparer les
diffrents codes gnrs
permet de corriger des problmes lis la conception du compilateur
par des optimisations fines (peepholes)

Samuel Tardieu (ENST)

Optimisation de code

67 / 77

Autres optimisations

Aiguillage dynamique
Minimalisation des tests de contraintes
Exceptions cot zro
Page zro
Serveurs de compilation
Caches de compilation

Samuel Tardieu (ENST)

Optimisation de code

68 / 77

Aiguillage dynamique

But : transformer les aiguillages dynamiques des langages objets en


aiguillages statiques
Mthode :
analyse globale du systme
infrence de type lorsque cest possible
remplacement des appels dynamiques par des appels statiques

Implmentations : Eiffel

Samuel Tardieu (ENST)

Optimisation de code

69 / 77

Tests de contraintes

But : liminer des tests de contraintes inutiles


Mthode :
analyse des types et des bornes des donnes
sortie de boucle des tests sur des donnes invariantes
utilisation de vrifications matrielles ds que possible

Implmentations : GNAT

Samuel Tardieu (ENST)

Optimisation de code

70 / 77

Exceptions

But : rduire le cot des exceptions :


une exception non leve ne doit rien coter
une exception leve peut prendre du temps

Mthode :
gnration dans lexcutable de tables (code, exception,
traite-exception)
lors de la leve dune exception, analyse du graphe dappel et
dtermination du traite-exception appeler

Implmentations : GNAT

Samuel Tardieu (ENST)

Optimisation de code

71 / 77

Page zro

But : permettre le pipelining de if (p && *p) {...}


Problme : en prsence dun pipe de plusieurs niveaux, la lecture de *p
doit tre diffre si p vaut zro (erreur de lecture, adresse non valide)
Solution : le systme dexploitation autorise la page contenant
ladresse zro en lecture

Samuel Tardieu (ENST)

Optimisation de code

73 / 77

Temps de compilation

On peut rduire le temps de compilation :


Serveur de compilation : un serveur garde en mmoire les arbres
smantiques (langages avec prototypes)
Cache de compilation : un serveur garde sur disque les versions
compiles des fichiers, en cas de recompilation du mme fichier avec
les mmes options

Samuel Tardieu (ENST)

Optimisation de code

74 / 77

Compilation interactive

En Forth,
il ny a pas de compilateur central (chaque mot cit gnre un appel
lui-mme en mode compilation)
chaque mot peut tre rendu intelligent, optimiser en fonction des
mots prcdents et positionner des indices pour les mots suivants
par exemple, dup drop fera que drop annulera leffet du dup

Samuel Tardieu (ENST)

Optimisation de code

76 / 77

Conclusion

Loptimisation a lieu tous les niveaux, du code source au code


machine
Certaines optimisations prennent du temps la compilation pour un
faible gain, dautres prennent peu de temps pour un gain norme
Plus la connaissance de la machine cible est grande, meilleure est
loptimisation possible
Toute nouvelle optimisation est source derreur potentielle

Samuel Tardieu (ENST)

Optimisation de code

77 / 77