Dois-je penser au code machine compilé lorsque j'écris mon code?

20

Par exemple, j'ai le code suivant:

auto z = [](int x) -> int {
    if (x > 0) {
        switch (x) {
            case 2: return 5;
            case 3: return 6;
            default: return 1;
            }
        }
    return 0;
    };

Et plus tard, j'appelle cela plusieurs fois. Dans le code asm, je vois des appels externes avec lambda .... quelque chose ... Cela devient difficile à lire et je pense que cela peut également entraîner des performances. Alors peut-être que je gagne en méta-programmation mais est-ce que je perds en débogage asm et en performances? Dois-je éviter les fonctionnalités du langage moderne, les macros et autres aspects de la méta-programmation pour être sûr en termes de performances et de simplicité de débogage?

cnd
la source
1
Selon la version du compilateur et sa bibliothèque standard fournie, lambda peut en effet être implémenté de manière inefficace. Voir cette question sur Stackoverflow. Cependant, la responsabilité de l'amélioration devrait incomber au fournisseur du compilateur.
rwong
15
Vous ne devriez pas avoir besoin de déboguer le code assembleur, sauf si vous êtes dans le chemin critique des performances. Aussi, "code propre"! = "Bonnes performances".
BЈовић
Corrigez votre indentation s'il vous plaît. J'ai essayé de le faire, mais il semble que vous ne pouvez pas modifier uniquement les espaces blancs.
Christoffer Hammarström
3
@Heather: Vous semblez utiliser le style Ratliff , que je n'ai jamais vu auparavant et que je trouve difficile à lire. C'est certainement l'un des moins connus. Mon impression était que vous n'aviez pas mis en retrait correctement. Peu importe alors si vous le trouvez lisible, je ne suis pas d'accord.
Christoffer Hammarström
1
Le ifest complètement redondant dans l'exemple de code, et bien que le compilateur le détecte probablement, il n'y a aucune raison de tenter une mauvaise prédiction de branche.
dmckee

Réponses:

59

Dois-je penser au code machine compilé lorsque j'écris mon code?

Non , pas lorsque vous écrivez votre code la première fois et que vous ne souffrez d'aucun problème de performance réel et mesurable. Pour la plupart des tâches, c'est le cas standard. Penser trop tôt à l'optimisation est appelé "optimisation prématurée", et il y a de bonnes raisons pour que D. Knuth appelle cela "la racine de tout mal" .

Oui , lorsque vous mesurez un goulot d'étranglement des performances réel et prouvable, et que vous identifiez cette construction lambda spécifique comme la cause première. Dans ce cas, il peut être judicieux de se souvenir de la "loi des abstractions qui fuient" de Joel Spolsky et de réfléchir à ce qui pourrait se produire au niveau de l'asm. Mais attention, vous serez peut-être étonné de voir à quel point l'augmentation des performances sera faible lorsque vous remplacerez une construction lambda par une construction de langage "pas si moderne" (du moins, lorsque vous utilisez un compilateur C ++ décent).

Doc Brown
la source
2
+1 Concis, précis et facile à suivre par Doc habituel, heureux de vous avoir ici.
Jimmy Hoffa
D'accord, réponse très claire.
cnd
8

Le choix entre lambda et functor-class est un compromis.

Le gain de lambda est principalement syntaxique, en minimisant la quantité de passe-partout et en permettant l'écriture de code conceptuel en ligne, à l'intérieur de la fonction qui va l'utiliser (immédiatement ou plus tard).

En termes de performances, ce n'est pas pire qu'une classe functor , qui est une structure ou une classe C ++ qui contient une seule "méthode". En fait, les compilateurs ne traitent pas lambda différemment d'une classe de foncteurs générée par le compilateur derrière la scène.

// define the functor method somewhere
struct some_computer_generated_gibberish_0123456789
{
    int operator() (int x) const
    {
        if (x == 2) return 5;
        if (x == 3) return 6;
        return 0;
    }
};

// make a call
some_computer_generated_gibberish_0123456789 an_instance_of_0123456789;
int outputValue = an_instance_of_0123456789(inputValue);

Dans votre exemple de code, en termes de performances, il n'est pas différent d'un appel de fonction, car cette classe de fonctor n'a aucun état (car elle a une clause de capture vide), ne nécessitant ainsi aucune allocation, constructeur ou destruction.

int some_computer_generated_gibberish_0123456789_method_more_gibberish(int x)
{
    if (...) return ...;
    return ...;
}

Le débogage de tout code C ++ non trivial à l'aide d'un désassembleur a toujours été une tâche difficile. Cela est vrai avec ou sans utilisation de lambda. Cela est dû à l'optimisation sophistiquée du code par le compilateur C ++ qui a entraîné la réorganisation, l'entrelacement et l'élimination du code mort.

L'aspect de manipulation de nom est quelque peu désagréable, et le support du débogueur pour lambda est encore à ses balbutiements . On ne peut qu'espérer que le support du débogueur s'améliorera avec le temps.

Actuellement, la meilleure façon de déboguer du code lambda est d'utiliser un débogueur qui prend en charge la définition de points d'arrêt au niveau du code source, c'est-à-dire en spécifiant le nom du fichier source et le numéro de ligne.

rwong
la source
3

Pour ajouter à la réponse de @DocBrown, rappelez-vous que de nos jours, les CPU sont bon marché mais la main-d'œuvre est chère.

Dans le coût global d'un programme, le matériel est généralement insignifiant par rapport au coût de maintenance, qui est de loin la partie la plus chère d'un projet typique (encore plus que son développement).

Par conséquent, votre code doit optimiser la maintenance avant tout, sauf lorsque les performances sont critiques (et même dans ce cas, la maintenance doit être prise en compte).

Paddy Landau
la source
Seulement partiellement vrai. Si votre code exécute O (n ^ 2) (quadratique) et que vous pouvez faire quelque chose de mieux, dites O (log (n)) (logarithmique), le matériel n'aura jamais beaucoup plus de performances que de changer le code. Dans le cas spécifié par l'affiche originale, cela est très peu probable.
gnash117
@ gnash117 - oui, vous avez raison si le code doit être exécuté plusieurs fois; merci de l'avoir signalé. Dans de tels cas, la documentation claire du code le maintiendra maintenable tout en permettant l'amélioration des performances.
Paddy Landau
"le travail coûte cher" - Correct. Le temps de votre client est très important et souvent coûteux.
Cerad