8
votes

Pointeurs partagés et la performance

J'utilise des pointeurs partagés pour la Soiem Time maintenant, et j'ai des problèmes de performance dans mon programme ... Je voudrais donc savoir si des pointeurs partagés entraînent une diminution de la performance. Si oui, alors combien? Merci beaucoup.

Mon programme est multi-threadé, utilisant STD :: TR1 :: Shared_PTR


4 commentaires

Il h. Pas de réponse ici, mais j'ai juste aimé la façon dont le titre a été formulé. Je pense que la CPU exécute des instructions d'exécution joyeusement lorsque cela voit soudainement une instruction de pointeur partagée, entrez dans le dos du pipeline. "Oh non, ça va aller huuuuurt ...... ow!"


Qu'est-ce qui vous fait penser que le problème est des indicateurs partagés?


Avoir des gens qui disent qu'ils gaspillent le temps de la CPU, c'est-à-dire: p


@Guest j'ai créé un test simple a fait la même opération avec SmartPointers et avec des pointeurs bruts pour un million de fois (l'opération est simplement d'initialiser une nouvelle instance et appelle de supprimer pour Raw et crée un nouveau Shared_ptr pour SMARD) Les smarts prennent du temps de 3073 millisecondes et le Les pointeurs bruts prennent du temps de 1789 millisecondes, ce qui est à la petite différence, et est attendu, dans les constructions intelligentes 2 et 2 destructions que l'une est pour le pointeur intelligent lui-même et l'autre est pour la classe principale de la classe principale.


7 Réponses :


5
votes

Les pointeurs partagés sont comptés. En particulier lorsque vous utilisez la multi-threading, l'incrémentation et la décrémentation du nombre de références peuvent prendre beaucoup de temps. La raison en matière de multithreading fait mal ici est que si vous avez passé un pointeur partagé entre les threads, le nombre de références finirait par partagée entre ces threads, de sorte que toute manipulation doit être synchronisée entre les threads. Cela peut ralentir des choses un peu.

EDIT: Pour ceux qui se soucient de la quantité de fil de fil plus lente peuvent faire des opérations assez simples, voir les tests de Herb Sutter avec quelques implémentations de Cordes de vache . Bien que ses tests soient loin d'être parfaits (par exemple, il n'a testé que sur Windows), il vous donne toujours une idée du type de ralentissement que vous pouvez vous attendre. Pour la plupart des fins pratiques, vous pouvez / penser à une chaîne de vache comme une autre chose comme un Shared_Ptr , avec beaucoup de fonctions de membre (non pertinentes) ajoutées.


10 commentaires

Ceci n'est vrai que si vous utilisez un mécanisme de comptage de référence qui est au courant. Il n'apparaît pas que c'est le cas selon la documentation boost.org/doc/libs/1_38_0/libs/smart_ptr/...


Il ne dit pas ce que Shared_ptr il utilise. Certains sont déjà au courant, et certains ne le sont pas. Il est ouvert à interroger si celui qu'il utilise est ou non. Cela dit, vous avez certainement raison de dire que les chances d'être la cause d'un problème de performance sont assez éloignées.


DU TEMPS DE TEMPS ACCEMBRE AUX INCÉMENT / DÉCRÉMENT Compte de référence? Sérieusement? Sur X86 / X64 s'il prend du temps "significatif" de temps pour incrémenter / décrémenter le nombre de références, cela signifie simplement que vous ne faites rien d'autre dans votre programme. Les opérations verrouillées peuvent être «significativement» plus lentes que leurs alternatives à une seule-filetage, mais elles sont toujours ultra-rapides par rapport à ce que font les programmes normaux (c'est-à-dire de lire certaines données à partir de fichiers, de tout calcul non trivial, etc.)


Ceci est une supposition spéculative sans informations difficiles. Le type que nous faisons tous juste avant de profiler pour tester notre devin. Malheureusement, le monde réel ne tient pas de l'eau.


Il est certainement vrai que je n'ai pas profilé à son programme et attribuant un problème de performance à Shared_ptr sans le faire est la spéculation. Cela n'était cependant pas la question qu'il a posée. Ce qu'il a demandé était de savoir si Shared_ptr a causé une ralentissement, et si oui combien. La réponse est "Oui, ils peuvent, bien que ce soit exactement combien est presque impossible à prédire". Je conviens qu'ils ne sont probablement pas la source de son problème, mais ce n'est pas ce qu'il a demandé.


Si les gens devraient simplement mesurer les performances du pointeur brut vs partagé_ptr Ils ne seraient pas critiques de votre message .. mais hé, c'est comme la même vieille ignorance .. Shared_ptr-S ralentissez-vous pour le prix que vous payez dans la maintenabilité et tout à fait fortement.


Pour Boost :: Shared_PTR, sur les CPU qui l'appuient, le comptage de référence est effectué avec des opérations atomiques qui n'ont pas besoin de synchronisation.


Nous avons eu cette discussion au travail il y a quelques semaines - combien il est coûteux de réussir un boost Shared_ptr par valeur plutôt que par référence. S'avère est qu'il peut être plus de 200 fois plus lent en raison des opérations de verrouillage, ainsi que de la cornue de code destinée à traiter avec appel à l'appel, une exception peut être soulevée. Bien sûr, passer par référence ne fait que quelques instructions. BTW La plate-forme est Windows XP avec VisualStudio 2005.


@stefaanv: Ce n'est pas vraiment "pas besoin de synchronisation", mais qui dispose de suffisamment de synchronisation supportées directement par le matériel. Le support direct par le matériel aide définitivement - mais il reste encore beaucoup plus lentement que quelque chose qui n'a pas besoin de synchronisation du tout.


Eh bien, mon programme est un serveur de jeu, le profileur en cours d'exécution est trop lent, ou je devrai le tester hors serveur Live ...



9
votes

Il est pratiquement impossible de répondre correctement à cette question compte tenu des données. Le seul moyen de réellement dire ce qui provoque une question de performance dans votre application consiste à exécuter un profileur sur le programme et à examiner la sortie.

Cela étant dit, il est très improbable qu'un partage_ptr cause le ralentissement. Le type Shared_PTR et de nombreuses variantes cultivées à la maison sont utilisées dans un nombre toujours croissant de programmes C ++. Je les utilise moi-même dans mon travail (professionnel à la maison). J'ai passé beaucoup de temps à profiler mes applications de travail et Shared_Ptr n'a jamais été proche d'un problème de mon code ou de tout autre code dans la demande. Il est beaucoup plus probable que l'erreur soit ailleurs.


0 commentaires

3
votes

très improbable - vous devrez passer la majeure partie de votre temps à passer des pointeurs.

L'effet des PTR partagés est généralement mineur et il est difficile de construire un cas de bord où ils deviennent un problème (en supposant une implémentation appropriée et un compilateur optimisant correctement).

Impacts du PTR partagé:

  • taille d'allocation accrue.

    Cela ne comporterait que si vous avez de nombreux indicateurs partagés à de très petits objets (par exemple, des dizaines de millions de partagés_ptr ) et / ou fonctionnent près d'une limite de mémoire. Il existe un petit potentiel pour une performance notable diminuer si les allocations supplémentaires dépassent un niveau de cache / numa dans une boucle interne

  • augmentation de l'augmentation des allocations

    Shared_PTR attribue un objet de suivi (nombre de référence, nombre faible et Delier). Cela met la pression sur le tas et peut provoquer un ralentissement général si vous avez un nombre total élevé d'allocations et de translocations.
    Peut être évité à l'aide de make_shared , de placer un objet référent et de trackng en une seule allocation

  • Comptage de référence

    augmente le coût d'une copie d'un pointeur. Dans une seule application filetée, vous remarqueriez que vous ne savourez que de vous passer de votre temps à copier des pointeurs de toute façon. Dans une application multithreadée, vous auriez toujours besoin d'avoir une intervention élevée sur les mêmes pointeurs.
    Le coût de la copie peut être avoié dans de nombreux endroits en passant un partagé_ptr const & par exemple. comme argument de fonction.

  • Déroférence

    Le coût de la déséroférence supplémentaire est zéro dans une version de libération d'un compilateur d'optimisation. Les constructions de débogage équivalent souvent à des appels de fonction et aux chèques nuls supplémentaires. Néanmoins, en particulier dans les bâtiments de débogage, vous devez passer la plupart du temps le déséroferience des pointeurs pour faire une différence.


    Sans Informateur supplémentaire, nous ne pouvons pas vous aider. Vous devez décrire ce que les "problèmes de performance" sont (la douleur générale, certaines opérations prenant une longue période, beaucoup d'échange) et des chiffres clés - de votre application, combien de pointeurs intelligents sont présents, à quelle fréquence ils sont copiés, et quelles autres opérations vous exécutez Besindse Jongler Smart Pointers.

    ou vous apprenez à utiliser le moniteur de performance et / ou à un profileur pour déterminer ce qui provoque les ralentissements et s'il existe des goulots d'étranglement particuliers.


0 commentaires

5
votes

Si votre programme semble avoir un problème de performance, il est parfaitement naturel de commencer à deviner quel pourrait être le problème, mais si vous voulez placer un pari, il est presque 100% susceptible d'être autre chose. Le profilage peut trouver le problème. C'est la méthode que j'utilise. < / a>


0 commentaires

1
votes

Une chose qui pourrait blesser la performance est excessif en passant partagée_ptr en tant que paramètres de fonction. Une solution pour cela transmettre des références à Shared_PTR. Cependant, il s'agit d'une micro-optimisation, alors ne le faites que lorsque vous avez vraiment besoin

EDIT: En pensant à cela, il existe de meilleurs moyens d'optimiser:

  • Lorsque vous passez excessivement le pointeur, vous devriez probablement laisser l'objet faire quelque chose au lieu de le traîner.
  • Vous pouvez passer (const) référence à l'objet au lieu du pointeur
  • transmettez une référence au pointeur lorsque le pointeur doit être modifié

0 commentaires


13
votes

Si votre application passe autour de 700 messages XML d'octets pouvant être contenus dans des messages de protocole Google 65 octets ou de 85 messages ASN.1 d'octets, alors cela ne va probablement pas importer. Mais si elle traite un million de quelque chose une seconde, je ne refroiserais pas le coût de l'ajout de 2 cycles de modification de l'écriture (RMW) à la suite d'un pointeur.

Une lecture complète Modifier l'écriture est de l'ordre de 50 NS, donc deux est de 100 ns. Ce coût est le coût d'une Lock-Inc et d'un verrou de verrouillage - la même chose que 2 CAS. Ceci est la moitié d'une réserve de section critique Windows et de libération. Ceci est comparé à une seule poussée de cycle de machine (400 secondes Pico sur une machine de 2,5 gz)

Et cela n'inclut même pas les autres coûts d'invalidation de la ligne de cache contenant réellement le nombre, les effets de la serrure de bus sur d'autres processeurs, etc.

Passage des pointeurs intelligents de la référence constante est presque toujours préféré. Si la callee ne fait pas un nouveau pointeur partagé lorsqu'il souhaite garantir ou contrôler - de la durée de vie du pointeau , il s'agit d'un bug dans la callee . Pour aller faire du fil willy-nilly sur la sécurité de réflexion en toute sécurité comptant les pointeurs intelligents autour de la valeur ne veut que demander des hits de performance.

L'utilisation des pointeurs comptés de référence simplifie sans aucun doute des viftimes, mais de transmettre des pointeurs partagés par la valeur pour tenter de protéger contre les défauts de la callee est un non-sens total et total.

L'utilisation excessive de comptage de référence peut rapidement transformer un programme svelte pouvant traiter des messages de 1 mm par seconde (MPS) dans une graisse qui gère 150 km de MPS sur le même matériel. Tout à coup, vous avez besoin d'une demi-rack de serveurs et de 10000 $ / an en électricité.

Vous êtes toujours mieux désactivé si vous pouvez gérer la durée de vie de vos objets sans compter de référence.

Un exemple d'une simple amélioration est dit que si vous allez faire l'extraction d'un objet et que vous connaissez la largeur de la fanout (dire n) incrément de n plutôt que d'incrémenter individuellement à chaque fanout.

BTW lorsque la CPU voit un préfixe de verrouillage, il dit vraiment "Oh non ça va faire mal".

Tout ce qui étant dit, je suis d'accord avec tout le monde que vous devriez vérifier le point chaud.


0 commentaires