La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Performance des logiciels Besoins et stratégies (avec des exemples de Steve McConnell « Code Complete ») Vladimir Makarenkov (Université du Québec à Montréal)

Présentations similaires


Présentation au sujet: "Performance des logiciels Besoins et stratégies (avec des exemples de Steve McConnell « Code Complete ») Vladimir Makarenkov (Université du Québec à Montréal)"— Transcription de la présentation:

1 Performance des logiciels Besoins et stratégies (avec des exemples de Steve McConnell « Code Complete ») Vladimir Makarenkov (Université du Québec à Montréal)

2 Nécessité davoir des logiciels performants Applications critiques Applications scientifiques Informatique embarquée Besoin de temps de réponse très courts Services distants Avantage concurrentiel … La performance doit faire partie des spécifications

3 Ne pas optimiser le code si ce nest pas nécessaire Les méthodes doptimisation manuelles produisent souvent un code peu maintenable et de faible qualité La recherche doptimisation demande des ressources de haut niveau Loptimisation peut introduire des erreurs difficilement retraçables

4 Facteurs influençant les performances Choix des algorithmes Choix des structures de données Choix du langage et du compilateur Choix du matériel Importance des accès mémoire ou E/S Qualité du code & expertise du programmeur

5 Principe de Pareto (80 / 20) Pareto: « 80% des richesses sont possèdes par 20% de la population » (Peut sappliquer à toute sorte de domaines) Knuth: moins de 4% du code compte pour plus de 50% du temps dexécution Rechercher les portions critiques (« profiling ») Rechercher les structures et types adaptés aux besoins et moins gourmands en ressources Modulariser lapplication –Facilite le profilage et les modifications locales Utiliser des compilateurs offrant des options doptimisation Optimiser les détails du code (code-tuning)

6 Règles doptimisation 1 re règle doptimisation –Ne rien faire 2 e règle doptimisation –Ne rien faire 3 e règle doptimisation (pour experts seulement) –Ne rien faire maintenant Attendre davoir une version finale entièrement opérationnelle.

7 Optimisation par le compilateur Souvent suffisant pour atteindre les objectifs –Meilleure que loptimisation manuelle Loptimisation par le compilateur peut améliorer les performances de plus de 40% –Loptimisation manuelle se limite à % dans le meilleur des cas. Loptimisation manuelle peut entrer en conflit avec des options du compilateur Choisir le compilateur en conséquence

8 Comparaison des performances de certains compilateurs (en secondes) LangageSans Optimisation Optimisation par le compilateur Gain C++ (compilateur 1) % C++ (compilateur 2) % C++ (compilateur 3) % C#1.55 0% Visual Basic1.78 0% Java VM % Java VM < 1% Java VM %

9 Mesures de performance Permettent de circonscrire les portions de code critiques Il faut des mesures précises Il faut mesurer ce qui nous intéresse –Attention aux délais dûs aux OS, des programmes en arrière plan, etc. Utiliser des outils de profilage Garder les mesures pour les tests subséquents Refaire les mesures après chaque modification

10 Outils dévaluation Unix cc –p nom_du_fichier -> a.out -> mon.out ( voir avec prof ) gcc –pg nom_du_fichier -> a.out -> gmon.out ( voir avec gprof ) Windows –ANTS Profiler –JProbe Gestion du temps du langage –Java classe Date, Time, currentTimeMillis() –C clock, time

11 Quand optimiser ? Si la performance ne correspond pas aux attentes ou aux spécifications Si le gain en vaut la peine –Le temps passé à optimiser ne doit pas être supérieur au gain réalisé pendant toute la durée de vie du programme

12 Quand optimiser ? (2) Si la performance apporte une plus value importante au logiciel Quand le code est finalisé et fonctionnel Après avoir trouvé les points critiques

13 Analyse de performances : comment ? Sur un code complètement implémenté et testé Sur une version « release » (optimisée par le compilateur …) Avec des données représentatives Le cycle doptimisation:

14 Sources dinefficacité classiques Boucles –Sortir les calculs, tests et opérations qui ne dépendent pas des itérations de la boucle for (i = 0; i < image.with()*image.height(); i++){…} vs int longueur = image.with()*image.height() for (i = 0; i < longueur; i++) {…}

15 Sources dinefficacité (2) Boucles –Ordre des boucles imbriquées Placez la boucle la plus active à lintérieur for (i = 0; i < 1000; i++) for(j = 0; j < 10; j++) {…} vs for (j = 0; j < 10; j++) { for(i = 0; i < 1000; i++) {…} }

16 Sources dinefficacité (3) Boucles –Dérouler les boucles for (i = 1; i < 4; i++) { a[i] = 0; } vs a[1] = 0; a[2] = 0; a[3] = 0; –Ordre de parcours de tableaux Profiter de lantémémoire (i.e. mémoire cache)

17 Remarques Loption doptimisation par le compilateur peut effectuer quelques unes des optimisations citées dans les exemples précédents (et suivants), telles que lidentification des invariants de boucles, déroulement de boucles simples ou lélimination des sous–expressions communes dans une ligne de code. Cependant, si ces modifications naltèrent pas la lisibilité du code, elles peuvent être faites manuellement. Loptimisation de la gestion de lantémémoire (i.e. mémoire cache) dépens de la manière dont le processeur gère la mémoire. Cest une optimisation de bas niveau étroitement liée au matériel.

18 Sources dinefficacité (4) Test –Utiliser les opérateurs court-circuitants && et || if ((c >= 0) && (c <= 9)) {…} –Traiter les cas usuels et fréquents en premier

19 Sources dinefficacité (5) Calculs –Garder le résultat dun calcul plutôt que de le refaire x = (sin(y) + 1) / (sin(y) – 1); vs monSin = sin(y); x = (monSin + 1) / (monSin – 1);

20 Sources dinefficacité (6) Calculs –Utiliser des opérations moins coûteuses Additions vs multiplication Multiplication par linverse vs division … x = pow(y,2)/2; vs x = (y*y)*0.5;

21 Sources dinefficacité (7) Calculs –Éviter les calculs inutiles sqrt(x) < sqrt(y) donne le même résultat que x < y –Faire un prétraitement des données avant de faire une opération coûteuse –Effectuer un précalcul des résultats courants Ex: tableau de sinus / cosinus pour des valeurs courantes

22 Sources dinefficacité (8) Types de données –Utiliser le type de données approprié –Utiliser le type de données le moins gourmand qui répond aux besoins char < short < int < long < float < double (attention: pas toujours vrai)

23 Sources dinefficacité (9) Types de données –Éviter les nombres à point flottant si ce nest pas indispensable Ex: le calcul de coordonnées à lécran en float na pas de sens, pixels = 1 pixel –Faire attention à la gestion des chaînes de caractères Java et C# créent des instances de classes pour chaque modification dune chaîne et en font la copie C parcourt la chaîne au complet pour en calculer sa longueur

24 Sources dinefficacité (10) E/S & accès distants –Préférer le travail sur des données en mémoire, éviter les accès disque, réseaux, bases de données… –Utiliser la mémoire cache Ex: images dans les navigateurs

25 Sources dinefficacité (11) Erreurs et oublis dans le code –Code de débogage oublié –Libération de la mémoire –Indexation des bases de données –Passage par valeur vs par référence Ex: les tableaux demandent une copie sils sont passés par valeur

26 Comparaison du temps daccès sur un tableau de 100 éléments (en secondes) Accès aléatoire Accès séquentiel LangageAccès fichier disqueAccès mémoireGain C % C# % LangageAccès fichier disqueAccès mémoireGain C % C# %

27 Procédure doptimisation 1) Développer du code maintenable et facile à comprendre 2) En cas de problèmes de performance –A. Garder une version fonctionnelle du code –B. Profiler lexécution du système pour trouver les points critiques –C. Déterminer les sources des problèmes. Sont-ils dûs à une mauvaise architecture, à de mauvais algorithmes, etc.

28 Procédure doptimisation (2) –D. Vérifier si le tuning peur apporter une amélioration, sinon garder le code de létape 1 –E. Faire le tuning des zones trouvées en C –F. Mesurer chaque modification individuellement –G. Si la modification napporte pas de changements significatifs, revenir au code de létape A 3) Répéter létape 2 jusquà ce que les exigences initiales soient satisfaites

29 Attention Ne pas optimiser les prototypes, les tests ou tout code non finalisé Lutilisation de structures de données adaptées apportent plus de gains que le tuning La clarté du code doit primer en premier lieu Commenter les changements. –Risque de « recorriger » lors dune relecture –Le tuning produit souvent du code peu clair

30 Attention (2) « Le mieux est lennemi du bien » –Écrire un programme qui répond aux attentes et noptimiser que les parties critiques Attention aux mythes –Les recettes de cuisine, les idées préconçues, les vieilles solutions, etc. ne sont pas adaptées au contexte et sont souvent dépassées par les avancées technologiques. –Ne se fier quaux tests en situation avec des données représentatives du problème Testez, testez et retestez

31 Techniques doptimisation Code Tuning

32 Rappels Loptimisation (tuning) ne touche que des petites portions du code (points critiques) Les techniques présentées doivent faire lobjet de tests en situation réelle (compilateur, materiel, etc.) Loptimisation ne doit être faite que sur du code final, sil ne correspond pas aux spécifications et en dernier recours par rapport à dautres méthodes

33 Rappels (2) Chaque modification doit être testée et mesurée individuellement Toute modification doit être clairement commentée et expliquée

34 Exemples de gains sur certaines opérations Sur des int (compilateur C, C++, source Kernighan et Pike 1999, en nanosecondes) À tester sur votre configuration OpérationIntFloatDouble i++8N.A i = a + b12 i = a * b1211 i = a / b

35 Arrêter de tester si on connaît la réponse –Exemple de recherche inutile: for(i=0; i

36 Optimisation des opérations logiques (2) switch(entree) { case +: case = : {…} case 0:… case 9: {…} case,: case ?:…:{…} case A:… case Z: {…} … } Ordonner les tests par leur fréquence switch(entree) { case A:… case Z: {…} case,: case ?:…:{…} case 0:… case 9: {…} case +: case = : {…} … }

37 Optimisation des opérations logiques (3) Ordonner les tests par leur fréquence Cas du CaseSans modificationsCode modifiéGain C# % Java2.56 0% Visual Basic % Cas du ifSans modificationsCode modifiéGain C# % Java % Visual Basic %

38 Comparaison du if et du case selon différents langages Langagecaseif elseGain C# % Java % Visual Basic %

39 Optimisation des opérations logiques (4) Substituer des expressions logiques compliquées par des tables de valeurs Utiliser des transformations logiques pour minimiser les opérations (INF 1130)

40 Optimisation des opérations logiques (5) Utiliser lévaluation paresseuse –Évaluer les expressions le plus près possible de leur utilisation –Garder les résultats en mémoire si on doit les utiliser plusieurs fois –Utiliser des langages adaptés (ex: Haskell, Prolog, etc.)

41 Optimisation des opérations logiques (6) La catégorie de lobjet est définie selon son appartenance à un ou plusieurs des 3 groupes (voir le schéma à droite) if (( a && !c)||(a && b && c)) { category = 1;} else if (( b && !a)||(a && c && !b)) { category = 2;} else if ((c && !a && !b)) { category = 3;} else { category = 0;} 0 1 A 2 B C

42 Optimisation des opérations logiques (7) Remplacer les expressions compliquées par des tableaux // définit categoryTable static int categoryTable [2][2][2] = { //!b!c!bcb!cbc 0, 3,2,2,// !a 1,2,1,1// a }; … category = categoryTable[a][b][c];

43 Optimisation des boucles Ce sont des sources importantes de gain (ou perte) de performances Unswitching –Faire les tests qui ne dépendent pas de la boucle à lextérieur (Attention, donne parfois du mauvais code)

44 Optimisation des boucles (2) for (i = 0; i < count; i++) { if (sumType == SUMTYPE_NET) { netSum = netSum + amount[i]; } else { grossSum = grossSum + amount[i]; }

45 Optimisation des boucles (3) if (sumType == SUMTYPE_NET) { for (i = 0; i < count; i++) { netSum = netSum + amount[i]; } } else { for (i = 0; i < count; i++) { grossSum = grossSum + amount[i]; } }

46 Optimisation des boucles (4) LangageSans modificationsCode modifiéGain C % Java % Visual Basic < 1%

47 Optimisation des boucles (5) for(i=0; i < nbEmployes; i++){ nomEmploye[i] = ; } … for(i=0; i < nbEmployes; i++){ salaireEmploye[i] = 0; } Fusion de boucles –Regrouper les portions de code qui travaillent sur le même ensemble déléments for(i=0; i < nbEmployes; i++){ nomEmploye[i] = ; salaireEmploye[i] = 0; }

48 Optimisation des boucles (6) Fusion de boucles LangageSans modificationsCode modifiéGain C % Visual Basic % PHP %

49 Optimisation des boucles (7) i = 0; while (i < count) { a[i] = i; i = i + 1; } Déroulement i = 0; while (i < count - 2) { a[i] = i; a[i + 1] = i + 1; a[i + 2] = i + 2; i = i + 3; } if ( i <= count - 1) { a[count - 1] = count - 1; } if ( i == count - 2) { a[count - 2] = count - 2; }

50 Optimisation des boucles (8) Déroulement Langage (count = 100) Sans modificationsCode modifiéGain C % Java % PHP %

51 Optimisation des boucles (9) rabaisQuantite = taux->rabais-> facteurs->net; for(i = 0; i rabais->facteurs-> net; }

52 Optimisation des boucles (10) Minimiser le travail dans les boucles Langage (nbTaux = 100) Sans modificationsCode modifiéGain C % C# % Java %

53 Optimisation des boucles (11) found = FALSE; i = 0; //test double while((!found) && (i < count)){ if (item[i] == testValue){ found = TRUE; } else { i++; } if (found) {…} Utilisation de sentinelles // Attribuer la sentinelle // Garder la valeur dorigine initialValue = item[count]; item[count] = testValue; i = 0; while (item[i] != testValue){ i++; } // Test si la valeur trouvée if (i < count) {…}

54 Optimisation des boucles (12) Utilisation de sentinelles Tableau de 100 entiersSans modificationsCode modifiéGain C# % Java % Visual Basic % Tableau de 100 floatSans modificationsCode modifiéGain C# % Java % Visual Basic %

55 Optimisation des boucles (13) Mettre la boucle la plus occupée à lintérieur LangageSans modificationsCode modifiéGain C % Java % PHP % for (col = 0; col < 100; col++) { for (lgn = 0; lgn < 5; lig++) { sum += table[lgn][col]; } for (lgn = 0; lgn < 5; lig ++) { for (col = 0; col < 100; col++) { sum += table[lgn][col]; }

56 Optimisation des boucles (14) Réduire la difficulté LangageSans modificationsCode modifiéGain C % Visual Basic % for (i = 0; i < nbVentes; i++) { com[i] = (i+1) * rev * baseCom * rabais; } incremCom = rev*baseCom*rabais; cumulCom = incremCom; for (i = 0; i < nbVentes; i++) { com[i] = cumulCom; cumulCom += incremCom ; }

57 Transformation de types Int vs Float –Attention: peut varier beaucoup selon le langage LangageSans modificationsCode modifiéGain C % Visual Basic % PHP % Dim x As Single For x = 0 to 99 A(x) = 0 Next Dim i As Integer For i = 0 to 99 A(i) = 0 Next

58 Transformation de types (2) Utilisation de tableaux de taille réduite LangageSans modificationsCode modifiéGain C % C# % Java % Visual Basic % for (lgn = 0; lgn < nbLgn; lgn++) { for(col = 0; col < nbCol; col++) { matrix[lgn][col] = 0; } for (i = 0; i < nbLgn * nbCol; i++) { matrix[i] = 0; }

59 Transformation de types (3) Minimiser les références aux tableaux for (typeRabais = 0; typeRabais < nbTypes; typeRabais++) { for (nivRabais = 0; nivRabais < nbNiveaux; nivRabais++) { taux[nivRabais] *= rabais[typeRabais]; } for (typeRabais = 0; typeRabais < nbTypes; typeRabais++) { rabais = rabais[typeRabais]; for (nivRabais = 0; nivRabais < nbNiveaux; nivRabais++) { taux[nivRabais] *= rabais ; }

60 Transformation de types (4) Minimiser les références aux tableaux LangageSans modificationsCode modifiéGain C % C# % Visual Basic %

61 Expressions mathématiques et logiques Utilisation didentités algébriques et logiques simplifiées LangageSans modificationsCode modifiéGain C % Visual Basic % Python % !a & !b3 opérations pow(x, 3)1 appel à pow if (sqrt(x) < sqrt(y)) {…} 2 appels à sqrt !(a | b)2 opérations x*x*xpas dappel de fonction if (x < y) {…} Même valeur de vérité sans faire appel à la fonction sqrt

62 Expressions mathématiques et logiques (2) Utilisation dopérations moins coûteuses LangageSans modificationsCode modifiéGain Visual Basic % Python % //polynôme du n-ème ordre valeur = coef[0]; for (puiss = 1; puiss <= ordre; puiss++) { valeur += coef[puiss] * pow(x, puiss); } //polynôme du n-ème ordre valeur = coef[0]; puissX = x; for (puiss = 1; puiss <= ordre; puiss++) { valeur += coef[puiss] * puissX; puissX = puissX * x; }

63 Initialiser les valeurs à la compilation unsigned int Log2 (unsigned int x) { return (unsigned int) (log(x) / log(2)); } const double LOG2 = ; unsigned int Log2 (unsigned int x) { return (unsigned int) (log(x) / LOG2)); } LangageSans modificationsCode modifiéGain C % Java % PHP % Expressions mathématiques et logiques (3)

64 Être attentif aux routines système LangageSans modificationsCode modifiéGain C % Java % PHP % Expressions mathématiques et logiques (4) unsigned int Log2 (unsigned int x) { return (unsigned int) (log(x) / log(2)); } // fonction sans points flottants // (approximation) unsigned int Log2 (unsigned int x) { if (x < 2) return 0; if (x < 4) return 1; if (x < 8) return 2; … if (x < ) return 30; return 31; }

65 Utilisation de constantes du bon type Précalcul des résultats Éliminer les expressions communes Expressions mathématiques et logiques (5)

66 Calcul préalable dexpressions complexes Expressions mathématiques et logiques (6) double CalculMensualites (long emprunt, int mois, double tauxInteret) { return emprunt / (( 1.0 – Math.pow((1.0 + (tauxInteret / 12.0)), -mois)) / (tauxInteret / 12.0)); }

67 Calcul préalable dexpressions complexes Expressions mathématiques et logiques (7) InteretMensuel = tauxInteret / 12.0; double CalculMensualites (long emprunt, int mois, double tauxInteret) { return emprunt / (( 1.0 – Math.pow((1.0 + InteretMensuel), -mois)) / InteretMensuel); }

68 Routines Bonne décomposition en sous-routines Réécrire les routines en ligne (ou des macros) –De nos jours moins efficace. Le compilateur peut le faire directement avec les options doptimisation. –Exemple: les performances dun programme de copie dune chaîne de caractères réécrit en ligne (fonction inline en C++): LangageRoutineCode inlineGain C % Java %

69 Utiliser un langage de bas niveau Utiliser lassembleur pour optimiser le code C++ et du C pour optimiser le code écrit dans un langage de haut niveau, etc. Nutiliser cette approche que si lon maîtrise le langage de bas niveau et que si les autres solutions nont pas apporté les effets escomptés

70 Utiliser un langage de bas niveau Approche: –1) Écrire 100% du code en langage de haut niveau –2) Tester lapplication entièrement et vérifier son exactitude –3) Si les spécifications de performances ne sont pas atteintes, profiler le programme pour trouver les points critiques (bottlenecks) –4) Recoder quelques petits morceaux de code en langage de bas niveau

71 Connaître le langage utilisé La connaissance des principes internes du langage utilisé permettent dobtenir de bonnes performances par lutilisation des instructions appropriées –Java et C# créent un nouvel objet et font une copie pour toute modification dans un String. Sil y a beaucoup de modifications de texte, utiliser les classes appropriées (StringBuilder ou similaires) –En C, strlen() parcours toute la chaîne pour calculer sa longueur –Vérifier si le passage par défaut des paramètres se fait par référence ou par valeur, forcer le choix approprié


Télécharger ppt "Performance des logiciels Besoins et stratégies (avec des exemples de Steve McConnell « Code Complete ») Vladimir Makarenkov (Université du Québec à Montréal)"

Présentations similaires


Annonces Google