Votre question est l'une des questions qui n'a pas de réponse que l'on pourrait qualifier de "vérité absolue". L'overhead d'un appel de fonction normal dépend de trois facteurs :
-
Le CPU. L'overhead des CPU x86, PPC et ARM varie beaucoup et même si vous restez sur une seule architecture, l'overhead varie également beaucoup entre un Intel Pentium 4, un Intel Core 2 Duo et un Intel Core i7. L'overhead peut même varier sensiblement entre un processeur Intel et un processeur AMD, même si les deux fonctionnent à la même vitesse d'horloge, car des facteurs tels que la taille du cache, les algorithmes de mise en cache, les modèles d'accès à la mémoire et l'implémentation matérielle de l'opcode d'appel lui-même peuvent avoir une influence considérable sur l'overhead.
-
L'ABI (Application Binary Interface). Même avec le même processeur, il existe souvent différentes ABI qui spécifient comment les appels de fonction passent les paramètres (via les registres, via la pile ou via une combinaison des deux) et où et comment l'initialisation et le nettoyage du cadre de la pile ont lieu. Tout ceci a une influence sur l'overhead. Différents systèmes d'exploitation peuvent utiliser différentes ABI pour la même unité centrale ; par exemple, Linux, Windows et Solaris peuvent tous trois utiliser une ABI différente pour la même unité centrale.
-
Le compilateur. Le respect strict de l'ABI n'est important que si les fonctions sont appelées entre des unités de code indépendantes, par exemple si une application appelle une fonction d'une bibliothèque système ou si une bibliothèque utilisateur appelle une fonction d'une autre bibliothèque utilisateur. Tant que les fonctions sont "privées", c'est-à-dire non visibles en dehors d'une bibliothèque ou d'un binaire donné, le compilateur peut "tricher". Il peut ne pas suivre strictement l'ABI mais utiliser des raccourcis qui permettent d'appeler les fonctions plus rapidement. Par exemple, il peut passer les paramètres dans un registre au lieu d'utiliser la pile ou il peut sauter la configuration et le nettoyage de la trame de la pile si ce n'est pas vraiment nécessaire.
Si vous voulez connaître l'overhead pour une combinaison spécifique des trois facteurs ci-dessus, par exemple pour Intel Core i5 sur Linux en utilisant GCC, la seule façon d'obtenir cette information est de comparer la différence entre deux implémentations, l'une utilisant des appels de fonction et l'autre où vous copiez le code directement dans l'appelant ; de cette façon, vous forcez l'inlining à coup sûr, puisque la déclaration inline n'est qu'une indication et ne conduit pas toujours à l'inlining.
Cependant, la vraie question ici est : Le montant exact des frais généraux a-t-il vraiment de l'importance ? Une chose est sûre : Un appel de fonction a toujours une surcharge. Il peut être petit, il peut être grand, mais il existe à coup sûr. Et aussi petit soit-il, si une fonction est appelée assez souvent dans une section critique pour les performances, l'overhead aura une certaine importance. L'alignement rend rarement votre code plus lent, à moins que vous n'en fassiez trop ; il rendra cependant le code plus gros. Les compilateurs d'aujourd'hui sont plutôt bons pour décider eux-mêmes de l'opportunité d'une mise en ligne ou non, de sorte que vous n'avez pratiquement jamais à vous creuser la tête à ce sujet.
Personnellement, j'ignore complètement l'inlining pendant le développement, jusqu'à ce que j'ai un produit plus ou moins utilisable que je peux profiler et seulement si le profilage me dit, qu'une certaine fonction est appelée très souvent et aussi dans une section critique de l'application, alors j'envisagerai le "force-inlining" de cette fonction.
Jusqu'à présent ma réponse est très générique, elle s'applique aussi bien au C qu'au C++ et à l'Objective-C. En guise de conclusion, permettez-moi de dire quelque chose sur le C++ en particulier : Les méthodes virtuelles sont des appels de fonction indirects doubles, ce qui signifie qu'elles ont un coût d'appel de fonction plus élevé que les appels de fonction normaux et qu'elles ne peuvent pas être intégrées. Les méthodes non virtuelles peuvent être inlined par le compilateur ou non, mais même si elles ne le sont pas, elles sont toujours beaucoup plus rapides que les méthodes virtuelles, donc vous ne devriez pas rendre les méthodes virtuelles, à moins que vous n'ayez vraiment l'intention de les surcharger ou de les faire surcharger.
0 votes
Vote de clôture pour cause de "trop large". On ne peut pas vraiment répondre à cette question de manière sensée. Cela dépend du compilateur, de la détection des points chauds, du processeur (mise en cache, exécution spéculative, mise en mémoire tampon des cibles de branchement), et de nombreux autres facteurs.