Pourquoi un programme nécessite-t-il un nombre minimum spécifique de cœurs de processeur?

55

Est-il possible d'écrire du code (ou un logiciel complet, plutôt qu'un morceau de code) qui ne fonctionnera pas correctement s'il est exécuté sur une CPU dont le nombre de cœurs est inférieur à N? Sans le vérifier explicitement et en échouant exprès:

SI (noOfCores <4) ALORS ne fonctionne pas correctement exprès

Je suis en train de regarder la configuration minimale requise pour un jeu ( Dragon Age: Inquisition ), qui indique au minimum un processeur à quatre cœurs. De nombreux joueurs disent qu'il ne fonctionne PAS sur les processeurs à deux cœurs et EVEN sur les processeurs Intel Core i3 avec deux cœurs physiques et deux cœurs logiques. Et ce n'est pas un problème de puissance de calcul.

D'après ce que j'ai compris, les threads sont complètement isolés du processeur par le système d'exploitation, ce qui est impossible.

Juste pour clarifier les choses:

Je ne demande pas "Puis-je connaître le nombre de cœurs de processeur à partir du code et échouer exprès?" ... Un tel code serait mal intentionné (vous oblige à acheter un processeur plus coûteux pour exécuter un programme - sans besoin de puissance de calcul). Je demande que votre code, par exemple, comporte quatre threads et échoue lorsque deux threads sont exécutés sur le même noyau physique (sans vérification explicite des informations système et échec intentionnel) .

En bref, peut-il y avoir un logiciel nécessitant plusieurs cœurs sans nécessiter de puissance de calcul supplémentaire provenant de plusieurs cœurs? Il faudrait simplement N cœurs physiques distincts.

Uylmz
la source
11
Si vous lisez ma question attentivement, vous verrez qu'ils ne demandent pas la même chose.
Uylmz
21
Étant donné que le nombre de cœurs peut être récupéré, il peut être comparé à N, et si cette comparaison est évaluée à true, le code peut faire tout ce dont il a envie, y compris, mais sans s'y limiter, se comporter de manière non annoncée. Quelle est votre question?
3
Êtes-vous sûr que le problème est vraiment et directement lié au nombre de cœurs? Peut-être que le jeu mentionné est partiellement basé sur une fonctionnalité uniquement (correctement) fournie par le processeur avec au moins 4 cœurs?
mgoeminne
25
Notez que la "configuration système minimale" est souvent "la configuration système minimale requise pour fonctionner avec des performances acceptables", en particulier avec les jeux. Il est très possible que Dragon Age puisse, en théorie, fonctionner sur une seule boîte, mais si vous le faisiez, il y aurait des chutes de trames massives. Ils ont donc besoin de ce nombre de cœurs non pas pour vous obliger à acheter du matériel, mais pour éviter les problèmes de qualité de la part des utilisateurs de matériel bas de gamme.
Gort le robot
3
@Sebb: Je pense que vous êtes sur quelque chose: si 4 cœurs physiques sont corrélés avec plus de cache que 2 physiques / 4 logiques, le jeu pourrait naturellement s'étouffer sur des machines 2x2 sans atteindre leurs limites de puissance de traitement car il manque le cache tous les temps. Le test consisterait à trouver un processeur avec 2x2 cœurs et des charges de cache, ou 4 cœurs et peu de cache, et voir ce qui se passe.
Steve Jessop

Réponses:

45

Cela peut être possible "par accident" avec une utilisation négligente de l’affinité principale. Considérons le pseudocode suivant:

  • commencer un fil
  • dans ce fil, savoir sur quel noyau il fonctionne
  • définir son affinité CPU à ce noyau
  • commencer à faire quelque chose d'intense calcul / boucle pour toujours

Si vous démarrez quatre de ceux-ci sur un processeur à deux cœurs, le réglage de l'affinité de base pose problème, ou bien deux threads encombrent les cœurs disponibles et deux threads qui ne sont jamais planifiés. À aucun moment, il n'a explicitement demandé combien il y avait de cœurs.

(Si vous avez des threads de longue durée, la définition de l'affinité CPU améliore généralement le débit)

L'idée que les sociétés de jeux "obligent" les gens à acheter du matériel plus coûteux sans raison valable n'est pas très plausible. Cela ne peut que leur faire perdre des clients.

Edit: ce message a maintenant 33 votes positifs, ce qui est assez, car il est basé sur des suppositions éclairées!

Il semble que les gens aient DA: Je coure mal sur des systèmes dual-core: http://www.dsogaming.com/pc-performance-analyses/dragon-age-inquisition-pc-performance-analysis/ Cette analyse mentionne que la situation s'améliore grandement si l'hyperthreading est activé. Etant donné que HT n'ajoute plus d'unités d'émission d'instruction ni de cache, il permet simplement à un thread de s'exécuter pendant qu'un autre se trouve dans une stalle de cache, ce qui suggère fortement qu'il est lié uniquement au nombre de threads.

Une autre affiche affirme que la modification des pilotes graphiques fonctionne: http://answers.ea.com/t5/Dragon-Age-Inquisition/Working-solution-for-Intel-dual-core-CPUs/td-p/3994141 ; Etant donné que les pilotes graphiques ont tendance à être une ruche de misères et de voyous, ce n'est pas surprenant. Un ensemble notoire de pilotes avait un mode "correct & lent" par rapport au mode "rapide & incorrect" sélectionné si appelé depuis QUAKE.EXE. Il est tout à fait possible que les pilotes se comportent différemment pour différents nombres de processeurs apparents. Peut-être (retour à la spéculation) un mécanisme de synchronisation différent est utilisé. Mauvais usage des spinlocks ?

"L'utilisation abusive de primitives de verrouillage et de synchronisation" est une source très répandue de bogues. (Le bogue que je suis censé observer au travail en écrivant ceci est "un crash si vous modifiez les paramètres de l'imprimante en même temps que le travail d'impression est terminé").

Edit 2: les commentaires mentionnent le système d'exploitation essayant d'éviter la privation de threads. Notez que le jeu peut avoir son propre quasi-ordonnanceur interne pour attribuer le travail aux threads, et il y aura un mécanisme similaire dans la carte graphique elle-même (qui est en réalité un système multitâche à part entière). Les chances d'un bug dans l'un de ceux-ci ou l'interaction entre eux sont assez élevées.

www.ecsl.cs.sunysb.edu/tr/ashok.pdf (2008) est une thèse de troisième cycle sur l'amélioration de la planification des cartes graphiques, qui mentionne explicitement qu'elles utilisent normalement la planification selon le principe du premier arrivé, premier servi, qui est facile à mettre en œuvre. systèmes non préemptifs. La situation s'est-elle améliorée? Probablement pas.

pjc50
la source
1
Oui, la réponse à cette question comporte deux parties: l’affinité CPU permet de coder quelque chose qui en ferait une exigence technique de Windows, la solution alternative étant que les systèmes en temps réel peuvent très certainement exiger de telles choses. +1 pour être la seule personne à mentionner l'affinité CPU, qui est vraiment le coupable le plus susceptible de répondre à ce qui est demandé ici.
Jimmy Hoffa
3
Qu'est-ce qui peut mal tourner si vous définissez l'affinité avec le noyau actuel? Avec le multitâche préemptif, le thread en attente sera planifié à moins que le thread actuel ait la priorité maximale possible ("temps réel" dans Windows). Je verrais un autre scénario: chacun des 4 threads se voit attribuer une affinité définie de manière statique de 1,2,4,8, auquel cas les deux derniers threads ne seront jamais programmés (bien que je ne sois pas sûr de définir l'affinité sur effective zéro va réussir).
Ruslan
@Ruslan Peut-être que tenter de définir une affinité non valide plantera l'application en premier lieu?
Luaan
1
@ Luan et bien ce n'est pas cette opération risquée qui conduit à un crash. Au maximum, ce à quoi je m'attendais est une erreur renvoyée par le système d'exploitation. Je viens de vérifier, sous Linux, l'erreur "Invalid argument". Je ne sais pas ce que Windows dirait.
Ruslan
@Ruslan Chaque système d'exploitation majeur depuis plus de dix ans inclut un code destiné à éviter la famine de threads (généralement en renforçant la priorité d'un thread qui ne fonctionne pas assez longtemps).
Voo le
34

Il peut être nécessaire d’avoir 4 cœurs car l’application exécute quatre tâches dans des threads parallèles et s’attend à ce qu’elles se terminent presque simultanément.

Lorsque chaque thread est exécuté par un noyau séparé et que tous les threads ont exactement la même charge de travail de calcul, il est fort probable (mais loin d'être garanti) de terminer à peu près au même moment. Mais lorsque deux threads fonctionnent sur un même noyau, le timing sera beaucoup moins prévisible car le noyau changera de contexte tout le temps.

Les bogues qui surviennent à cause d'un timing de thread inattendu sont appelés " conditions de concurrence ".

Dans le contexte du développement de jeux, une architecture plausible avec ce type de problème pourrait être celle où différentes fonctionnalités du jeu sont simulées en temps réel par différents threads de la CPU. Lorsque chaque fonction est exécutée sur son propre noyau, elles sont toutes simulées à peu près à la même vitesse. Mais lorsque deux fonctionnalités fonctionnent sur un même noyau, elles ne seront simulées que deux fois moins vite que le reste du monde du jeu, ce qui pourrait entraîner toutes sortes de comportements étranges.

Notez qu'une architecture logicielle reposant sur des threads indépendants exécutés avec des timings spécifiques est extrêmement fragile et témoigne d'une très mauvaise compréhension de la programmation concurrente. Dans la quasi-totalité des API multithreading, certaines fonctionnalités permettent de synchroniser explicitement les threads afin d'éviter ce type de problèmes.

Philipp
la source
11
Mais tout jeu a une dépendance fragile à la possibilité de terminer tous les calculs pour la trame suivante dans le temps pour le rendre avec une fréquence raisonnable. Même si vos 4 threads sont correctement synchronisés, il peut s'avérer impossible d'effectuer un rendu dans les délais impartis, et il n'y a aucun avantage à ce que le jeu soit correct, mais injouable en raison du retard et du bégaiement.
Inutile
1
@Useless: Ce n'est pas vraiment vrai. Vous pouvez par exemple utiliser des cadres de mémoire tampon ou des données de simulation pour masquer tout bégaiement. Il existe également des conceptions simultanées plus cohérentes. Effectuer tous vos traitements en temps réel et exiger une synchronisation exacte de ces traitements sont deux choses différentes.
DeadMG
23
"Une architecture logicielle reposant sur des threads indépendants fonctionnant avec des timings spécifiques est extrêmement fragile" C'est pourquoi je ne peux pas imaginer un jeu qui ne fonctionne pas du tout avec 2 cœurs, mais fonctionne de manière fiable avec 4 cœurs. Même avec 4 cœurs, le timing sera imprévisible, de sorte que la situation de compétition se produira aussi, même si elle est moins fréquente.
svick
8
@svick bien sûr. Mais la question demande "est-ce possible?" pas "est-ce sain d'esprit?"
user253751
5
Tout code avec ce type de "conditions de concurrence" est totalement cassé , quel que soit le nombre de noyaux sur lesquels vous l'exécutez. (D'autant plus qu'il n'y a absolument aucune garantie quant à ce qui se passe sur le système.) Je doute sérieusement que ce soit la cause, étant donné la facilité avec laquelle le jeu trébucherait même sur un système hexacore ...
DevSolar
16

Il est peu probable que ces "exigences minimales" représentent quelque chose en dessous duquel le jeu ne fonctionnera pas. Plus vraisemblablement, ils représentent quelque chose en dessous duquel le jeu ne fonctionnera pas avec des performances acceptables. Aucune entreprise de jeux vidéo ne souhaite traiter avec de nombreux clients se plaignant de performances médiocres lorsqu'ils les exécutent sur une seule boîte de 1 Ghz, même si le logiciel pouvait fonctionner techniquement. Donc, ils ont probablement délibérément conçu pour échouer dur sur les boîtes avec moins de cœurs que ce qui leur donnerait des performances acceptables.

Le taux de trame est une mesure importante dans les performances de jeu. Ils fonctionnent généralement à 30 ou 60 images par seconde. Cela signifie que le moteur de jeu doit rendre la vue actuelle à partir de l'état du jeu dans un laps de temps déterminé. Pour atteindre 60 ips, il ne lui reste plus que 16 ms. Les jeux avec des graphismes haut de gamme sont extrêmement gourmands en ressources CPU, ce qui représente un énorme compromis entre essayer d'améliorer la qualité (ce qui prend plus de temps) et la nécessité de respecter ce budget. Ainsi, le budget temps de chaque image est extrêmement limité.

En raison du manque de temps, le développeur souhaite idéalement disposer d'un accès exclusif à un ou plusieurs noyaux. Ils veulent aussi probablement pouvoir faire leur rendu dans un noyau, exclusivement, car c'est ce qui doit être fait avec ce budget temps, tandis que d'autres choses, telles que le calcul de l'état du monde, se déroulent selon un processus séparé où il n'en sera rien. intrusion.

En théorie, vous pourriez mettre tout cela sur un seul noyau, mais tout devient beaucoup plus difficile. Tout à coup, vous devez vous assurer que tout ce qui se passe dans l'état du jeu se passe assez rapidement et permet à votre rendu de se produire. Vous ne pouvez pas simplement en faire deux threads logiciels car il n’ya aucun moyen de faire comprendre au système d’exploitation "le thread A doit effectuer une quantité de travail X maximale en 16 ms, quel que soit le thread B".

Les développeurs de jeux n'ont aucun intérêt à vous faire acheter du nouveau matériel. La raison pour laquelle ils ont une configuration système requise est que le coût de la prise en charge des machines d'extrémité inférieure n'en vaut pas la peine.

Gort le robot
la source
Bien que cela soit vrai, il arrive que vous puissiez acheter du matériel à double cœur suffisamment puissant pour pouvoir obtenir davantage, dans un laps de temps donné, que le matériel à quatre coeurs décrit dans les spécifications minimales. Pourquoi le fournisseur n’a-t-il pas déclaré ce matériel acceptable, une décision qui ne peut que leur faire perdre des ventes?
Jules
4
La chose à comparer n'est pas 2 vs 4 noyaux. C'est essentiellement 1 vs 3 cœurs, car le CPU n ° 0 sera plus ou moins indexé par le pilote graphique et les DPC. Les effets de cache et de migration sont également importants si vous surabaissez un processeur avec plusieurs types de tâches dans le système de tâches d'un jeu moderne. L'exigence est là parce que Frostbite (le moteur de DA: I) est conçu dès le départ avec un réglage très minutieux qui nécessite un nombre particulier de cœurs.
Lars Viklund le
6
@LarsViklund On dirait que vous connaissez plus de détails que quiconque ici. Avez-vous envisagé de préparer une réponse?
Gort le robot
1
"Il est peu probable que ces" exigences minimales "représentent un seuil en deçà duquel le jeu ne fonctionnera pas. Elles sont beaucoup plus susceptibles de représenter un seuil en deçà duquel le jeu ne fonctionnera pas avec des performances acceptables." - Le processeur Intel G3258 est un processeur dual core très puissant, largement utilisé par les joueurs et capable de faire fonctionner des jeux avec autant de ressources, voire plus de ressources, que Dragon Age Inquisition, mais de nombreux joueurs rapportent que le jeu ne tourne pas dessus.
Uylmz
2
@ Reeek Je doute qu'un utilisateur final puisse facilement dire à quel point un jeu donné nécessite beaucoup de ressources par rapport à un autre.
Gort le robot
9

Trois threads en temps réel qui ne dorment jamais et un autre thread. S'il y a moins de quatre cœurs, le quatrième thread ne s'exécute jamais. Si le quatrième thread a besoin de communiquer avec l'un des threads temps réel pour que celui-ci se termine, le code ne se terminera pas avec moins de quatre cœurs.

Évidemment, si les threads temps réel attendent quelque chose qui ne leur permet pas de dormir (comme un verrou tournant), le concepteur du programme a tout gâché.

Josué
la source
1
On peut soutenir que lorsqu'une application utilisateur demande des threads en temps réel, le concepteur a tout
gâché
2
Je l'ai fait. Un demi-million de lignes de code. Un cas utilisant environ 300 lignes. Le thread en temps réel passe le plus clair de son temps à attendre une entrée afin de pouvoir horodater l'entrée et la transmettre à un thread de moindre priorité.
Josué
2
@ Luan Pour la plupart des applications, je serais d'accord avec vous, mais les jeux sont une bête différente, tout comme les applications intégrées. Dans les deux cas, le souci de bien jouer avec d’autres applications concurrentes est en faveur de la performance.
Reirab
Même s’il ne serait pas particulièrement efficace, ce scénario ne conduirait à aucune impasse: l’inversion des priorités s’en occuperait (dans l’hypothèse où tout ordonnanceur serait à peu près correct dans n’importe quel grand système d’exploitation de la dernière décennie)
Voo le
2
@Joshua > Windows ne sait pas ce qu'est l'inversion de priorité. Quelle? support.microsoft.com/kb/96418 , msdn.microsoft.com/en-us/library/windows/desktop/ms684831.aspx . En outre, l'inversion de priorité est le terme qui décrit le problème , pas une solution (@Voo).
Bob
3

Tout d'abord, les threads logiciels n'ont rien à voir avec les threads matériels et sont souvent mélangés. Les threads logiciels sont des morceaux de code pouvant être envoyés et exécutés séparément dans le contexte du processus. Les threads matériels sont principalement gérés par le système d'exploitation et sont envoyés au noyau du processeur lorsqu'il parle de programmes standard. Ces threads matériels sont distribués en fonction de la charge; le répartiteur de threads matériels agit plus ou moins comme un équilibreur de charge.

Toutefois, lorsqu'il s'agit de jeux, en particulier de jeux haut de gamme, les threads matériels sont parfois gérés par le jeu lui-même ou le jeu indique au répartiteur de threads quoi faire. En effet, chaque tâche ou groupe de tâches n'a pas la même priorité que dans un programme normal. Étant donné que Dragon Age est issu d’un studio de jeu haut de gamme utilisant des moteurs de jeu haut de gamme, je peux imaginer qu’il utilise la répartition "manuelle" et que le nombre de cœurs devient alors une exigence système minimale. N'importe quel programme se bloquerait lorsque j'enverrais une partie de code au 3ème cœur physique s'exécutant sur une machine avec seulement 1 ou 2 cœurs.

dj bazzie wazzie
la source
Cette. Rappelez-vous que dire "cocher non" signifie qu'une entreprise fabrique son logiciel de manière spécifique pour forcer les utilisateurs à acheter du matériel plus coûteux (ce qui serait mal intentionné).
Uylmz
2
Ces problèmes existent tant qu'il y a des jeux sur PC. Au début, nous avions 486dx et 486sx, puis les MMX et Pentium non-MMX, noyau et non-cœur, et nous avons aujourd'hui des exigences n-core. C'est l'une des raisons pour lesquelles les consoles existent encore.
dj bazzie wazzie
4
Avez-vous une référence pour les jeux prenant en charge la planification du processeur eux-mêmes? Autant que je sache, cela n'est pas directement possible sous Windows, du moins pas d'une manière qui échouerait comme vous le suggérez.
Jules
2
@djbazziewazzie en fait, Windows fournit une API pour ce faire, c'est-à-dire qu'un thread doit toujours utiliser le même noyau; Cela s'appelle affinité de thread et ne vous permet pas de sélectionner manuellement le morceau de code qui s'exécute où et quand, et ne peut pas provoquer une défaillance du système comme vous le suggérez (le système ignorera une demande pour définir l'affinité sur un noyau inexistant, et continuez à planifier le thread dans n'importe quel noyau dès qu'il sera disponible Je suis sûr que c'est ce que id Tech utilise, et cela ne revient pas vraiment à "gérer les threads matériels lui-même".
Jules
1
@djbazziewazzie Vous semblez également mal comprendre le sens de Grand Central Dispatch, qui ne donne pas aux développeurs davantage de contrôle sur la manière dont leur code est planifié; en fait, son objectif est exactement le contraire: il faut choisir le nombre de threads à créer et le code à exécuter sur tel thread, hors des mains des applications, de manière à ce qu'il puisse être optimisé pour le matériel disponible au niveau du système. La dépendance à un certain nombre de cœurs est exactement le type de problème que GCD a été conçu pour éviter.
Jules
1

Puisqu'il est possible d'utiliser la virtualisation pour avoir plus de cœurs virtuels que physiques et que le logiciel ne sache pas qu'il s'exécute sur une virtualisation et pense au contraire qu'il possède autant de cœurs physiques, je dirais qu'un tel logiciel n'est pas possible.

C'est-à-dire qu'il n'est pas possible d'écrire un logiciel qui s'arrête toujours sur moins de N cœurs.

Comme d'autres l'ont fait remarquer, certaines solutions logicielles peuvent potentiellement vérifier, en particulier si le système d'exploitation et le code utilisés offrent peu de protection contre les conditions de concurrence critique lorsque N processus s'exécutent sur <N processeurs. Le vrai truc, c'est que le code échouera si vous avez moins de N processeurs, mais pas lorsque vous avez N processeurs mais que votre système d'exploitation peut affecter le travail à moins de N processeurs.

Lawtonfogle
la source
1

Il se peut que trois threads agissent (générant des arrière-plans ou des mouvements de NPC) et transmettant des événements à un quatrième, censé agréger / filtrer les événements et mettre à jour le modèle de vue. Si le quatrième thread ne reçoit pas tous les événements (car il n'est pas planifié sur un core), le modèle de vue ne sera pas mis à jour correctement. Cela peut ne se produire que sporadiquement, mais ces cœurs doivent être disponibles à tout moment. Cela pourrait expliquer pourquoi vous ne voyez pas toujours une utilisation élevée du processeur, mais que le jeu ne fonctionne toujours pas correctement.

RGT
la source
1
Dans un tel scénario, le jeu échouerait également de manière aléatoire lorsque des services d'arrière-plan étaient planifiés, ce qui est assez fréquent sur la plupart des ordinateurs.
Jules
1

Je pense que Joshua se dirige dans la bonne voie, mais pas à sa conclusion.

Supposons que vous ayez une architecture dans laquelle trois threads sont écrits pour faire tout ce qu'ils peuvent: quand ils terminent ce qu'ils font, ils recommencent. Pour maintenir les performances, ces threads ne libèrent pas le contrôle, ils ne veulent pas risquer le décalage du planificateur de tâches Windows. Tant qu'il y a 4 noyaux ou plus, cela fonctionne très bien, sinon, il échoue.

En général, ce serait une mauvaise programmation, mais les jeux sont un autre problème - lorsque vous devez choisir entre une conception inférieure sur tout le matériel ou une conception supérieure sur un matériel suffisamment correct ou une défaillance sur un matériel inférieur, les développeurs de jeux choisissent généralement exiger le matériel.

Loren Pechtel
la source
Il n'est généralement pas possible d'écrire un thread qui ne cédera pas le contrôle à d'autres threads. Tous les systèmes d'exploitation modernes non-RTOS utilisent le multitâche préemptif, ce qui empêche intentionnellement un thread (en mode utilisateur) de ne pas libérer le contrôle d'un noyau donné. Les fils du noyau, bien sûr, sont une autre affaire.
Reirab
@reirab Boost sa priorité.
Loren Pechtel
@ Loren Ne change pas le fait que le planificateur meurt toujours, ce qui signifie que vous devez partager le temps avec d'autres threads de la même priorité et avec la priorité d'amplification du planificateur des threads affamés. Vous ne pouvez pas faire cela sur des systèmes d’exploitation normaux et même si vous le pouviez, les jeux ne seraient certainement pas une application acceptable de le faire non plus.
Voo le
1

Is it possible to write code (or complete software, rather than a piece of code) that won't work properly when run on a CPU that has less than N number of cores?

Absolument. L'utilisation de threads en temps réel serait un bon exemple d'une situation dans laquelle cela est non seulement possible, mais également la manière souhaitée (et souvent la seule manière correcte) de mener à bien la tâche. Cependant, les threads en temps réel sont généralement limités au noyau du système d'exploitation, généralement pour les pilotes qui doivent pouvoir garantir qu'un événement matériel est géré dans un laps de temps défini. Vous ne devriez pas avoir de threads en temps réel dans les applications utilisateur normales et je ne suis pas sûr qu'il soit même possible d'en avoir un dans une application en mode utilisateur Windows. Généralement, les systèmes d'exploitation rendent intentionnellement impossible d'effectuer cette opération depuis un utilisateur, précisément parce que cela permet à une application donnée de prendre le contrôle du système.

Concernant les applications utilisateur: Votre hypothèse selon laquelle la vérification d'un nombre donné de threads afin de l'exécuter est nécessairement malveillante dans l'intention n'est pas correcte. Par exemple, vous pouvez avoir 2 tâches de longue durée et à forte intensité de performances qui nécessitent un noyau pour elles-mêmes. Quelle que soit la vitesse du cœur du processeur, le partage d’un cœur avec d’autres threads peut entraîner une dégradation grave et inacceptable des performances en raison de la destruction des caches de cache et des pénalités normales encourues en cas de commutation de threads (assez conséquents). Dans ce cas, cela serait parfaitement raisonnable, spécialement pour un jeu, définissez chacun de ces threads de manière à avoir une affinité uniquement sur un noyau pour chacun d’eux, puis définissez tous vos autres threads de manière à ne pas avoir d’affinité sur ces 2 noyaux. Pour ce faire, cependant, vous '

reirab
la source
1

Tout code utilisant des spinlocks avec une quantité perceptible de conflits de verrous fonctionnera terriblement (dans une mesure où, pour une application comme un jeu, vous pouvez dire "ne fonctionne pas" ) si le nombre de threads dépasse le nombre de cœurs.

Imaginons par exemple un thread producteur qui soumet des tâches à une file qui dessert 4 threads grand public. Il n'y a que deux noyaux:

Le producteur essaie d’obtenir le spinlock, mais celui-ci est détenu par un consommateur utilisant l’autre noyau. Les deux cœurs fonctionnent en même temps que le producteur tourne, attendant que le verrou soit libéré. C'est déjà mauvais, mais pas aussi grave que cela va l'être.
Malheureusement, le thread consommateur est à la fin de son temps, il est donc préempté et un autre thread consommateur est planifié. Il essaie de mettre la main sur le verrou, mais bien sûr, le verrou est pris. À présent, deux cœurs tournent et attendent quelque chose d’inévitable.
Le fil producteur arrive à la fin de sa tranche de temps et est préempté, un autre consommateur se réveille. Encore une fois, deux consommateurs attendent la libération d'un verrou, et cela ne se produira tout simplement pas avant que deux délais supplémentaires soient écoulés.
[...] Enfin, le consommateur qui tenait le spinlock a relâché le verrou. Il est immédiatement pris par celui qui tourne sur l’autre noyau. Il y a 75% de chances (3 pour 1) que ce soit un autre fil de consommation. En d'autres termes, il est probable à 75% que le producteur soit toujours bloqué. Bien entendu, cela signifie également que les consommateurs stagnent. Sans les tâches médiocres du producteur, ils n'ont rien à faire.

Notez que cela fonctionne en principe avec n'importe quel type de verrouillage, pas seulement les spinlocks - mais l'effet dévastateur est beaucoup plus évident avec les spinlocks car le processeur continue de graver des cycles sans réaliser rien.

Maintenant, imaginez qu’en plus de ce qui précède, certains programmeurs eurent l’idée géniale d’utiliser un thread dédié avec une affinité définie sur le premier noyau. RDTSC donnera donc des résultats fiables sur tous les processeurs (ce n’est pas le cas, mais certains le pensent).

Damon
la source
C’est pourquoi les bons verrous spin rétrogradent peu de temps après à un autre type de verrou, et même mieux s’effectuent plus rapidement si les utilisations antérieures du même verrou ont dû être rétrogradées.
Ian
-1

Si je comprends ce que vous demandez, c'est possible, mais c'est une très, très mauvaise chose.

L'exemple canonique de ce que vous décrivez consisterait à maintenir un compteur incrémenté de plusieurs threads. Cela ne nécessite presque rien en termes de puissance de calcul mais nécessite une coordination minutieuse entre les threads. Tant qu'un seul thread à la fois effectue un incrément (qui est en fait une lecture suivie d'un ajout suivi d'une écriture), sa valeur sera toujours correcte. En effet, un thread lit toujours la valeur "précédente" correcte, en ajoute une et écrit la valeur "suivante" correcte. Obtenez deux threads dans l'action en même temps et les deux liront la même valeur "précédente", obtiendront le même résultat de l'incrément et écrivent la même valeur "suivante". Le compteur n'aura effectivement été incrémenté qu'une seule fois, même si deux threads pensent l'avoir fait.

Cette dépendance entre timing et exactitude est ce que l’informatique appelle une situation de concurrence critique .

Les conditions de concurrence sont souvent évitées en utilisant des mécanismes de synchronisation pour s'assurer que les threads souhaitant opérer sur une donnée partagée doivent se mettre en ligne pour accéder. Le compteur décrit ci-dessus peut utiliser un verrou en lecture-écriture pour cela.

Sans accès à la conception interne de Dragon Age: Inquisition , tout ce que l’on peut faire est de spéculer sur les raisons de son comportement. Mais je vais essayer quelques choses que j'ai vu faire dans ma propre expérience:

Il se peut que le programme soit basé sur quatre threads qui ont été ajustés pour que tout fonctionne lorsque les threads fonctionnent presque sans interruption sur leurs propres cœurs physiques. Le "réglage" peut prendre la forme de réarrangement de code ou d'insertion de couches de sommeil dans des endroits stratégiques afin d'atténuer les bugs induits par la race qui apparaissent lors du développement. Encore une fois, tout cela est une conjecture, mais j’ai vu les conditions de course «résolues» de cette façon plus de fois que je n’aimerais compter.

L'exécution d'un programme comme celui-ci sur un environnement moins capable que l'environnement pour lequel il a été configuré introduit des modifications de minutage résultant du code ne s'exécutant pas aussi rapidement ou, plus probablement, de changements de contexte. Les commutations de contexte se produisent de manière physique (les cœurs physiques de la CPU changent entre les tâches que ses cœurs logiques conservent) et logique (le système d’exploitation de la CPU attribue du travail aux cœurs), mais l’un ou l’autre de ces écarts serait le délai d'exécution "prévu". Cela peut faire ressortir un mauvais comportement.

Si Dragon Age: Inquisition ne prend pas la simple décision de s'assurer qu'il y a suffisamment de cœurs physiques disponibles avant de poursuivre, c'est la faute de EA. Ils dépensent probablement une petite fortune pour répondre aux appels de support et aux courriers électroniques de personnes qui ont essayé de lancer le jeu avec trop peu de matériel.

Blrfl
la source
1
Certains joueurs disent que cela est dû au fait que le DRM fonctionne sur 2 cœurs et que le jeu fonctionne également à 2. Lorsque les fils de DRM et de jeu fonctionnent sur le même noyau, cela se gâte. Mais cela ne me semble pas correct. Il s’agit peut-être d’une petite histoire composée par un joueur qui ne connaît pas beaucoup l’architecture sw ou hw.
Uylmz
4
Les conditions de course n’ont vraiment pas grand-chose à voir avec le nombre de cœurs, -1 ... une machine avec des threads virtuels multiples peut avoir des conditions de course totalement dépendantes de la technique de découpage du temps d’exécution, ou bien de nombreux systèmes de base peuvent éviter toutes les conditions de course dépendantes. sur la rigueur avec les opérations des membres ...
Jimmy Hoffa le
1
@ Reek: Sans une connaissance intime du fonctionnement du programme, rien n'est supposé. Deux cœurs à faire que le DRM me semble un peu excessif.
Blrfl
1
@ JimmyHoffa: Je ne suis pas d'accord. Une situation de concurrence demeure une situation de concurrence, même si elle ne provoque pas un comportement indésirable. Le nombre de noyaux peut influer sur le fait que ce comportement se produise ou non, c'est ce que le questionneur a demandé, mais je ne l'ai pas cité comme unique variable.
Blrfl
-1

Windows a des fonctionnalités intégrées pour cela: la fonction GetLogicalProcessorInformation est dans l' API Windows . Vous pouvez l'appeler depuis votre programme pour obtenir des informations sur les cœurs, les cœurs virtuels et l'hyperthreading.

Donc, la réponse à votre question serait: oui.

Pieter B
la source
3
Je ne demande pas "Puis-je trouver aucun noyau de code?" ... Un tel code sera mal intentionné (vous oblige à acheter un processeur plus coûteux pour exécuter un programme - sans besoin de puissance de calcul).
Uylmz
3
Cette fonction donne beaucoup plus d’informations qu’un simple "nombre de cœurs". Avec ces informations, vous pouvez déduire des cœurs physiques, des cœurs logiques, etc. Si vous pouvez déduire cela, vous pouvez alors écrire un logiciel pour utiliser ces informations. De manière positive ou négative (programme d'accident lorsque vous voyez 4 cœurs mais moins de 4 cœurs physiques).
Pieter B
1
Cela peut fonctionner sous Windows, mais qu’en est-il de OSX / Linux / iOS / Android / etc.? Bien qu'il fasse référence à un jeu en tant qu'instance où ce problème est observé (et la corrélation naturelle serait Windows = Jeu), il ne semble pas s'agir d'une requête spécifique à un jeu.
Robert le
Pour un jeu comme Dragon Age, les systèmes en question sont Windows / XBox / PS4.
Gort le robot
Linux a /proc/cpuinfoet sysconf(_SC_NPROCESSORS_ONLN)(ce dernier étant mentionné dans POSIX). L'utilisation de l'info pour imposer un seuil de performance minimum reste néanmoins une forme assez mauvaise.
cHao