Je suis actuellement au stade de la conception d'une architecture basée sur des composants en C ++.
Ma conception actuelle comprend l'utilisation de fonctionnalités telles que:
std::vector
s destd::shared_ptr
s pour maintenir les composantsstd::dynamic_pointer_cast
std::unordered_map<std::string,[yada]>
Les composants représenteront les données et la logique de divers éléments nécessaires dans un logiciel de type jeu, tels que les graphiques, la physique, l'IA, l'audio, etc.
J'ai lu partout que les erreurs de cache sont néfastes sur les performances, j'ai donc effectué quelques tests, ce qui m'a amené à croire qu'en effet, cela pouvait ralentir une application.
Je n'ai pas pu tester les fonctionnalités linguistiques susmentionnées, mais il est dit dans de nombreux endroits que celles-ci ont tendance à coûter cher et doivent être évitées si possible.
Étant donné que je suis au stade de la conception de l'architecture, et ceux-ci seront inclus dans le cœur de la conception, devrais-je essayer de trouver des moyens de les éviter maintenant, car il sera très difficile de le changer plus tard s'il y a des performances problèmes?
Ou je suis juste pris à faire une optimisation prématurée?
la source
the answer to this question is almost always a resounding "YES !!"
. Je pense toujours qu'il vaut mieux le faire fonctionner d'abord et l'optimiser plus tard, mais YMMV, tout le monde a son avis, tous valides, et seul l'OP peut vraiment répondre à sa propre question - subjective -.Réponses:
Sans rien lire d'autre que le titre: Oui.
Après avoir lu le texte: Oui. Bien qu'il soit vrai que les cartes et les pointeurs partagés, etc. ne fonctionnent pas bien dans le cache, vous constaterez très certainement que ce pour quoi vous voulez les utiliser - pour autant que je sache - n'est pas le goulot d'étranglement et ne sera pas conservé ou utiliser efficacement le cache quelle que soit la structure des données.
Écrivez le logiciel en évitant les erreurs les plus stupides, puis testez, puis trouvez les goulots d'étranglement, puis optimisez!
Fwiw: https://xkcd.com/1691/
la source
Je ne connais pas C ++, mais en général cela dépend.
Vous n'avez pas besoin d'optimiser prématurément les algorithmes isolés où vous pouvez facilement les optimiser quand il s'agit de cela.
Cependant, vous devez obtenir la conception globale de l'application pour atteindre les indicateurs de performance clés souhaités.
Par exemple, si vous devez concevoir une application pour répondre à des millions de demandes par seconde, vous devez penser à l'évolutivité de l'application lors de sa conception, plutôt que de faire fonctionner l'application.
la source
Si vous devez demander, alors oui. L'optimisation prématurée signifie l'optimisation avant de vous assurer qu'il existe un problème de performances important.
la source
ECS? Je vais en fait suggérer qu'il n'est peut-être pas prématuré, si c'est le cas, de réfléchir beaucoup au côté orienté données de la conception et de comparer les différents représentants, car cela pourrait avoir un impact sur vos conceptions d'interface , et ce dernier est très coûteux à modifier tard dans la le jeu. De plus, ECS exige juste beaucoup de travail et de réflexion en amont et je pense que cela vaut la peine d'utiliser une partie de ce temps pour vous assurer que cela ne vous causera pas de problèmes de performances au niveau de la conception plus loin étant donné la façon dont cela va être au cœur de votre tout le moteur flippant. Cette partie me regarde:
Même avec de petites optimisations de chaînes, vous avez un conteneur de taille variable (chaînes) à l'intérieur d'un autre conteneur de taille variable (unordered_maps). En fait, les petites optimisations de chaînes pourraient être aussi nuisibles qu'utiles dans ce cas si votre table est très clairsemée, car l'optimisation de petites chaînes impliquerait que chaque index inutilisé de la table de hachage utilisera toujours plus de mémoire pour l'optimisation SS (
sizeof(string)
serait être beaucoup plus grande) au point où la surcharge de mémoire totale de votre table de hachage peut coûter plus cher que tout ce que vous y stockez, en particulier si c'est un composant simple comme un composant de position, en plus d'engendrer plus de ratés de cache avec l'énorme foulée pour passer d'une entrée de la table de hachage à la suivante.Je suppose que la chaîne est une sorte de clé, comme un ID de composant. Si c'est le cas, cela rend déjà les choses considérablement moins chères:
... si vous voulez avoir les avantages d'avoir des noms conviviaux que les scripteurs peuvent utiliser, par exemple, alors les chaînes internes peuvent vous donner le meilleur des deux mondes ici.
Cela dit, si vous pouvez mapper la chaîne à une plage raisonnablement faible d'indices densément utilisés, vous pourrez peut-être le faire:
La raison pour laquelle je ne considère pas cela prématuré est que, encore une fois, cela pourrait avoir un impact sur la conception de votre interface. Le but du DOD ne devrait pas être d'essayer de proposer les représentations de données les plus efficaces imaginables en une seule fois IMO (qui devraient généralement être réalisées de manière itérative si nécessaire), mais de les penser suffisamment pour concevoir des interfaces sur le dessus pour travailler avec cela. des données qui vous laissent suffisamment de marge de manœuvre pour profiler et optimiser sans modifier la conception en cascade.
À titre d'exemple naïf, un logiciel de traitement vidéo qui couple tout son code à cela:
Ne va pas loin sans une réécriture potentiellement épique, car l'idée d'abstraire au niveau d'un seul pixel est déjà extrêmement inefficace (
vptr
elle - même coûterait souvent plus de mémoire que le pixel entier) par rapport à l'abstrait au niveau de l' image (ce qui représentent souvent des millions de pixels). Donc, réfléchissez suffisamment à vos représentations de données à l'avance pour ne pas avoir à faire face à un tel scénario de cauchemar, et idéalement pas plus, mais ici, je pense que cela vaut la peine de penser à ce genre de choses dès le départ car vous ne voulez pas construire un moteur complexe autour de votre ECS et constatez que l'ECS lui-même est le goulot d'étranglement d'une manière qui vous oblige à changer les choses au niveau de la conception.En ce qui concerne les échecs de cache ECS, à mon avis, les développeurs s'efforcent souvent trop de rendre leur cache ECS convivial. Cela commence à céder trop peu pour que l'argent essaie d'accéder à tous vos composants de manière parfaitement contiguë, et impliquera souvent de copier et de mélanger les données partout. Il est généralement suffisant, par exemple, de simplement trier les index des composants avant de les accéder afin que vous y accédiez de manière à ne pas charger au moins une région de mémoire dans une ligne de cache, uniquement pour l'expulser, puis charger tout à nouveau dans la même boucle juste pour accéder à une partie différente de la même ligne de cache. Et un ECS n'a pas à fournir une efficacité incroyable à tous les niveaux. Ce n'est pas comme si un système d'entrée en bénéficiait autant qu'un système de physique ou de rendu, je recommande donc de viser «bon» efficacité à tous les niveaux et "excellente" seulement là où vous en avez vraiment besoin. Cela dit, l'utilisation de
unordered_map
etstring
voici assez facile à éviter.la source