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 : eaxv1*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