Journal Optimiser un programme C++

Posté par  (site web personnel, Mastodon) .
Étiquettes : aucune
0
1
mai
2003
re-Hello,

J'ai besoin de conseils de votre part. Je suis assez content de mon projet C++, mais j'aimerais l'optimiser. Qqn aurait des conseils pour la stratégie liée à l'utilisation de mon programme ?

J'ai essayé de faire un free des variables malloquées quand c'était possible, mais à part ça :
- A quoi faut-il faire spécialement attention ?
- quelle est la commande pour mesurer le temps d'exécution d'une partie particulière du programme ?
- quels sont les trucs à savoir ?

Merci de l'aide...

Pour info, la moitié des étudiants ont un programme qui tourne en 30-45 minutes ! Le mien tourne en 5'40'', mais c'est le gros oeuvre et j'aimerais pouvoir descendre à quelques secondes, je pense que c'est possible :D

Merci à tous
  • # Re: Optimiser un programme C++

    Posté par  . Évalué à 6.

    J'ai essayé de faire un free des variables malloquées quand c'était possible

    C'est pas quand c'est possible qu'il faut le faire, c'est tout le temps
    • [^] # Re: Optimiser un programme C++

      Posté par  . Évalué à 1.

      C'est vrai, mais ajoutons a cela qu'a part avec le fameux char* (qu'il faut vite encapsuler dans une classe representant les chaines de caracteres, ou prendre le string de la STL) il vaut mieux utiliser new et delete que malloc et free !
    • [^] # Re: Optimiser un programme C++

      Posté par  (site web personnel) . Évalué à 1.

      Un malloc (et un new en C++) coute beaucoup de ressources. Il est bien plus utile de réutiliser des espace mémoire déja alloués que de les libérer pour en créer d'autre après.

      Bien sûr il faut aussi éviter les fuites mémoire :)
  • # Re: Optimiser un programme C++

    Posté par  (site web personnel) . Évalué à 1.

    time
    • [^] # Re: Optimiser un programme C++

      Posté par  (site web personnel) . Évalué à 5.

      les outils systems ne donnent que le temps globale d execution d un processus. Donc pour chrono, soit tu le fait a la main, soit tu fork ... quand le fork meurt, le temps d execution est une des valeurs de retour de l apli ... c est ce que retourne time sous bash ...

      Pour gagner du temps : limite les acces disque, prefere tout metre en RAM ( si ca tiens ), puis evite les acces memoire repetes : prefere les traitemens consecutifs de la meme variable : si le compilo est intelligent, il laisse la valeur en registre, ce qui evite les acces RAM ... enfin, paufine bien tes boucles.
      Si tu as des appels de fonctions a outrace, j ai remarque qu un passage par adresse est plus rapide que par valeur ( moins d allocation memoire ), mais une variable globale doit pouvoire faire mieux). Reflechi et cherche tout ce qui peut prendre du temps. evite les definitions de fonctions ; les fonctions inline vouees au remplacement acelerent aussi la chose. Enfin regroupe les operations consecutives en une seule instruction :
      a=a+2;
      a=2*a;
      est plus lent que
      a=2*(a+2);
      j ai teste.

      si deux boucles ont les meme bornes, regroupe les en une seule : tu gagne sur le traitement de la variable d incrementation ET sur le saut en arriere ...

      Bref , si tu veux aprendre a programmer du C efficace, fait 6 mois d ASM ...
  • # Re: Optimiser un programme C++

    Posté par  (site web personnel) . Évalué à 6.

    J'ai essayé de faire un free des variables malloquées quand c'était possible, mais à part ça :
    J'appuie fortement ce que dit kadreg, note quand même que faire des free n'accelerera pas la vitesse d'exécution (à moins que tu ne fasse swapper ton ordi à force de ne rien libérer ;).

    - A quoi faut-il faire spécialement attention ?
    Aux nombre d'appels des constructeurs/destructeurs, surtout si ils font tous des new/delete
    A bien inliner les fonctions qui valent le coup
    A passer par référence les paramètres qui sont des structures, même si tu n'as pas l'utilité d'un passage par référence

    - quelle est la commande pour mesurer le temps d'exécution d'une partie particulière du programme ?
    gprof. Tu compiles avec "g++ -g -pg" puis tu tapes "gprof gmon.out". Tu obtiendras les temps passés dans chaque fonction et le nombre d'appel, etc... (man gprof pour plus de détails). Note que gprof ne voit pas les fonctions qui one été inlinées.
    Sinon si tu veux une bonne précision (ie au cycle d'horloge près) tu peux utiliser les time stamp counters des cpus x86 pentium et supérieurs, mais il faudra mettre un peu les mains dans le cambouis pour les lire, ou bien trouver une lib qui le fait.

    - quels sont les trucs à savoir ?
    Les options de g++ à utiliser (par exemple, comment casser le respect de la norme ieee sur les flottants au profit de la vitesse d'exécution, à savoir avec g++ -ffast-math -mno-ieee-fp, ou comment optimiser pour ton architecture : -march=i686 pour les pentium pro, -msse voire -msse2 pour générer du code flottant qui utilise le SSE au lieu du 387)
    Aux problèmes de cache : si tu as des données assez importantes, il faut surveiller l'utilisation de ton cache, et en particulier à quelle vitesse les infos qu'il contient sont remplacées (cache trashing).
    Ne pas se tromper de niveau d'optimisation : si ton algo est en o(n^3), cherches en plutôt un avec une complexité inférieure avant de te lancer dans des optimisations à tout va.
    Ne pas se tromper de structures de données : de la même manière précédemment, tu peux dans certains algos baisser la complexité et donc accélérer l'exécution avec des choses simples comme les listes triées par exemple.
    • [^] # Re: Optimiser un programme C++

      Posté par  (site web personnel, Mastodon) . Évalué à 1.

      Merci pour toutes ces infos ! J'essaie gprof, mais il ne trouve aucun gmon.out ! :(
      J'ai aussi ajouté, comme recommandé dans le man, -fprofile-arcs à ma compil (j'utilise g++3.2) mais rien ne change :(

      Mes livres CC By-SA : https://ploum.net/livres.html

      • [^] # Re: Optimiser un programme C++

        Posté par  (site web personnel) . Évalué à 1.

        - tu compiles avec -g -pg
        - tu exécutes ton code (essaye de trouver un cas typique)
        - tu trouveras normalement un gmon.out dans le répertoire courant
      • [^] # Re: Optimiser un programme C++

        Posté par  (site web personnel) . Évalué à 2.

        Pour que ton executable te produise un gmon.out, il faut que tu compiles _et _ que tu link ton executable avec l'option -pg. Si tu fais l'un sans l'autre (erreur commune), tu n'auras pas de gmon.out.

        En gros:

        Tu compiles avec: $(CXX) $(CXXFLAGS) -pg -c -o plop.o plop.cpp
        Tu linkes avec: $(CXX) -pg -o plop plop.o
        • [^] # Re: Optimiser un programme C++

          Posté par  (site web personnel, Mastodon) . Évalué à 1.

          j'ai juste ajouté, dans mon makefile :

          # Définitions
          CC=g++
          CFLAGS= -g -pg

          J'essaye en rajoutant
          LDIRS= -pg ?

          Mes livres CC By-SA : https://ploum.net/livres.html

        • [^] # Re: Optimiser un programme C++

          Posté par  (site web personnel, Mastodon) . Évalué à 1.

          En fait, j'ai rajouté :

          LFLAGS= -pg

          et
          Compilation :
          $(CC) $(CFLAGS) $(IDIRS) -c $<

          Construction :
          $(CC) $(LFLAGS) -o projet $(OBJS) $(LDIRS) $(LIBS)

          Mes livres CC By-SA : https://ploum.net/livres.html

          • [^] # Re: Optimiser un programme C++

            Posté par  (site web personnel, Mastodon) . Évalué à 2.

            ça marche ! Genial ! :)
            Mais comment je fais pour décripter ça :

            index % time self children called name
            0.00 0.00 25079300/25079300 (3)
            [1] 100.0 7.74 109.59 25079300 data_start [1]
            109.59 0.00 683449164/1383110750 _fini [2]
            -----------------------------------------------
            10169489 _fini [2]
            0.00 0.00 699661586/1383110750 (3)
            109.59 0.00 683449164/1383110750 data_start [1]
            [2] 93.4 109.59 0.00 1383110750+10169489 _fini [2]
            10169489 _fini [2]

            Mes livres CC By-SA : https://ploum.net/livres.html

            • [^] # Re: Optimiser un programme C++

              Posté par  (site web personnel) . Évalué à 3.

              gprof te genere un "flat profile" des fonctions appelées dans ton programme. Les divers champs du tableau te renseignent sur le pourcentage pris par la fonction x, le temps cumulé dans ton programme, son temps d'execution propre total durant le run, temps propre d'execution pour un appel, le nombre d'appels faits a cette fonction, et le biensur le nom de ta fonction.

              Un adage plutot vérifié veut que tu concentres tes efforts d'optimisation sur les 5% des fonctions qui te bouffent en general les 95% du temps d'execution. C'est un peu éxagéré comme conseil mais il est vrai en général qu'un petit nombre de fonctions appelées très souvent dans un programme, jouent ainsi un role plus que dominant sur le temps d'execution total. Ainsi si tu optimises ces fonctions critiques, tu donneras un bon coup de speed a ton appli.

              En gros mieux vaut optimiser une fonction X appelée 10000 pour gagner 1ms par appel (10s au total) que d'optimiser une fonction appelée 5 fois de 1s par appel (5s au total).
    • [^] # Re: Optimiser un programme C++

      Posté par  . Évalué à 1.

      A bien inliner les fonctions qui valent le coup
      Il est important d'inliner les petites fonctions pour les mettres dans les grandes (surtout que gcc s'en sort tres mal tout seul).
      Ne pas oublier qu'une fonction pour etre inliner doit etre "vue" par le code qui l'utilise, donc elle doit etre incluse dans un fichier .hh par exemple.

      A passer par référence les paramètres qui sont des structures, même si tu n'as pas l'utilité d'un passage par référence
      Par reference ou via un pointeur. Le passage par reference t'informant que le pointeur qu'on te passe ne doit pas etre detruit (par convention).

      Je rajouterais mettre le mot clef const le plus souvent possible, ca permet de plus facilement detecter les alias memoires dans certain cas et facilite un peu la vie au compilo.

      Enfin de maniere general utilise des containers de la STL plutot que tes propres types, car ceci sont tres efficaces. Si jamais tu manipules des listes verifient que tu as vraiment besoin de pouvoir ajouter en tete (push_front), si ce n'est pas le cas prefere l'utilisation du container vector plutot que list (Il gere les donnees sous forme de tableau linaire en memoire, ce qui ameliore les perfs au final).
      De plus si tu connais la taille a l'avance de tes tableaus profites-en pour le specifier des le depart, ca fait un gain de temps en limitant les malloc.

      Enfin de maniere generale evitent la construction/destruction d'objet dans tes boucles critiques (ainsi que des appels systemes).
  • # Re: Optimiser un programme C++

    Posté par  . Évalué à 1.

    Compile ton programme avec les options de profilage (-pg pour gcc/g++ de mémoire). Ensuite un coup de gprof te permettra de voir quelles sont les parties de ton programme qui prennent le plus de temps.

    Bien choisir ses algorithmes est le plus important.

    Utiliser les bonnes options de compilation et voir si elles ont un effet ou non sur le temps d'exécution (-O2, -funroll-loops, -fomit-frame-pointers, etc. voir la doc de gcc).
  • # autre chose

    Posté par  . Évalué à 1.

    evite la resolution tardive (le polymorphisme) c'est agreable a concevoir mais c'est tres lent. Il vaut mieux utiliser des references plutot que des pointeurs.

    Exemple: B est sous-classe de A.

    A * toto;
    [...]
    toto = new B();
  • # Re: Optimiser un programme C++

    Posté par  . Évalué à 3.

    Je ne l'ai pas encore vu dans les commentaires, je signale donc l'existence de l'excellent Valgrind. À associer à kcachegrind pour exploiter graphiquement les résultats.

    Voila la description debian de Valgrind :


    Description: A memory debugger for x86-linux
    Valgrind is a GPL'd tool to help you find memory-management problems in your programs. When a program is run under Valgrind's supervision, all reads and writes of memory are checked, and calls to malloc/new/free/delete are intercepted.
    .
    Valgrind can debug more or less any dynamically-linked ELF Linux x86 executable, without modification, recompilation, or anything, as long as it contains only classic x86 code (MMX/SSE/SSE2/3DNow! largely unsupported for the moment). There is experimental support for programs using libpthread.
    .
    A satellite program, cachegrind, can be used for processor-level (simulated) cache analysis.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.