42 votes

Pourquoi la mise en ligne est-elle considérée plus rapide qu'un appel de fonction?

Maintenant, je sais que c'est parce qu'il n'y a pas la surcharge de l'appel d'une fonction, mais est la surcharge de l'appel d'une fonction vraiment lourd (et de la valeur de la dilatation de l'avoir incorporé) ?

De ce que je me souviens, quand une fonction est appelée, dire que f(x,y), x et y sont poussés sur la pile, et le pointeur de pile sauts à un bloc vide, et commence l'exécution. Je sais que c'est un peu trop simplifié, mais suis-je raté quelque chose? Un peu de pousse et un saut pour appeler une fonction, est-il vraiment beaucoup de frais généraux?

Permettez-moi de savoir si j'oublie quelque chose, merci!

64voto

AndreyT Points 139512

Mis à part le fait qu'il n'y a pas d'appel (et donc pas de frais associés, comme paramètre de préparation avant l'appel et le nettoyage après l'appel), il y a un autre avantage important de l'in-lining. Lorsque le corps de la fonction est inline, c'est le corps peut être ré-interprété dans le contexte spécifique de l'appelant. Cela pourrait permettre immédiatement le compilateur pour plus de réduire et d'optimiser le code.

Pour un exemple simple, cette fonction

void foo(bool b) {
  if (b) {
    // something
  }
  else {
    // something else
  }
}

aura besoin réel de branchement si elle est appelée en tant que non-fonction inline

foo(true);
...
foo(false);

Toutefois, si les appels sont inline, le compilateur sera immédiatement en mesure d'éliminer la ramification. Essentiellement, dans le cas ci-dessus inline permet au compilateur d'interpréter l'argument de fonction comme une constante de compilation (si le paramètre est une constante de compilation) - quelque chose qui n'est généralement pas possible avec les fonctions inline.

Cependant, il n'est pas même à distance se limite à ça. En général, les possibilités d'optimisation de permis de inline sont nettement plus loin. Pour un autre exemple, lorsque le corps de la fonction est incorporé dans le spécifique de l'appelant contexte, le compilateur dans le cas général sera en mesure de propager l'connu aliasing relations présentes dans le code d'appel dans la fonction inline code, rendant ainsi possible d'optimiser le code de fonction mieux.

Encore une fois, les exemples sont nombreux, tous issus de la base fait que inline appels sont immergés dans le spécifique de l'appelant le contexte, ainsi l'activation des différentes inter-contexte optimisations, ce qui ne serait pas possible avec les non-inline calles. Avec l'in-lining, vous obtiendrez de nombreuses versions de l'original de votre fonction, chaque version est adapté et optimisé individuellement pour chaque appelant contexte. Le prix de ce qui est, de toute évidence, le danger potentiel de l'augmentation du code, mais si utilisé correctement, il peut offrir de notables avantages de performance.

27voto

"Un peu de pousse et un saut pour appeler une fonction, est-il vraiment beaucoup de frais généraux?"

Il dépend de la fonction.

Si le corps de la fonction est d'une seule machine, le code de l'instruction, de l'appel et de retour les frais généraux peuvent être beaucoup beaucoup centaine %. Dire 6 fois, à 500% de frais généraux. Ensuite, si votre programme n'est rien mais un gazillion les appels à cette fonction, sans l'in-lining, vous avez augmenté la durée de fonctionnement de 500%.

Cependant, dans l'autre sens inline peut avoir un effet néfaste, par exemple, parce que le code que sans l'in-lining place dans une page de la mémoire qui ne fonctionne pas.

Donc, la réponse est toujours quand il s'agit de l'optimisation, la première de toute MESURE.

Cheers & hth.,

12voto

Pontus Gagge Points 12950

Il n'y a pas d'appel et de la pile de l'activité, ce qui permet d'économiser quelques cycles CPU. Moderne, la CPU, le code de localité est également importante: faire un appel peut vider le pipeline d'instruction et force le PROCESSEUR d'attente pour la mémoire récupérée. Cela compte beaucoup dans les boucles serrées, car la mémoire primaire est beaucoup plus lent que moderne de la CPU.

Cependant, ne vous inquiétez pas au sujet de l'in-lining, si votre code est appelé à quelques reprises dans votre application. Vous inquiétez pas, un lot, si on l'appelle millions de fois pendant que l'utilisateur attend des réponses!

11voto

sbi Points 100828

Le classique du candidat pour inline est un accesseur, comme std::vector<T>::size().

Avec inline permis c'est juste de la récupération d'une variable à partir de la mémoire, probablement une seule et même instruction sur toutes les architectures. Le "peu de pousse et un saut" (plus de retour) est facilement plusieurs fois autant.

Ajoutez à cela le fait que, plus le code est visible à la fois à un optimiseur, le mieux qu'il puisse faire son travail. Avec beaucoup de l'in-lining, il voit beaucoup de code à la fois. Cela signifie qu'il pourrait être en mesure de conserver la valeur dans un PROCESSEUR inscrire, et complètement épargner le coût de voyage de la mémoire. Maintenant, nous pourrions prendre à propos d'une différence de plusieurs ordres de grandeur.

Et puis theres modèle de méta-programmation. Cela se traduit parfois par l'appel de nombreuses petites fonctions récursives, juste pour aller chercher une valeur unique à la fin de la récursivité. (Pensez à récupérer la valeur de la première entrée d'un type spécifique dans un tuple avec des dizaines d'objets.) Avec inline activé, l'optimiseur peut directement accéder à cette valeur (qui, rappelons-le, peut être dans un registre), l'effondrement des dizaines d'appels de fonction en accédant à une seule valeur dans un PROCESSEUR inscrire. Cela peut transformer en un terrible performances de porc dans une belle et rapide du programme.


Le masquage de l'état que des données privées dans les objets (encapsulation) a ses coûts. Inline est une partie de C++ dès le début afin de réduire ces coûts de l'abstraction. À l'époque, les compilateurs ont beaucoup plus de mal à détecter les bons candidats pour inline (et rejeter les mauvais) qu'ils ne le sont aujourd'hui, donc manuellement inline résulté en une grande vitesse gainings.
Aujourd'hui, les compilateurs sont réputés pour être beaucoup plus intelligent que nous sommes sur la ligne. Les compilateurs sont capables de fonctions en ligne automatiquement ou de ne pas les fonctions inline utilisateurs marqués inline, même s'ils le pouvaient. Certains disent que l'in-lining, devrait être laissée à l'compilateur complètement et nous ne devrions même pas pris la peine de marquage fonctions en tant que inline. Cependant, je n'ai pas encore de voir une étude approfondie montrant que ce soit manuellement le faire est toujours en vaut la peine ou pas. Donc pour le moment, je vais continuer à le faire moi-même, et de laisser le compilateur de remplacer que si il pense qu'il peut faire mieux.

5voto

kilotaras Points 1217

laisser

 int sum(const int &a,const int &b)
{
     return a + b;
}
int a = sum(b,c);
 

est égal à

 int a = b + c
 

Pas de saut - pas de frais généraux

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X