Vous pourrez peut-être convaincre votre collègue avec des raisons techniques que le compilateur peut intégrer pour lui, donc cette "optimisation" au niveau de la source n'est pas utile.
J'espère que vous exagérez ce qu'ils ont dit à propos de la méthode de 3000 lignes la plus optimisée possible , ou bien votre collègue n'a probablement aucune idée de l'optimisation des performances et ne se soucie que de quelque chose qu'il a lu une fois. Les personnes qui pensent savoir quelque chose mais ne comprennent pas vraiment sont parfois les plus difficiles à convaincre. J'ai eu plusieurs échanges dans des commentaires de débordement de pile avec des gens refusant de croire qu'ils avaient tort, mais incapables de donner une explication technique cohérente qui avait du sens.
En tant qu'expert en optimisation asm (SO badges or dans [x86], [assembly], [performance], [sse] tags, etc.), je peux vous dire qu'il est presque impossible que cette fonction soit "la plus optimisée possible", même si votre collègue a passé des années à la profiler et à la régler ( sur un matériel spécifique? avec un système d'exploitation et une version de compilateur spécifiques?) Une fonction aussi grande aura toujours de la place pour de petits ajustements (ou de nouvelles idées pour de grands changements) qui pourraient la rendre plus rapide, ou plus petite (code machine) à la même vitesse (peut-être plus conviviale pour l'hyperthreading pour faire le même travail avec moins d'instructions) .
Je ne pense pas que le compilateur C # + JIT soit si mauvais qu'il ne puisse pas appeler la méthode en ligne pour vous, surtout s'ils n'ont qu'un seul site d'appel . Je ne connais pas C # (principalement C et C ++), mais a-t-il quelque chose qui ressemble à une fonction non membre statique en ligne
que le compilateur peut intégrer au lieu d'émettre un stand -alone définition pour, et le fera même si la fonction est large? Ou quelque chose comme GNU C __attribute __ ((always_inline))
? Votre collègue pourrait les utiliser pour avoir l'impression de bénéficier de l'optimisation qu'il juge importante sans que la source ne soit en désordre.
Mais plus important encore, "être optimisé" ne vaut un compromis en termes de lisibilité que lorsque la version de base simple (que vous avez écrite comme point de départ et pour comparer la version optimisée) est plus lente que vous le souhaitez fort>. Vous ne pouvez pas dire si vous optimisez réellement quoi que ce soit si vous n'avez pas de point de départ à comparer, et ainsi juger de la lisibilité ou de la taille du code machine / de l'empreinte du cache d'instructions par rapport à l'accélération.
Écrire une version "optimisée" moins lisible sans une base de référence simple est généralement une erreur , à moins que vous ne pensiez déjà savoir par expérience comment la version simple se compilerait et qu'elle ne serait pas efficace assez. Habituellement, vous avez une version simple dans le cadre d'un test unitaire pour une version déroulée / vectorisée manuellement. (Ce cas d'inclusion manuelle est peut-être différent, cependant. Cela ne rend pas un élément de logique individuel plus complexe ou "étrangement" implémenté. Ou est-ce le cas? Y a-t-il une optimisation manuelle entre les blocs?)
Inlining Cela en vaut souvent la peine pour les petites fonctions, mais appeler un gros bloc de code à partir de plusieurs sites d'appels n'utilise qu'une seule fois l'empreinte du cache d'instructions. Cependant, cela paie les frais généraux d'appel de fonction à chaque fois, donc le microbenchmarking d'une seule fonction, sans le contexte complet du programme, peut donner une belle apparence à l'inlining et au déroulement excessifs. Habituellement, nous allons bien laisser la décision aux heuristiques modernes du compilateur; ils sont généralement assez bien réglés, surtout s'ils peuvent effectuer une optimisation guidée par profil pour trouver des boucles qui sont réellement chaudes. (Les compilateurs JIT fonctionnent au moment de l'exécution, ils ont donc des données de profilage s'ils souhaitent les utiliser. Habituellement, en créant une version pas entièrement optimisée ou en interprétant au début, puis en utilisant des données de profilage pour des méthodes virtuelles en ligne spéculatives et des choses comme ça. / p>
Parfois, l'optimisation ne nuit pas à la lisibilité, mais dans ce cas, c'est clairement le cas.
En C ++, j'écris souvent de petites fonctions d'aide static inline
qui seront intégrées dans une fonction plus grande dont j'optimise la merde avec les intrinsèques SIMD. Quand je regarde l'asm généré par le compilateur, il n'y a exactement aucun inconvénient dans l'efficacité du code machine, et un bon avantage dans la lisibilité de la source. Aucune définition autonome n'apparaît nulle part dans l'exécutable pour ces fonctions d'assistance, donc elles ne gonflent même pas l'exécutable.
Si vous voulez insister sur le problème, demandez à votre collègue s'il a a regardé la sortie asm du compilateur JIT pour sa méthode et l'a profilée, et a trouvé que ces gros blocs conditionnels permettaient au compilateur d'optimiser d'une manière qu'il ne pouvait pas avec l'inlining.
Être conscient de ce que votre compilateur + le matériel peut faire efficacement n'est pas toujours une mauvaise chose, si vous laissez cela informer vos choix de codage quand cela ne nuit pas à la lisibilité.
Il est tentant de se laisser entraîner dans l'optimisation de quelque chose qui n'a pas besoin d'être optimisé . Surtout si vous ne pensez à optimiser pour la vitesse de cette fonction que si elle a été appelée dans une boucle chaude , alors qu'elle ne sera pas dans une boucle chaude. S'il est appelé rarement, le cache de code peut être froid, donc compact est préférable. (Moins de lignes de code de cache à charger à partir de la mémoire principale.)
Ce type d'argument n'aide que si vous pouvez exclure toutes les fonctions d'assistance courantes de cette méthode de 3000 lignes. Mettre chaque bloc dans une fonction distincte ne réduira pas le code machine. Cela pourrait rendre la logique de décision pour la fonction à distribuer plus localisée, ce qui entraînerait une empreinte de cache I plus petite pour cela. Et peut-être moins de 4k pages touchées / chargées à partir du disque / i-TLBfootprint.