» 
allemand anglais arabe bulgare chinois coréen croate danois espagnol estonien finnois français grec hébreu hindi hongrois islandais indonésien italien japonais letton lituanien malgache néerlandais norvégien persan polonais portugais roumain russe serbe slovaque slovène suédois tchèque thai turc vietnamien
allemand anglais arabe bulgare chinois coréen croate danois espagnol estonien finnois français grec hébreu hindi hongrois islandais indonésien italien japonais letton lituanien malgache néerlandais norvégien persan polonais portugais roumain russe serbe slovaque slovène suédois tchèque thai turc vietnamien

définition - Optimisation de code

voir la définition de Wikipedia

   Publicité ▼

dictionnaire collaboratif

Vous pouvez participer à l'enrichissement du dictionnaire et proposer vos propres définitions pour ce mot ou un autre.

Inscription possible avec votre compte Facebook

Wikipedia

Optimisation de code

                   

En programmation informatique, l'optimisation est la pratique qui consiste généralement à réduire le temps d'exécution d'une fonction, l'espace occupé par les données et le programme, ou la consommation d'énergie.

La règle numéro un de l'optimisation est qu'elle ne doit intervenir qu'une fois que le programme fonctionne et répond aux spécifications fonctionnelles. L'expérience montre qu'appliquer des optimisations de bas niveau du code avant que ces deux conditions ne soient réalisées revient le plus souvent à une perte de temps et s'avère néfaste à la clarté du code et au bon fonctionnement du programme :

« L'optimisation prématurée est la source de tous les maux. »

— Donald Knuth, citant Dijkstra

Cependant cette citation, tronquée, est très souvent mal interprétée. La version complète étant :

« On devrait oublier les petites optimisations locales, disons, 97 % du temps : l'optimisation prématurée est la source de tous les maux[1]. »

— Donald Knuth

La citation originale indique très clairement que cette règle ne doit s'appliquer qu'aux optimisations locales, de bas niveau (réécriture en assembleur, déroulage de boucle etc.) et pas aux optimisations de haut niveau concernant le choix des algorithmes ou l'architecture d'un projet. Au contraire plus le projet grandit et plus ces optimisations de haut niveau seront difficiles et coûteuses (en termes de temps, difficulté et budget), voire impossible, à effectuer.

La plupart des compilateurs récents pratiquent de façon automatique un certain nombre d'optimisations qu'il serait fastidieux d'effectuer manuellement et qui rendraient le code source moins lisible.

L'optimisation manuelle locale peut s'avérer nécessaire dans des cas très spécifiques, mais les mesures montrent que sur des machines RISC qui possèdent un nombre élevé de registres et où l'efficacité demande le regroupement des instructions identiques pour bénéficier de l'effet pipeline, l'optimiseur d'un compilateur C fournit souvent un code plus efficace que celui qui serait écrit en assembleur par un programmeur expérimenté (ce qui n'était jamais le cas sur les machines CISC). Et de surcroit ce code est bien plus facile à maintenir, car les instructions en C restent dans un ordre lié à la seule intelligibilité du code et non aux spécificités de la machine : dans les optimiseurs actuels, en effet, les ordres machines associés à une instruction ne se trouvent plus nécessairement en position contiguë, pour des raisons d'efficacité d'exécution. Cela rend le code assembleur généré particulièrement indéchiffrable.

Sommaire

  Pratique de l'optimisation

  Première approche

Avant de commencer l'optimisation, il faut savoir mesurer la vitesse du code. Pour cela il faut choisir un paramètre, de préférence simple et mesurable. Ceci peut être par exemple le temps de traitement sur un jeu de donnée précis, ou le nombre d'images affichées par seconde, ou encore le nombre de requêtes traitées par minute.

Une fois le paramètre de mesure déterminé, il faut mesurer le temps passé dans chacune des parties du programme. Il n'est pas rare que 80 % à 90 % du temps soit consacré à l'exécution de 10 % du code (les boucles critiques). Les chiffres varient en fonction de la taille et de la complexité des projets. Il faut localiser ces 10 % de code pour être le plus rentable dans ses optimisations. Cette étape de localisation peut être réalisée à l'aide d'outils spécialisés d'instrumentation du code nommés profilers. Ils sont chargés de compter le nombre d'exécutions de chaque fonction et de cycles du microprocesseur correspondants au cours de l'exécution.

Ensuite on itère sur la section la plus consommatrice de ressource autant de fois que nécessaire cette boucle :

  • optimisation d'une partie du code
  • mesure du gain de performances

  Seconde approche

On peut optimiser à plusieurs niveaux un programme:

  • au niveau algorithmique, en choisissant un algorithme de complexité inférieure (au sens mathématique) et des structures de données adaptées,
  • au niveau du langage de développement, en ordonnant au mieux les instructions et en utilisant les bibliothèques disponibles,
  • en utilisant localement un langage de bas niveau, qui peut être le langage C ou, pour les besoins les plus critiques, le langage assembleur.

On ne passe au niveau supérieur d'optimisation qu'une fois qu'on a épuisé les possibilités d'un niveau. L'utilisation d'un langage de bas niveau sur l'ensemble d'un projet pour des raisons de rapidité est l'une des erreurs les plus communes et les plus coûteuses que puisse faire un projet industriel.

L'optimisation de code est considéré par beaucoup de développeurs amateurs comme un art un peu magique et, pour cette raison, comme l'une des parties les plus excitantes de la programmation. Ceci les conduit à croire qu'un bon programmeur est une personne qui optimise d'emblée le programme. Cependant l'expérience montre qu'elle ne peut pallier une mauvaise conception initiale. C'est dans la conception que l'expérience du développeur joue le plus. Par ailleurs, dans un nombre majoritaire et grandissant de cas, le « bon programmeur » est moins celui qui écrit du code astucieux (l'optimiseur s'en chargera le plus souvent mieux que lui) que celui qui écrit du code lisible et aisé à maintenir.

Une bonne connaissance des techniques de structures de données ainsi que des algorithmes (même sans aller jusqu'aux considérations théoriques poussées de la complexité algorithmique) se montre bien plus féconde que celle d'un langage d'assemblage. Lorsqu'on a déterminé l'algorithme le plus adéquat, les optimisations les plus efficaces peuvent être obtenues en utilisant le chemin suivant :

  • écriture du code critique dans un langage de haut niveau (comme Scheme ou Common Lisp),
  • application de transformations mathématiques successives qui préservent la spécification du programme tout en réduisant la consommation des ressources,
  • traduction du code transformé dans un langage de bas niveau (langage C).

Dans la pratique, les performances des machines actuelles font que des applications comportant beaucoup d'entrées-sorties lentes peuvent faire l'économie de ces trois étapes et se rédiger directement dans un langage comme Haskell. L'application bien connue nget, qui moissonne systématiquement les images publiées dans les forums Usenet, avait dans sa première implémentation été écrite en Haskell. La version en C n'en a été qu'une traduction qui ne se révèle pas plus performante pour ce type d'application. Une application limitée principalement par le CPU et la vitesse de la mémoire par contre pourra gagner énormément à être écrite dans un langage tel que le C ou le C++.

  Optimisation automatique

Les compilateurs sont souvent capables de faire des optimisations locales, auxquelles aucun développeur ne penserait en première approche.

Pour le langage C, cela peut considérer :

  • les variables locales et les registres
  • les fonctions non implémentées en assembleur en tant que fonction
  • les switch, qui sont optimum.

Toutefois on peut grandement aider le compilateur en déclarant les variables avec les mots-clefs const et/ou restrict quand c'est possible. Autrement le compilateur ne peut savoir si une zone mémoire est accessible par d'autres références, et désactivera des optimisations (phénomène dit d'aliasing mémoire).

  Exemples

  Utilisation de variables locales pour éviter l'aliasing de mémoire

Le code C++ suivant sera en général peu optimisé par le compilateur car il est souvent incapable de savoir si le code de la boucle modifie ou non le compteur d'itérations : un pointeur ou une référence pourrait le modifier.

 void MyClass::DoSomething() const
 {
     for( int i=0; i<'''m_nbrElements'''; ++i )
     {
         void *ptr = GetSomePtr();
         ....
     }
 }

Dans cette version, on indique clairement qu'on utilise un nombre d'itérations fixé à l'avance et qui ne sera jamais modifié, autorisant le compilateur à effectuer des optimisations plus agressives:

 void MyClass::DoSomething()
 {
     '''const int nbrElements = m_nbrElements;'''
     for( int i=0; i<'''nbrElements'''; ++i )
     {
         ....
     }
 }

  Une spécificité du binaire : le décalage

Une des toutes premières optimisations a été celle de la division et de la multiplication par une puissance de 2.

En effet, l'informatique actuelle repose sur le binaire, puisqu'elle utilise comme élément de base le transistor (et historiquement, auparavant le relais) qui n'autorise que deux valeurs différentes.

On a donc logiquement implémenté en langage machine les opérations de décalage à gauche et décalage à droite.

En effet, en binaire, le décalage d'un nombre d'un cran vers la gauche le multiplie par 2.

Ainsi, 2 (10_2) décalé de 1 bit donne 4 (100_2).
5 (101_2) décalé de 2 bits donne 20 (10100_2) : 5*2^2=20.

Ceci marche aussi pour la division, en décalant les bits vers la droite.

100 (1100100_2) décalé de 3 bits vers la droite donne 100/2^3=12.5 donc 12 (1100_2) car nous travaillons sur des nombres entiers.

Sinon l'arithmétique entière d'un processeur est en fait l'arithmétique dans l'anneau des \mathbb{Z}/2^{32}\mathbb{Z} par exemple. Et donc, tout les nombre premiers avec 2^{32} ont un inverse, et il est possible d'effectuer une division par l'un de ces nombres en une seule instruction. Par exemple, dans l'anneau des entiers sur 32 bits, diviser par 3 revient à multiplier par 2863311531. Diviser par 14 revient à multiplier par 3067833783 puis diviser par 2. C'est donc possible avec deux instructions. Les compilateurs savent faire ces optimisations mais pour cela le diviseur doit être connu à la compilation.

La division dans le cas général est une instruction coûteuse en temps machine, et n'est d'ailleurs toujours pas disponible sur la grande majorité des processeurs de type RISC.

  Le mot clef inline du C

Le code C suivant:

 inline int f(int a, int b) {
     return a * b;
 }
 
 int g (int a) {
     switch (a) {
         case 10:
             return f(a, a);
         case 11: 
         case 12:
             return f(a - 2, a);
         case 1200:
             return f(a - 2, a);
         default:
             return f(a, a);
     }
 }

Une compilation avec gcc -O4 -S donne:

         .file    "opt.c"
         .text
         .p2align 4,,15
         .globl   g
         .type    g, @function
 g:
         pushl   %ebp
         movl    %esp, %ebp
         movl    8(%ebp), %edx
         cmpl    $12, %edx
         jg      .L14
         leal    -2(%edx), %eax
         cmpl    $11, %edx
         jge     .L15
         movl    $100, %eax
         cmpl    $10, %edx
 .L17:
         je      .L2
         movl    %edx, %eax
 .L15:
         imull   %edx, %eax
 .L2:
         popl    %ebp
         ret
         .p2align 4,,7
 .L14:
         movl    $1437600, %eax
         cmpl    $1200, %edx
         jmp     .L17
         .size   g, .-g
         .section        .note.GNU-stack,"",@progbits
         .ident  "GCC: (GNU) 3.3.2 (Mandrake Linux 10.0 3.3.2-6mdk)"

Ce qui pourrait se traduire, pour une compréhension plus aisée, par le code C suivant:

 int g(int a) {
 
  int eax, b;
 
  if (a > 12)          /* cas a == 1200 */
    goto L14;
 
  eax = a - 2;
  if (a >= 11)         /* cas a == 11 ou a == 12 */
    goto L15;
 
  eax=100;             /* = 10 * 10 */
  b=10;
 
 L17:
  if (a == b)          /* cas a == 10 */
    goto L2;
                       /* cas "default" */
  eax=a;
 L15:
  eax=eax*a;
 
 L2:
  return eax;
 
 L14:
  eax = 1437600;       /* = 1200*(1200-2) */
  b = 1200;
  goto L17;
 }

On peut remarquer par exemple que la fonction 'f' n'a pas été générée, mais que son code a directement été incorporé dans la fonction 'g' (le mot clef 'inline' permet de forcer ce type d'optimisation en C)

  Notes et références

  1. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

  Voir aussi

  Liens externes

   
               

 

Toutes les traductions de Optimisation de code


Contenu de sensagent

  • définitions
  • synonymes
  • antonymes
  • encyclopédie

Dictionnaire et traducteur pour mobile

⇨ Nouveau : sensagent est maintenant disponible sur votre mobile

   Publicité ▼

sensagent's office

Raccourcis et gadgets. Gratuit.

* Raccourci Windows : sensagent.

* Widget Vista : sensagent.

dictionnaire et traducteur pour sites web

Alexandria

Une fenêtre (pop-into) d'information (contenu principal de Sensagent) est invoquée un double-clic sur n'importe quel mot de votre page web. LA fenêtre fournit des explications et des traductions contextuelles, c'est-à-dire sans obliger votre visiteur à quitter votre page web !

Essayer ici, télécharger le code;

SensagentBox

Avec la boîte de recherches Sensagent, les visiteurs de votre site peuvent également accéder à une information de référence pertinente parmi plus de 5 millions de pages web indexées sur Sensagent.com. Vous pouvez Choisir la taille qui convient le mieux à votre site et adapter la charte graphique.

Solution commerce électronique

Augmenter le contenu de votre site

Ajouter de nouveaux contenus Add à votre site depuis Sensagent par XML.

Parcourir les produits et les annonces

Obtenir des informations en XML pour filtrer le meilleur contenu.

Indexer des images et définir des méta-données

Fixer la signification de chaque méta-donnée (multilingue).


Renseignements suite à un email de description de votre projet.

Jeux de lettres

Les jeux de lettre français sont :
○   Anagrammes
○   jokers, mots-croisés
○   Lettris
○   Boggle.

Lettris

Lettris est un jeu de lettres gravitationnelles proche de Tetris. Chaque lettre qui apparaît descend ; il faut placer les lettres de telle manière que des mots se forment (gauche, droit, haut et bas) et que de la place soit libérée.

boggle

Il s'agit en 3 minutes de trouver le plus grand nombre de mots possibles de trois lettres et plus dans une grille de 16 lettres. Il est aussi possible de jouer avec la grille de 25 cases. Les lettres doivent être adjacentes et les mots les plus longs sont les meilleurs. Participer au concours et enregistrer votre nom dans la liste de meilleurs joueurs ! Jouer

Dictionnaire de la langue française
Principales Références

La plupart des définitions du français sont proposées par SenseGates et comportent un approfondissement avec Littré et plusieurs auteurs techniques spécialisés.
Le dictionnaire des synonymes est surtout dérivé du dictionnaire intégral (TID).
L'encyclopédie française bénéficie de la licence Wikipedia (GNU).

Copyright

Les jeux de lettres anagramme, mot-croisé, joker, Lettris et Boggle sont proposés par Memodata.
Le service web Alexandria est motorisé par Memodata pour faciliter les recherches sur Ebay.
La SensagentBox est offerte par sensAgent.

Traduction

Changer la langue cible pour obtenir des traductions.
Astuce: parcourir les champs sémantiques du dictionnaire analogique en plusieurs langues pour mieux apprendre avec sensagent.

Dernières recherches dans le dictionnaire :

5456 visiteurs en ligne

calculé en 0,047s

   Publicité ▼

Je voudrais signaler :
section :
une faute d'orthographe ou de grammaire
un contenu abusif (raciste, pornographique, diffamatoire)
une violation de copyright
une erreur
un manque
autre
merci de préciser :

Mon compte

connexion

inscription

   Publicité ▼