IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Vérifier qu'une fonction "inline" l'a bien été.


Sujet :

C++

  1. #1
    Membre régulier
    Inscrit en
    Septembre 2010
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 73
    Points : 90
    Points
    90
    Par défaut Vérifier qu'une fonction "inline" l'a bien été.
    Lorsqu'on indique qu'une fonction est inline c'est pour placer le code là où on en à besoin à la compilation et ne pas avoir à l'appeler pendant l’exécution (entre autres).
    J'ai lu un peu partout qu'un compilateur pouvait faire ce qu'il voulait d'une fonction inline, l'interpréter comme bon lui semble.

    Donc ma question, comment fait-on pour savoir comment une fonction inline a été interprétée ? Si le programme l'appelle ou pas ?

    Merci.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonsoir,

    il y a peut être une approche plus fine mais une manière simple de le vérifier est de comparer les temps CPU avec et sans le mot-clé inline.

    Je ne suis pas un grand expert des compilateurs mais il est probable que tous ne prennent pas la même décision en fonction du contenu d'une fonction.

    Dans les environnement de développement, il est parfois proposé des options pour forcer un peu le compilateur; c'est le cas dans Visual Studio par exemple.

  3. #3
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Je ne suis pas un grand expert des compilateurs mais il est probable que tous ne prennent pas la même décision en fonction du contenu d'une fonction.
    Ce n'est pas probable, c'est certain, sauf dans certains cas où c'est obligé.

    Visual Studio va par exemple inliner de force tes fonctions inline même en Debug de manière à ce que ce soit plus rapide mais aussi plus dur a débugger si tu passe par ces fonctions. En revanche, que ce soit inline ou pas, une fonction membre déclarée dans un header sera forcément inliné en Release.

    Gcc a un comportement différent. J'en connais d'autres aussi.

    Bref, ce qui est conseillé c'est de ne pas inliner du tout sauf :

    1. on veut écrire une fonction libre qui doit rester dans le header sans être dans un cpp (par exemple n'importe quelle fonction libre template)
    2. on veut que le processeur fasses tout ce qu'il peut pour optimiser la dite fonction à l'appel.

    La seconde raison est valide seulement dans du code assez "bas niveau" comme une classe représentant un type de nombre ou encore un vecteur mathématique(géométrique?). Même en debug, il faut que les manipulations soient rapide, et comme elles sont courtes on a rarement besoin du pas a pas pour voir comment elles marchent.

    Donc le conseil général c'est :
    1. n'utilise pas les inline si tu peux
    2. si tu as de sproblèmes de performance liés a des fonctions qui pourraient être inline, TEST avec inline, voir comment ton compilo va se comporter
    3. si tu envisages d'utiliser inline à cause de résultats de 2., alors fait en sorte de connaitre le comportement spécifique de ton compilateur. Généralement c'est spécifié dans un document, si ça ne l'est pas TEST ENCORE.

    Donc la plupart du temps, ignorer inline.


    Pour répondre à la question, au pas à pas d'un débuggeur (gdb ou Visual Studio) tu peux savoir si le code a été inliné selon si tu as les infos dispo ou pas. Mais c'est moins fiable que de regarder le code assembleur généré.
    Perso, j'hésite de me poser la question, je ne fais que TESTER quand je veux utiliser inline, voir ce que ça donne, sauf quand c'est du template (qui devra être inliné de toutes façons.

  4. #4
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonsoir Klaim,

    je vais rebondir un peu sur tes propos parce que je ne comprends pas tout.

    Citation Envoyé par Klaim Voir le message
    Visual Studio va par exemple inliner de force tes fonctions inline même en Debug de manière à ce que ce soit plus rapide mais aussi plus dur a débugger si tu passe par ces fonctions.
    En quoi est-ce plus dur à deboguer? Je n'ai jamais eu de problème.
    Au fait, tu peux désactiver la prise en compte du mot-clé inline en debug et pas en release si tu veux.

    Citation Envoyé par Klaim Voir le message
    En revanche, que ce soit inline ou pas, une fonction membre déclarée dans un header sera forcément inliné en Release.
    Je me trompe peut-être mais il me semblait que les fonctions membre inline doivent forcément être déclarées et définies dans un header (dans un cpp ça ne compile pas normalement). De plus, dans l'exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Foo
    {
    public:
        int fun1() { return _myint;};
        int fun2();
        int fun3();
    private:
        int _myint;
    };
     
    inline int Foo::fun2() 
    { 
        return _myint;
    }
     
    int Foo::fun3() 
    { 
        return _myint;
    }
    il me semble que la fonction fun3 n'est inline.

    Du coup la première raison que tu donnes pour décider d'utiliser inline me paraît discutable mais encore une fois je peux me tromper. Ce qu'on m'a toujours appris c'est qu'il ne faut utiliser inline que pour les fonctions vérifiant ces conditions :
    1. appelées souvent dans le code (inline permet ainsi une augmentation significative des performances),
    2. contenant peu de lignes de code (pour ne pas faire trop grossir la taille du code compilé)

    Je n'ai jamais vérifié mais il me semble également que le mot-clé inline est systématiquement refusé pour les fonctions contenant au moins une boucle (quel que soit le compilateur). Est-ce que quelqu'un en saurait plus là-dessus?

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par Aleph69 Voir le message
    Je me trompe peut-être mais il me semblait que les fonctions membre inline doivent forcément être déclarées et définies dans un header (dans un cpp ça ne compile pas normalement).
    Je n'ai pas vérifié dans la norme mais certains compilateurs permettent de définir la fonction inline dans le .cpp. Simplement l'inlining ne se fera que pour les appels après la définition de la fonction inline.

    Citation Envoyé par Aleph69 Voir le message
    De plus, dans l'exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Foo
    {
    public:
        int fun1() { return _myint;};
        int fun2();
        int fun3();
    private:
        int _myint;
    };
     
    inline int Foo::fun2() 
    { 
        return _myint;
    }
     
    int Foo::fun3() 
    { 
        return _myint;
    }
    il me semble que la fonction fun3 n'est inline.
    fun3 n'est pas inline et va même provoquer une erreur d'édition de lien si le fichier d'en-tête est inclus par plusieurs unité de compilation (multiple définition).

    Citation Envoyé par Aleph69 Voir le message
    Ce qu'on m'a toujours appris c'est qu'il ne faut utiliser inline que pour les fonctions vérifiant ces conditions :
    1. appelées souvent dans le code (inline permet ainsi une augmentation significative des performances),
    2. contenant peu de lignes de code (pour ne pas faire trop grossir la taille du code compilé)
    Et puis les fonctions définies dans le fichier d'en-tête pour éviter les problèmes de multiple définition.

    Citation Envoyé par Aleph69 Voir le message
    Je n'ai jamais vérifié mais il me semble également que le mot-clé inline est systématiquement refusé pour les fonctions contenant au moins une boucle (quel que soit le compilateur). Est-ce que quelqu'un en saurait plus là-dessus?
    Perso, je ne sais pas. Je n'ai jamais vérifié.

    @PO: comment savoir si les fonctions sont inlinées ? Un indice (pas toujours vrai) : vérifier les symboles de l'exécutable (fichier map). Si la fonction n'y est pas, c'est qu'elle a été inlinée partout où elle était utilisée.

  6. #6
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Salut,

    Citation Envoyé par 3DArchi Voir le message
    Et puis les fonctions définies dans le fichier d'en-tête pour éviter les problèmes de multiple définition.
    Dans quel cas a-t-on besoin de définir dans un header une fonction qui n'est pas inline? Il y a bien les fonctions template (inline ou non) mais à part ça je ne vois pas.

  7. #7
    Membre régulier
    Inscrit en
    Septembre 2010
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 73
    Points : 90
    Points
    90
    Par défaut
    Merci messieurs(-dames) !

    Je vais tester la technique des breakpoints, des symboles et s'il le faut avec le temps CPU. :]

  8. #8
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    Salut,
    Dans quel cas a-t-on besoin de définir dans un header une fonction qui n'est pas inline? Il y a bien les fonctions template (inline ou non) mais à part ça je ne vois pas.
    Une fonction dans le namespace non-nommé ? (donc une fonction statique). Elle peut être de taille importante, et une partie du code peut être défini selon certains valeurs de macros.

    Bon, je joue un peu à l'avocat du diable là

    Le fait est qu'on peut le faire. L'utilité, après... Tu sais, on peut faire des tas de choses qui sont inutiles ou dangereuses en C++
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  9. #9
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Je suis allé faire un petit tour par la faq car je ne savais pas qu'on pouvait faire des espaces de nom anonymes... et là je viens d'apprendre que je faisais du C sans le savoir à chaque fois que j'utilisais le mot-clé static!

  10. #10
    Membre régulier
    Inscrit en
    Septembre 2010
    Messages
    73
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 73
    Points : 90
    Points
    90
    Par défaut
    Ben voilà, le grande gagnante est la méthode du CPU.
    J'ai crée 2 fonctions "maFonction1" et "maFonction2" qui font la même chose, une en inline et l'autre non.
    Et je les ai lancée dans une boucle. L'inline l'emporte évidemment haut la main.

    Merci à tous.

  11. #11
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Et ouai, faut tester. Cela dit, ne t'attends pas a avoir tout le temps le même résultat, ça dépends fortement du context d'appel et du code de la fonction.

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,

    J'imagine que les comparaisons se font sur des versions release avec les mêmes options d'optimisations. Et pour renforcer sa conviction, les deux versions ont été exécutées plusieurs fois.

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    En fait, je ne suis pas loin de penser que l'intérêt du mot clé inline est bien plus fonctionnel (pour éviter à l'éditeur de liens de s'étonner de trouver plusieurs fois la définition d'une seule et même fonction) que réellement pratique (espoir de gains de performances).

    Je m'explique :

    L'appel d'une fonction (non inline) ne prend malgré tout pas des masses de temps: il s'agit "simplement" de sauvegarder un contexte (adresse courante d'exécution, plus l'une ou l'autre info) avant de sauter à une adresse d'exécution différente, et de revenir au point de départ une fois la fonction achevée.

    Cela ne tourne quand même qu'aux alentours de "quelques" cycles d'horloge, que diable!

    Pour obtenir un gain significatif (susceptible d'être compté ne serait-ce qu'en secondes) uniquement sur ces quelques cycles, il faudrait vraiment que la fonction inlinée soit appelée un très grand nombre de fois (en dessous de 50 000 fois, je ne crois même pas que l'on pourrait atteindre la seconde ! )

    Et il ne faut pas oublier le revers de la médaille qui est l'augmentation du code compilé (même si, dans certains cas, elle peut être considérée comme négligeable )

    Bon, si la fonction en question est simplement sensée renvoyer un entier ou une référence vers un objet quelconque, cela peut se justifier, et nous pouvons estimer qu'elle sera peut etre effectivement inlinée pour autant que nous ayions la certitude qu'il n'y aura pas une copie cachée dans le renvois de l'objet et que les copies cachées éventuelles ne produisent pas un nombre d'instruction processeur trop important

    Je voudrais en profiter pour revenir sur une erreur qui a été commise par aleph:
    contenant peu de lignes de code (pour ne pas faire trop grossir la taille du code compilé)
    Le nombre de lignes de code n'a strictement rien à voir car la notion même de ligne n'apparait pas en C ni en C++ (contrairement au cobol, par exemple) :

    En cobol, tout ce qui dépasse la colonne 80 d'une ligne est considéré comme du commentaire, et il faut expllictement dire que ce qui suit le retour à la ligne fait partie de la même instruction.

    Par contre, pour etre "standard compliant", les compilateurs sont tenu d'accepter au minimum 65 000 caractères sans rencontrer un retour à la ligne, et plusieurs instructions peuvent très bien se retrouver sur une seule et même ligne!

    Nous pouvons par exemple parfaitement envisager d'avoir un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    inline void foo(){for(int i = 0; i< MAXVAL;++i{truc machin; machin.do(); if(machin.bidul()){basard brol; brol.chouette(); /*... */}}}
    qui sera peut etre écrit sur une ligne (même si on le déconseille pour une question de visibilité) et qui sera compris et accepté par le compilateur.

    Cependant, il n'y a vraiment que peu de chances pour qu'il soit effectivement inliné, pour la simple et bonne raison que, une fois converti en instructions processeur, cela représente un nombre d'instructions incitant le compilateur à ne pas l'ininer.

    De même, nous pourrions avoir une seule instruction (complexe) sur plusieurs lignes de code! Il n'est pas rare de rencontrer un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    inline int bar()
    {
        int result = foo( truc.getX(),
                          truc.getY(),
                          bidule.isValid());
        return result;
    }
    simpelment pour "aérer le code" et le rendre plus visible.

    Et il se pourrait même que cette fonction (et toutes celles qui sont appelées, si elle sont déclarées inline) soit inlinée, simplement parce que cela ne correspond qu'à un nombre très restreint d'instruction processeur!

    Tout cela pour marteler une fois de plus un point important : le nombre d'instructions ou de ligne de code n'aura strictement aucune incidence sur l'inlining ou non d'une fonction!

    La seule chose qui aura une (éventuelle) incidence sur se point sera le nombre d'instructions processeur nécessaire à traduire les instructions décrites dans le code.

    Je tiens enfin à rappeler encore une fois qu'il est parfaitement inutile de compter sur l'inlining (dont on n'est pas forcément sur qu'il se fera) pour améliorer les performances d'une application : il y a beaucoup à faire pour améliorer les performances avant d'en arriver à ce point, à commencer par le fait d'améliorer l'ensemble des algorithmes!

    Pour te donner un exemple précis, imaginons les fonctions suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void fonction()
    {
        for(int i = 0; i < MAXFIRST; ++ i)
            fonction1();
    }
    void fonction1()
    {
        for (int i = 0; i< MAXSECOND; ++i)
            fonction2();
    }
    void fonction2()
    {
        for(int i = 0; i< MAXTHIRD; ++1)
            fonction3();
    }
    void fonction3(){/* ...*/}
    le simple fait de repérer dans fonction que tu ne dois pas appeler, pour un i donné, fonction1 te permettra d'éviter au total:
    • un appel à fonction1 soit
    • MAXSECOND appels à fonction2 soit
    • MAXTHIRD * MAXSECOND appels à fonction3
    Je te laisse évaluer le gain que tu pourrais avoir si, au final, tu en arrive à éviter un appel sur deux à fonction1 dans fonction, même si cela doit passer par un test de complexité relative
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  14. #14
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Salut,

    Citation Envoyé par koala01 Voir le message
    Tout cela pour marteler une fois de plus un point important : le nombre d'instructions ou de ligne de code n'aura strictement aucune incidence sur l'inlining ou non d'une fonction!

    La seule chose qui aura une (éventuelle) incidence sur se point sera le nombre d'instructions processeur nécessaire à traduire les instructions décrites dans le code.
    Merci d'avoir corrigé.

    Citation Envoyé par koala01 Voir le message
    En fait, je ne suis pas loin de penser que l'intérêt du mot clé inline est bien plus fonctionnel (pour éviter à l'éditeur de liens de s'étonner de trouver plusieurs fois la définition d'une seule et même fonction) que réellement pratique (espoir de gains de performances).
    Cela ne tourne quand même qu'aux alentours de "quelques" cycles d'horloge, que diable!

    Pour obtenir un gain significatif (susceptible d'être compté ne serait-ce qu'en secondes) uniquement sur ces quelques cycles, il faudrait vraiment que la fonction inlinée soit appelée un très grand nombre de fois (en dessous de 50 000 fois, je ne crois même pas que l'on pourrait atteindre la seconde ! )

    Je tiens enfin à rappeler encore une fois qu'il est parfaitement inutile de compter sur l'inlining (dont on n'est pas forcément sur qu'il se fera) pour améliorer les performances d'une application : il y a beaucoup à faire pour améliorer les performances avant d'en arriver à ce point, à commencer par le fait d'améliorer l'ensemble des algorithmes!
    En fait ça dépend vraiment des applications. Pour les miennes, je manipule des grosses matrices de plusieurs milliers ou millions de lignes/colonnes, des vecteurs dont la longueur est du même ordre de grandeur, au sein d'algorithmes itératifs qui eux-mêmes nécessitent un nombre d'itérations du même ordre de grandeur. Faire de l'expansion de code dans ce genre de calcul a vraiment un intérêt.

    Les derniers exemples que tu donnes contiennent des boucles : je suppute que l'expansion de ces codes te sera refusée par ton compilateur de toute manière. L'expansion concernant essentiellement des fonctions très simples, typiquement des accesseurs/mutateurs, il n'y a pas grand chose à optimiser d'un point de vue purement algorithmique.

  15. #15
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par koala01 Voir le message
    L'appel d'une fonction (non inline) ne prend malgré tout pas des masses de temps: il s'agit "simplement" de sauvegarder un contexte (adresse courante d'exécution, plus l'une ou l'autre info) avant de sauter à une adresse d'exécution différente, et de revenir au point de départ une fois la fonction achevée.

    Cela ne tourne quand même qu'aux alentours de "quelques" cycles d'horloge, que diable!

    Pour obtenir un gain significatif (susceptible d'être compté ne serait-ce qu'en secondes) uniquement sur ces quelques cycles, il faudrait vraiment que la fonction inlinée soit appelée un très grand nombre de fois (en dessous de 50 000 fois, je ne crois même pas que l'on pourrait atteindre la seconde ! )

    Et il ne faut pas oublier le revers de la médaille qui est l'augmentation du code compilé (même si, dans certains cas, elle peut être considérée comme négligeable )
    C'est parfois un peu plus compliqué. Un appel peut coûter chez au regard d'un inlining et le code inliné n'est pas forcément plus gros que le code non inliné. Cela car lorsque le code est inliné à la place de l'appel de la fonction, le compilateur peut réaliser des optimisations supplémentaires aboutissant à un code plus petit et plus rapide au delà du simple coût d'appel.

  16. #16
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par koala01 Voir le message
    L'appel d'une fonction (non inline) ne prend malgré tout pas des masses de temps: il s'agit "simplement" de sauvegarder un contexte (adresse courante d'exécution, plus l'une ou l'autre info) avant de sauter à une adresse d'exécution différente, et de revenir au point de départ une fois la fonction achevée.
    L'inlining ne gagne pas simplement le coût d'appel d'une fonction, mais aussi les possibilités d'optimisation supplémentaires liées au fait que la fonction soit directement lisible. Exemple bête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int f(int i)
    {
      if(i>20)
        // ...
      else
        //...
    }
     
    int g(int i)
    {
      if(i>30) {return f(i);}
      return 0;
    }
    Le fait d'inliner permettra la simplification de f dans ce contexte.

    Citation Envoyé par koala01 Voir le message

    Cela ne tourne quand même qu'aux alentours de "quelques" cycles d'horloge, que diable!

    Pour obtenir un gain significatif (susceptible d'être compté ne serait-ce qu'en secondes) uniquement sur ces quelques cycles, il faudrait vraiment que la fonction inlinée soit appelée un très grand nombre de fois (en dessous de 50 000 fois, je ne crois même pas que l'on pourrait atteindre la seconde ! )
    Si le reste du corps de f ne coûte lui aussi que quelques cycles d'horloge, quelques cycles gagnés, c'est important.
    Citation Envoyé par koala01 Voir le message
    Et il ne faut pas oublier le revers de la médaille qui est l'augmentation du code compilé (même si, dans certains cas, elle peut être considérée comme négligeable )
    Les seules fois où j'ai pu constater de visu une modification de la taille du code compilé liée à l'inlining, c'était une diminution, parfois drastique.
    Ceci est en particulier notable dans le code générique, où l'on a souvent tout un empilement de fonctions qui ne font pas grand'chose. Si cet empilement est précompilé grâce à l'inlining, on gagne pas mal de taille de code. Disons que l'inlining combat le code bloat des templates.
    Citation Envoyé par koala01 Voir le message
    Cependant, il n'y a vraiment que peu de chances pour qu'il soit effectivement inliné, pour la simple et bonne raison que, une fois converti en instructions processeur, cela représente un nombre d'instructions incitant le compilateur à ne pas l'ininer.
    Il peut être intéressant d'inliner des grosses fonctions, comportant une grand nombre d'instructions. L'exemple typique est la fonction qui ne serait appelée que par un seul point dans le code.
    Citation Envoyé par Aleph69 Voir le message
    Les derniers exemples que tu donnes contiennent des boucles : je suppute que l'expansion de ces codes te sera refusée par ton compilateur de toute manière.
    Je ne vois pas pourquoi un compilateur refuserait l'inlining d'une boucle. Il y a certainement des cas où ça peut avoir des gains intéressants. Par exemple, sous réserve qu'il n'y ait pas d'aliasing :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void fboucle(int n)
    {
      for (int i=0 ; i<n ; ++i) { f(i);}
    }
     
    void gboucle(int n)
    {
      for (int i=0 ; i<n ; ++i) { g(i);}
    }
     
    void h(int n)
    {
      fboucle(n);
      gboucle(n);
    }
    Si les appels à fboucle et gboucle sont inlinés, le code de h pourra ensuite devenir équivalent à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void h(int n)
    {
      for (int i=0 ; i<n ; ++i)
      {
        f(i);
        g(i);
      }
    }
    Et on aura gagné du temps non négligeable si f et g sont petits.



    Par contre, même si je me base beaucoup sur l'inlining quand j'écris du code (ce qui se traduit par le fait que je n'hésite pas à écrire des fonctions), j'utilise assez rarement le mot clef inline. Je considère que c'est plus le travail du compilateur que le mien. Bien entendu, si j'ai des problèmes de perfs importants dans du code (suffisamment importants pour qu'on m'alloue du temps pour les régler), que j'ai déjà bien revu mes algorithmes, que le profiling me montre qu'en ajoutant un inline à un endroit, ça s'améliore, je n'hésiterai pas à l'employer. Ça ne m'est tout simplement pas encore arrivé.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  17. #17
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonsoir,

    Citation Envoyé par JolyLoic Voir le message
    Je ne vois pas pourquoi un compilateur refuserait l'inlining d'une boucle.
    Il me semble que c'est ce qui arrive en pratique :
    http://www.daniweb.com/software-deve.../threads/13472

    Si tu connais un compilateur qui accepte l'expansion d'un code contenant une boucle, j'aimerais bien tester.

  18. #18
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Utiliser __forceinline sur MSVC et __attribute__((always_inline)) inline sur GCC-like...
    Boost ftw

  19. #19
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonsoir,

    forcer l'expansion d'un code avec __forceinline ou tout autre option de compilation est fortement déconseillé :
    The __forceinline keyword overrides the cost/benefit analysis and relies on the judgment of the programmer instead. Exercise caution when using __forceinline. Indiscriminate use of __forceinline can result in larger code with only marginal performance gains or, in some cases, even performance losses (due to increased paging of a larger executable, for example).
    Par ailleurs, contrairement à ce qui est suggéré, le compilateur conserve tout de même un certain libre-arbitre :
    The compiler treats the inline expansion options and keywords as suggestions. There is no guarantee that functions will be inlined. You cannot force the compiler to inline a particular function, even with the __forceinline keyword.
    Plus de précisions sur ce dernier point :
    Even with __forceinline, the compiler cannot inline code in all circumstances. The compiler cannot inline a function if:

    1. The function or its caller is compiled with /Ob0 (the default option for debug builds).

    2. The function and the caller use different types of exception handling (C++ exception handling in one, structured exception handling in the other).

    3. The function has a variable argument list.

    4. The function uses inline assembly, unless compiled with /Og, /Ox, /O1, or /O2.

    5. The function is recursive and not accompanied by #pragma inline_recursion(on). With the pragma, recursive functions are inlined to a default depth of 16 calls. To reduce the inlining depth, use inline_depth pragma.

    6. The function is virtual and is called virtually. Direct calls to virtual functions can be inlined.

    7. The program takes the address of the function and the call is made via the pointer to the function. Direct calls to functions that have had their address taken can be inlined.

    8. The function is also marked with the naked __declspec modifier.
    A priori (je n'ai pas testé), on peut forcer l'expansion de code ayant une boucle avec __forceinline mais c'est hors C++ (propriétaire).

    La question est : "existe-t-il un compilateur qui prend en compte le mot-clé inline en présence d'une boucle?"

    J'ai une autre question : que dit la norme à propos du mot-clé inline?

  20. #20
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Aleph69 Voir le message
    J'ai une autre question : que dit la norme à propos du mot-clé inline?
    Que c'est une aide, et non pas une obligation. Le compilateur n'est pas forcé de générer un appel inline à une fonction notée ainsi.

    Au niveau de la norme :

    * la fonction main ne peut pas être inline (ni statique) [3.6.1§3]. For logiquement d'ailleurs.
    * une fonction inline doit être définie dans toutes les unités de compilation ou elle est utilisée (que le compilateur l'inline ou non, qu'elle soit statique ou non) [3.2§3]. Sa définition peut apparaître après sa première utilisation - dès lors qu'une déclaration existe. Cette déclaration peut - ou non - déclarer que la fonction est inline ou non (car cette déclaration ne change pas le linkage) [7.1.1§7].

    Ex:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void func(); // déclaration ; func peut être utilisé [7.1.3§4] ; son linkage est externe [7.1.1]
    ...
     
    void h()
    {
      func();
    }
    ...
    inline void func() // définition
    {
    ...
    }
    * son linkage dépends de la manière dont est définie la fonction (si elle est static inline, elle a un linkage interne, sinon elle a un linkage externe) [7.1.1]. Il y a quelque chose d'important avec les fonctions inline dont le linkage est externe : bien qu'elle doivent apparaître dans toutes les unités de compilation sous la même forme, ces définitions multiples font quand même référence à la même fonction - c'est à dire que son adresse (oui, on peut prendre l'adresse d'une fonction inline et l'appeler via un pointeur de fonction, auquel cas l'appel est bien évidemment non-inline) ne change pas - contrairement à une fonction dont le linkage est interne, c'est à dire limité à une seule unité de compilation (elle possède donc plusieurs adresses si elle est appelée dans plusieurs unités de compilation).

    * Dès lors qu'une fonction avec un linkage externe est déclarée inline dans une unité de compilation, elle doit être déclarée inline dans toutes les unités de compilation où elle est utilisée [7.1.3§4].

    Citation Envoyé par Norme C++, section 7.1.2 §2
    A function declaration (8.3.5, 9.3, 11.4) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [PHP 5.3] [POO] : faire une fonction quote
    Par gwendoline-bricout dans le forum Langage
    Réponses: 7
    Dernier message: 20/02/2014, 10h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo