12. Optimisation.ppt
Download
Report
Transcript 12. Optimisation.ppt
L’optimisation
Laurent JEANPIERRE
<[email protected]>
IUT de CAEN – Campus 3
Département Informatique
Contenu du cours
Introduction
Le Pentium 4
Conseils généraux
Optimiser le code assembleur
Conseils généraux
Conseils spécifiques
Département Informatique
2
L’optimisation
En théorie ?
Rendre un programme optimal !
En pratique ?
Augmenter sa vitesse d’exécution
Réduire son empreinte mémoire
Rarement compatibles…
Département Informatique
3
Principes de base
Règle fondamentale :
D’abord un programme qui marche
Ensuite un programme optimisé
TESTER après chaque optimisation !
Langages de haut niveau
Faciles à utiliser
Développement rapide
Surcouche importante
Pas optimisé
Département Informatique
4
L’optimisation aujourd’hui
Un programme classique « optimisé », c’est :
90 % de haut niveau (plusieurs millions lignes)
9 % de bas niveau (100-1000 lignes)
Interface utilisateur, sauvegarde, …
Java, SmallTalk, Delphi, C++, …
Routines souvent utilisées, …
Maîtrise nécessaire (processeur, mémoire)
Pascal, C, …
1 % d’assembleur (<200 lignes)
Routines critiques (temps exécution)
Exécutées des millions de fois (boucles)
Département Informatique
5
Dans ce cours…
Focus sur le Pentium 4
Disponible en salle machine
Machines courantes aujourd’hui
Principes restent valables
Pour d’autres processeurs
Pour d’autres compilateurs
Dans certaines limites
Département Informatique
6
Contenu du cours
Introduction
Le Pentium 4
Conseils généraux
Optimiser le code assembleur
Conseils généraux
Conseils spécifiques
Département Informatique
7
Le Pentium 4
Processeur CISC à cœur RISC
Instructions CISC
mopérations RISC (mop)
Architecture netburst : Pipeline long (30)
Architecture super-scalaire
Plusieurs unités parallèles
Processeur de nouvelle génération
Optimise le code à la volée
Département Informatique
8
Architecture P4 ( © Intel )
Département Informatique
9
Architecture P4 (1)
Le cache
L2 : 256Ko, données + instructions
L1 : 8Ko données
2 cache-miss avant remplissage du cache
Accès en ordre croissant uniquement
Trace : 12Kmop (≈60K ?)
Le Front-End
(Pré-)charge les instructions
Décode les instructions chargées (1/cycle)
Cache les mop dans le trace-cache
Fournit les mop aux unités de calcul (3/cycle)
Département Informatique
10
Architecture P4 (2)
Retirement Unit
« Mise à la retraite »
Finalise les mop
Dans l’ordre du programme original
Valide les données des registres
Voir l’unité d’exécution…
Jusqu’à 3 mop/cycle
Département Informatique
11
Architecture P4 (3)
Le prédicateur de branchements
Prédit si un saut sera suivi ou non
Statique : au décodage
Au moment de son décodage
Avant son exécution !
Saut Jmp/Call : exécuté
Saut en arrière : exécuté
Saut en avant : non exécuté
Dynamique : si dans le trace-cache
Selon les exécutions précédentes
Statistiques sommaires... et en nombre limité
(4096 pour les sauts, 16 pour les RET )
Département Informatique
12
Architecture P4 (4)
Unité d’exécution ( © Intel )
4 ports en parallèle, out of order
Département Informatique
13
Architecture P4 (5)
Unité d’exécution (2)
4 ports en parallèle :
Chaque port est indépendant
1 cycle pour le transfert de données
de port à port ≠
Sauf de Load aux autres
Chaque port est « pipeliné »
Exécution de plusieurs instructions en séquence
Granularité variable
½ cycle pour les ALU
2 cycles pour les FPU/SIMD
PAS DU TOUT pour les divisions, ni FPU avancé (√,…)
Département Informatique
14
Architecture P4 (6)
Unité d’exécution (3)
Les données en mémoire
Port 2 pour le chargement
Crée un nouveau registre si besoin
Port 3 pour le stockage
Mémoire lente…
Registres virtuels :
Le P3 a 40 registres gen., le P4 en a 120 !
Un Load ou une opération ALU
Alloue un registre
Permet l’exécution hors-ordre si besoin
Département Informatique
15
Architecture P4 (7)
Unité d’exécution (4)
Utilise des buffers locaux
48 en lecture
24+ en écriture (selon versions)
« Store forwarding » : copie de buffer à buffer sans
passer par la mémoire !
« Write combining » : écriture de paquets en
mémoire (ex. : 1*64 au lieu de 8*8)
Store Forwarding, règles du jeu
On ne lit pas plus que ce qu’on a écrit
On aligne les lectures et les écritures
Il faut écrire AVANT de lire
Département Informatique
16
Contenu du cours
Introduction
Le Pentium 4
Conseils généraux
Optimiser le code assembleur
Conseils généraux
Conseils spécifiques
Département Informatique
17
Conseils généraux
D’abord améliorer les algorithmes
Ex. : Quick-sort au lieu du tri à bulles.
Utiliser les données les plus petites
Si la précision le permet !
float au lieu de double
char au lieu de int (éventuellement)
traitement plus rapide
parallélisation possible (SIMD)
Département Informatique
18
Conseils généraux (2)
Eviter les variables globales
Accès relatif (8b ou 16b au lieu de 32b)
Meilleure localité (cache + efficace)
Eviter les écritures multiples en //
Seulement 4 buffers pour le WriteCombining
Eviter de jouer avec les pointeurs
Préférer les tableaux
Compilation optimisée plus facile
Département Informatique
19
Conseils généraux (3)
Eviter les branches
Le programme se suit naturellement
Pas de branchement pas d’erreur de
prédiction
« Inliner » les fonctions courtes (évite
bouger pile)
Aligner variables
Accès plus rapide
Accès séquentiel cache optimisé
Département Informatique
20
Conseils généraux (4)
Eviter les dépendances longues
Autoriser le parallélisme
Exemple : eaxv1*v2*v3*v4*v5*v6*v7*v8
movl
imull
imull
imull
imull
imull
imull
imull
v1,%eax
v2,%eax
v3,%eax
v4,%eax
v5,%eax
v6,%eax
v7,%eax
v8,%eax
#1
#14/8
#14/8
#14/8
#14/8
#14/8
#14/8
#14/8
1+7*14=99 cycles
movl
v1,%eax
imull v2,%eax
movl
v3,%ebx
imull v4,%ebx
movl
v5,%ecx
imull v6,%ecx
movl
v7,%edx
imull v8,%edx
imull %ebx,%eax
imull %ecx,%edx
mov
$0,%edx
39 cycles
Département Informatique
#1
#14/8
#1
#14/8
#1
#14/8
#1
#14/8
#14/4.5
#14/4.5
#0.5
#0-1
#1-15 (0)
#2-3
#3-17 (1)
#4-5
#9-23 (0)
#5-6
#11-25(1)
#17-31(0)
#25-39(1)
#6-7 !!!!
21
Contenu du cours
Introduction
Le Pentium 4
Conseils généraux
Optimiser le code assembleur
Conseils généraux
Conseils spécifiques
Département Informatique
22
Optimiser le code assembleur…
Soit écrire le code de toute pièce
Soit optimiser le travail fait par un
compilateur
Souvent spécifique à un processeur
particulier…
Tout à refaire si le programme change !
Département Informatique
23
Contenu du cours
Introduction
Le Pentium 4
Conseils généraux
Optimiser le code assembleur
Conseils généraux
Conseils spécifiques
Département Informatique
24
Conseils généraux
Préférer les instructions simples
Consulter les tables du fabricant
Ex :
Eviter registres xH
LOOP : 8 cycles (+ besoin ROM microcode)
SUB $-1 + JNZ : 1+1 mops, 1 cycle !
IMUL $3 : 14 cycles (+ besoin ROM microcode)
3*ADD : 1.5 cycles !
Crée de fausses dépendances
Impose 1 mop de plus (Shift interne)
Eviter les instructions INC/DEC
Drapeau C intouché Crée dépendance
Département Informatique
25
Conseils généraux (2)
Passer les paramètres par registre
Dérouler boucles (quoique ?)
≤ 16 itérations prédiction de branchement
meilleure
Sauf si taille > Trace-cache !
Utiliser LEA pour calculs simples
Evite le stockage en mémoire
Sauf échelle (trop lent)
Ex : LEA 15(%ebx,%ecx),%eax
eax ebx+ecx+15
Utiliser XOR au lieu de MOV $0
Plus rapide, code plus court
Casse la dépendance aussi (SAUF XORP !)
Département Informatique
26
Conseils généraux (3)
Ne pas mélanger code et données
Aligner les sauts sur 16 octets
Surtout pour le Pentium-M
Ne pas créer le cadre pile si inutile
Panique du cache
Récupère registre EBP
Instructions en moins
Placer les invariants en mémoire
Libère un registre
Efficace grâce au cache + load-buffer
Département Informatique
27
Contenu du cours
Introduction
Le Pentium 4
Conseils généraux
Optimiser le code assembleur
Conseils généraux
Conseils spécifiques
Département Informatique
28
Conseils spécifiques
Préférer le SSE2 aux FPU
Si beaucoup de calculs
Plus rapide (même unité de calcul)
Possibilité de traitement parallèle
Sauf si instructions spécifiques (trigo, …)
Département Informatique
29
Conseils spécifiques
SSE :
Aligner les données
Accès mémoire plus rapide si @=16x
Ajouter du bourrage !
Plusieurs tableaux tableau de structure
Parallélisation plus simple
FPU :
Opérations avec des entiers 16b (PAS 32b)
Préférable de charger l’entier + opération flottante
Département Informatique
30
Exemple: Rotation 2D en C
Algorithme intuitif
#define N 4096
•Normal :
#define A M_PI/4.
struct point {double x,y;};
•Optimisé O3:
struct point pts[N]={{1,1},{-1,1},
{-1,-1},{1,-1}};
struct point res[N];
int main()
{
int i,j;
double ca = cos(A);
double sa = sin(A);
for (j=0;j<500000;j++) // Pour mesurer des choses
for (i=0; i<N; i++)
{
res[i].x = pts[i].x*ca – pts[i].y*sa;
res[i].y = pts[i].x*sa + pts[i].y*ca;
}// for i
}
Département Informatique
21s
12s
31
Exemple: Rotation 2D en C
Sans les structures
#define N 4096
#define A M_PI/4.
double px[N]={1,-1,-1,1};
double py[N]={1,1,-1,-1};
double rx[N]={1,-1,-1,1};
Double ry[N]={1,1,-1,-1};
•Normal :
14s
•Optimisé O3: 9s
int main()
{
int i,j;
double ca = cos(A);
double sa = sin(A);
for (j=0;j<500000;j++) // Pour mesurer des choses
for (i=0; i<N; i++)
{
rx[i] = px[i]*ca – py[i]*sa;
ry[i] = px[i]*sa + py[i]*ca;
}// for i
}
Département Informatique
32
Exemple: Rotation 2D en C
Algorithme intuitif, double float
#define N 4096
•Normal :
#define A M_PI/4.
struct point {float x,y;};
•Optimisé
struct point pts[N]={{1,1},{-1,1},
{-1,-1},{1,-1}};
struct point res[N];
14s
O3: 9s
int main()
{
int i,j;
float ca = cos(A);
float sa = sin(A);
for (j=0;j<500000;j++) // Pour mesurer des choses
for (i=0; i<N; i++)
{
res[i].x = pts[i].x*ca – pts[i].y*sa;
res[i].y = pts[i].x*sa + pts[i].y*ca;
}// for i
}
Département Informatique
33
Exemple: Rotation 2D en C
Sans structure, double float
#define N 4096
#define A M_PI/4.
float px[N]={1,-1,-1,1};
float py[N]={1,1,-1,-1};
float rx[N]={1,-1,-1,1};
float ry[N]={1,1,-1,-1};
•Normal :
14s
•Optimisé O3: 9s
int main()
{
int i,j;
float ca = cos(A);
float sa = sin(A);
for (j=0;j<500000;j++) // Pour mesurer des choses
for (i=0; i<N; i++)
{
rx[i] = px[i]*ca – py[i]*sa;
ry[i] = px[i]*sa + py[i]*ca;
}// for i
}
Département Informatique
34
Exemple: Rotation 2D en SSE
Algorithme intuitif
off=py-px
.data
.align 16
px:
py:
rx:
ry:
ca:
sa:
N=1024
.rept N
.double 1,-1,-1,1
.endr
.rept N
.double 1,1,-1,-1
.endr
.space 8*4*N
.space 8*4*N
.double 0,0
.double 0,0
.text
.global
main:
pushl
fldpi
fidivs
fsincos
fstl
fstpl
fstl
fstpl
movaps
movaps
main
%ebp
Quatre
ca
ca+8
sa
sa+8
ca,%xmm4
sa,%xmm5
format: .string "%f, %f\n"
Quatre:
.short 4
Département Informatique
35
Exemple: Rotation 2D en SSE
Algorithme intuitif (suite)
movl
boucle3:
movl
$500000,%ebx
movl
movl
boucle:
movapd
movapd
movapd
movapd
$px,%esi
$rx,%edi
mulpd
mulpd
mulpd
mulpd
$(2*N),%ecx
(%esi),%xmm0
off(%esi),%xmm1
(%esi),%xmm2
off(%esi),%xmm3
%xmm5,%xmm0
%xmm5,%xmm1
%xmm4,%xmm2
%xmm4,%xmm3
#
#
#
#
x.sin
y.sin
x.cos
y.cos
subpd
addpd
%xmm1,%xmm2
%xmm0,%xmm3
movapd
movapd
%xmm2,(%edi)
%xmm3,off(%edi)
addl
addl
loop
$16,%esi
$16,%edi
boucle
subl
jnz
$1,%ebx
boucle3
a
a
a
a
Département Informatique
Temps : 4,9s
36
Exemple: Rotation 2D en SSE
Algorithme optimisé (cœur – 1)
movl
movl
.align
boucle3:
boucle:
movapd
movapd
movapd
movapd
movapd
movapd
movapd
mulpd
movapd
mulpd
mulpd
mulpd
$500000,%ebx
$(-32*N),%ecx
16
rx(%ecx),%xmm1
py(%ecx),%xmm0
py(%ecx),%xmm2
rx(%ecx),%xmm3
py+16(%ecx),%xmm4
rx+16(%ecx),%xmm5
py+16(%ecx),%xmm6
sa,%xmm1
# y.sin
rx+16(%ecx),%xmm7
ca,%xmm2
# x.cos
sa,%xmm0
# x.sin
ca,%xmm3
# y.cos
a
a
a
a
#
#
#
#
#
#
#
#
#
#
#
#
1u
1u
1u
1u
1u
1u
1u
1u
1u
1u
1u
1u
Département Informatique
port
port
port
port
port
port
port
port
port
port
port
port
2,
2,
2,
2,
2,
2,
2,
1,
2,
1,
1,
1,
7/1
7/1
7/1
7/1
7/1
7/1
7/1
7/2+1
7/1
7/2+1
7/2+1
7/2+1
0-7
1-8
2-9
3-10
4-11
5-12
6-13
7-14
8-15
9-16
11-18
13-20
37
Exemple: Rotation 2D en SSE
Algorithme optimisé (cœur – 2)
movapd
movapd
subpd
addpd
%xmm2,ry(%ecx)
%xmm3,ca(%ecx)
%xmm5,%xmm6
# rx
%xmm4,%xmm7
# ry
#
#
#
#
movapd
movapd
%xmm6,ry+16(%ecx)
%xmm7,ca+16(%ecx)
# 2u port 0, 7/2
# 2u port 0, 7/2
31-38
33-40
# 1u port
# 1u port
#----# 30u
# 1u port
# 1u port
# 1u port
# 1u port
# 1u port
# 1u port
32-32.5
34-34.5
nop
addl
jnz
nop
nop
movl
subl
jnz
$32,%ecx
boucle
$(-32*N),%ecx
$1,%ebx
boucle3
2u
2u
1u
1u
Département Informatique
port
port
port
port
0,
0,
1,
1,
7/2
7/2
4/2+1
4/2+1
0/1, 0.5
0/1, 0.5
22-29
25-31
26-30
28-32
0, ?/0.5 34.5-35
0/1, 0.5 35-35.5
0/1, 0.5 35.5-36
0/1, 0.5 36-36.5
0/1, 0.5/0.5 +0.5
0(branch), ?/0.5
38
Exemple: Rotation 2D en SSE
Algorithme optimisé (cœur – 3)
jnz
nop
nop
movl
subl
jnz
boucle
# 1u port 0, ?/0.5
# 1u port 0/1, 0.5
# 1u port 0/1, 0.5
# 1u port 0/1, 0.5
# 1u port 0/1, 0.5
# 1u port 0, ?/0.5
#---Temps :
# 6u
$(-32*N),%ecx
$1,%ebx
boucle3
4,5s
XMM0
XMM3
XMM1
XMM2
XMM4
XMM7
XMM5
XMM6
x0|x1
y0|y1
y0|y1
x0|x1
x1|x2
y1|y2
y1|y2
x1|x2
*sin
*cos
*sin
*cos
*sin
*cos
*sin
*cos
+
ry0|ry1
rx0|rx1
Département Informatique
+
ry1|ry2
rx1|rx2
39
Exemple: Rotation 2D en SSE
Algorithme optimisé floats
Chaque registre contient 4 float ou 2 double
Meilleur parallélisme !
ca contient 4 fois le cosinus
sa contient 4 fois le sinus
Temps : 2,25s
XMM0
XMM3
XMM1
XMM2
XMM4
XMM7
XMM5
XMM6
x0..x3
y0..y3
y0..y3
x0...x3
x4..x7
y4..y7
y4..y7
x4..x7
*sin
*cos
*sin
*cos
*sin
*cos
*sin
*cos
+
ry0..ry3
rx0..rx3
Département Informatique
+
ry4..ry7
rx4..rx7
40
Bilan & Conclusion
Le programme optimisé est
Ecriture du programme C
3-4 heures
Optimisation du programme
1 heure
Ecriture du programme Assembleur
Plus rapide (14 secondes 2,25 secondes)
Plus long (31 lignes de C 120 lignes d’asm.)
Plusieurs dizaines d’heures
Mais un programmeur expérimenté irait plus
vite… certainement…
Département Informatique
41