Le titre de la question alternative serait:
Comment explicitement le compilateur générer du code pour les constructeurs générés par le compilateur dans une unité de traduction spécifique? em> Le problème que nous sommes confrontés est que pour un chemin de code le résultat - complètement mesuré - La performance est meilleure (d'environ 5%) si les appels COPY-CTOR d'un objet sont pas em> inliné, c'est-à-dire si ce constructeur est mis en œuvre manuellement. (Nous avons remarqué cela parce que pendant le nettoyage de code, la copie expressée superflue de cette classe (17 membres) a été supprimée.) P> EDIT: STRON> Notez que nous avons / EM> Vérifié le code de montage généré et s'est assuré que la génération d'inlinage et de code se produit comme je décris pour les deux versions de code différentes. p> Nous faisons face maintenant au choix de simplement déposer le code manuel COPY-CTOR en arrière (il fait exactement la même chose que le compilateur généré un) ou la recherche de tout autre moyen de pas em> inlindicing la copie cors de cette classe. p> existe un moyen (pour Microsoft Visual C ++) pour instancier explicitement les fonctions de classe générée par compilateur dans une unité de traduction spécifique ou être toujours inline dans chaque unité de traduction où elles sont utilisé? (Les commentaires pour GCC ou d'autres compilateurs sont également les bienvenus pour obtenir une meilleure image de la situation.) P> Comme les 2 premières réponses montrent un malentendu: le compilateur généré em> classe Les fonctions ne sont générées que par le compilateur lui-même si elles ne sont ni déclarées ni définies par l'utilisateur. Par conséquent, aucun modificateur que ce soit ne peut être appliqué à eux, car ces fonctions n'existent pas em> dans le code Sourcecode. P>
A code> A une valeur par défaut et copie CTOR, un DTOR et un opérateur de copie. Aucune de ces fonctions ne peut être modifiée via certaines DeclSpec car elles n'existent pas dans le code. P>
struct B {
std::string member;
B(B const& rhs);
};
6 Réponses :
__declSpec (NOINLINE) . < / p>
La documentation indique qu'il s'applique uniquement aux fonctions des membres, mais cela fonctionne en fait avec des fonctions libres. P>
Comment pouvez-vous utiliser cela pour une fonction générée par compilateur?
12,1 $ / 5- "une déclaration implicitement déclarée Le constructeur par défaut est une inine membre public de sa classe. ". P> blockQuote>
Donc, il n'y a rien grand chose que nous pouvons faire. Le constructeur implicateur doit être en ligne. Tout autre comportement à cet égard serait probablement une extension p>
avoir dit que p>
Il est probable que votre constructeur de copie manuel (que vous avez supprimé pendant le nettoyage du code) faisait la bonne chose. Par exemple, si l'un des membres (sur 17) de votre classe est un membre du pointeur, il est probable que le constructeur de copie manuelle a pris soin de la copie profonde (et a donc pris une performance touchée). P>
Donc, à moins que vous ne examiniez attentivement votre constructeur de copie manuelle, ne pensez même pas à le supprimer et à compter sur le constructeur de copie implicite (potentiellement buggy) (dans votre contexte) p>
Je suis d'accord avec la première partie de cette réponse, mais je ne peux pas voir ce qui vous conduit à l'autre conclusion. Premièrement, si le CC explicite faisait des choses supplémentaires, il est tout à fait improbable qu'il soit plus rapide que l'un implicite. Deuxièmement, OP a écrit que le CC explicite était "superflu", et je ne vois aucune raison de se méfier de la méfiance.
@Gorpik: "La performance est meilleure (d'environ 5%) si les appels COPY-CTOR d'un objet ne sont pas inlinés, c'est-à-dire que si ce constructeur est mis en œuvre manuellement."
Merci pour la citation STD! Et comme je l'ai déjà dit dans la question, la copie explicite CORTOR faisait exactement la bonne chose et l'une implicitement déclarée, c'est aussi exactement la bonne chose et il n'y a pas de problèmes de pointeur - le differ de la performance est vraiment et réellement dû à la ( Multipliez) COTE-CTOR-CORTRÉE enfilé contre la copie-CTOR dans une fonction distincte.
@Chubsdad: Oui, c'est ce que j'ai dit. Si la CCTOR explicite (mise en œuvre manuelle et non inline) fait des travaux supplémentaires, cela ne devrait pas mieux fonctionner.
@Martin: Comment avez-vous conclu que la performance touchée est due à plusieurs CC inlincé?
@Martin: Comme le dit Chubsdad, vous n'avez pas vraiment donné de raison de penser que l'inlinage n'a rien à voir avec la différence def. Peux-tu élaborer?
Eh bien, l'inlinisation pourrait nuire aux performances s'ils sont à la frontière du cache de code L1 ...
Je pense que l'OP est une fonction multiple en ligne dans différentes unités de traduction. Mais autant que je sache, un éditeur de force vraiment industriel optimisera vraiment toutes les copies inlicales redondantes dans toutes les unités de traduction. Mais pas sûr
@CHUBSDAD: Si vous avez plusieurs instanciations d'une fonction, il n'est pas inliné. L'intégralité de l'inlinisation consiste à placer l'instanciation du code sur le site d'appel, copiant efficacement la fonction. Ce n'est pas redondant et vous ne pouvez pas l'optimiser (au moins sans renvoyer l'optimisation d'origine d'origine)
@CHUBSAD, Autres - Voir les modifications pour des informations supplémentaires sur les mesures de performance.
Notez que j'ai depuis découvert que l'instruction standard n'implique pas que le compilateur doit générer un code inlinéré. Voir d'autres modifications.
Il est souvent préférable de l'isoler à quelques types de nœuds que vous savez problématiques. Exemple A:
/* B.hpp */ struct B { private: /* class types */ struct t_data { std::string member; /* 16 more ... */ public: /* declare + implement the ctor B needs */ /* since it is otherwise inaccessible, it will only hurt build times to make default ctor/dtor implicit (or by implementing them in the header, of course), so define these explicitly in the cpp file */ t_data(); ~t_data(); /* allow implicit copy ctor and assign -- this could hurt your build times, however. it depends on the complexity/visibility of the implementation of the data and the number of TUs in which this interface is visible. since only one object needs this... it's wasteful in large systems */ }; private: /* class data */ t_data d_data; public: /* you'll often want the next 4 out of line -- it depends on how this is created/copied/destroyed in the wild */ B(); B(const B& other); ~B(); B& operator=(const B&); }; /* B.cpp */ /* assuming these have been implemented properly for t_data */ B::B() : d_data() { } B::B(const B& other) : d_data(other) { } B::~B() { } B& B::operator=(const B&) { /* assuming the default behaviour is correct...*/ this->d_data = other.d_data; return *this; } /* continue to B::t_data definitions */
Je doute fortement l'inlinisation a quelque chose à voir avec ça. Si le compilateur augmente la copie CTOR générée par le compilateur, pourquoi ne serait-ce pas également définie explicitement? (Il est également inhabituel que les heuristiques d'optimisation du compilateur échouent si mal pour rendre un code inliné à 5% plus lent) p>
Avant de sauter aux conclusions, P>
Si tel est le cas, pourriez-vous mettre à jour votre question avec ces informations? P>
Il n'y a aucun moyen en C ++ pour indiquer si une fonction générée par le compilateur devrait ou ne doit pas être inlinée. Pas même des extensions spécifiques aux fournisseurs telles que in c ++ 0x, il est possible em> peut être possible (en fonction de la manière dont ces extensions spécifiques au fournisseur interagissent avec des fonctions déclarées comme Mais encore une fois, je ne suis pas convaincu que l'inlinage est la question. Très probablement, les deux fonctions aboutissent à un code de montage différent généré. P> __ DeclSpec (NOINLINE) CODE> vous aideront, puisque vous remettez explicitement la responsabilité de la fonction au compilateur. Donc, le compilateur choisit quoi faire avec elle, comment la mettre en œuvre et savoir s'il le fasse ou non. Vous ne pouvez pas tous les deux dire "Veuillez implémenter cette fonction pour moi", et en même temps "Veuillez me permettre de contrôler la manière dont la fonction est mise en œuvre". Si vous souhaitez contrôler la fonction, vous devez la mettre en œuvre. ;) p>
= par défaut code>). P>
+1. Le compilateur pourrait bien être incapable de faire connaître le CCTOR explicitement écrit s'il s'agit d'un fichier source (par opposition à un fichier d'en-tête), comme je suppose. Mais je suis d'accord avec le raisonnement principal et le reste de la réponse.
@Gorpik: Cela pourrait, mais cela dépend des drapeaux du compilateur. MSVC peut aligner sur les unités de traduction et même .libs avec les bons drapeaux. Et je suppose qu'ils utilisent une optimisation assez agressive s'ils sont préoccupés par une réduction de 5% de la performance.
J'ai modifié la question pour inclure une note que nous avons avoir i> effectivement vérifié l'Assemblée. Je vous assure que la seule différence entre les deux versions où la performance a été mesurée est celle-ci d'une copie inline et d'une copie de copie non inlinée. (Et oui, la copie manuelle CTOR est Evemioulsy pas en ligne, car elle est implémentée dans un fichier CPP et nous n'utilisons pas l'optimisation de l'ensemble de PRG.)
Intéressant. Dans ce cas, je suis corrigé. :) Je suppose que vous devrez mettre en œuvre explicitement la fonction (ou essayer, comme @gman suggéré dans un autre commentaire, optimisant la taille plutôt que la vitesse)
Vous pouvez utiliser une sorte d'objet imbriqué. De cette manière, le constructeur de copie de l'objet imbriqué peut être laissé à titre de défaut sans entretien, mais vous avez toujours un constructeur de copie créé explicitement créé que vous pouvez déclarer NOINLINE.
class some_object_wrapper { original_object obj; __declspec(noinline) some_object_wrapper(const some_object_wrapper& ref) : obj(ref) {} // Other function accesses and such here };
"Pourquoi avez-vous mis en œuvre un constructeur de copie manuelle s'il fait la même chose que le constructeur de copie par défaut?" ... Je devais rire de ça .... Avez-vous déjà érayé par le code hérité? La quantité de programmation de cargaison que vous pouvez trouver est simplement stupéfiante :-)
Ajouter ma propre conclusion et répondre à la question exacte sans entrer dans les détails: p>
vous ne peut pas strud> force em> le compilateur, spécifiquement VC ++, en ligne ou non en ligne un CTOR / DTOR généré par le compilateur / etc. - mais fort> p> li>
L'optimiseur choisira - à sa discrétion - s'il englobe le code d'une fonction générée par compilateur (CTOR) ou s'il génère une fonction "réelle" pour ce code. AFAIK Il n'y a aucun moyen d'influencer la décision de l'optimiseur à cet égard. P> li>
ol>
Oh, quel maux de tête! :-)
@Martin: C'est assez rare que la blessure de performance en ligne (généralement vous gagnez rapidement, car vous n'avez pas d'appel de fonctions et de sa configuration, etc.). Même si de la chance: /
Je ne vois pas ce qu'enlinge a à voir avec ça. Avez-vous vérifié que la version générée par le compilateur est inlinée et que vous avez explicitement mis en œuvre, ne le fait pas? Ou êtes-vous simplement de mélanger la terminologie, en utilisant "Inline" pour faire référence à quelque chose d'autre (généré par compilateur, peut-être) - et avez-vous vérifié en regardant dans l'assemblage généré que les celles générées et définies manuellement sont exactes la même chose ?
Essayez de compiler pour la taille au lieu de la vitesse.
Avez-vous essayé de le déclarer dans la définition de la classe, puis définissez-le dans votre unité de translation préférée, à l'aide de C ++ 0x
= défaut code>? C'est "essayé" à la fois au sens de ", cela affecte-t-il la vitesse?", Et aussi dans le sens de ", cela compilait-il, c'est-à-dire que votre version de MSVC prend en charge la fonctionnalité C ++ 0X?".
@Steve - Malheureusement no c ++ 0x ici.
@Steve: Même MSVC2010 ne prend pas en charge
= défaut code>, malheureusement.