Comment hardwareConcurrency révèle les cœurs réels de votre CPU
Voyez comment les navigateurs indiquent les cœurs CPU avec navigator.hardwareConcurrency et des tests avec Workers, et ce que ce signal peut révéler.
BotBrowser Team
Vous préférez la doc produit maintenue ?
Cet article a une page équivalente dans le centre de documentation. Utilisez les docs pour le flux canonique, les flags à jour et la référence durable.
navigator.hardwareConcurrency est un simple nombre, mais c'est l'un des indices matériels que n'importe quel script peut lire sans demande d'autorisation. Il indique combien de processeurs logiques le navigateur peut utiliser et il est disponible dans le fil principal ainsi que dans tous les types de worker. Un site qui veut juger si la description d'un appareil est cohérente peut comparer ce nombre aux autres valeurs matérielles qu'il observe et au comportement réel du travail parallèle. Les sections suivantes traitent de ce que signifie cette valeur, de la raison pour laquelle elle varie d'une machine à l'autre, de ce qu'elle apporte à l'identification et de ce que doit satisfaire un nombre de cœurs cohérent, issu d'un profil. BotBrowser peut communiquer un même nombre de cœurs issu du profil de façon cohérente dans les contextes d'un test contrôlé ; il ne peut pas changer le nombre de cœurs de la machine hôte ni l'usage qu'un site fait de cette valeur.
Voir la vidéo
Cette vidéo en anglais met à l'épreuve quatre affirmations sur le nombre de cœurs signalé dans une page de laboratoire contrôlée : la lecture dans la console, les contextes Worker, un test de montée en charge chronométré sur un hôte Ubuntu, et ce que l'article dit d'un profil. Elle montre deux machines, pas une population.
Résumé rapide
navigator.hardwareConcurrencyindique des processeurs logiques, pas un débit garanti.- Les machines virtuelles, les conteneurs, la politique du navigateur et les CPU hybrides peuvent modifier la valeur.
- Comparez la valeur du fil principal et des workers avec la plateforme et la mémoire du profil.
- BotBrowser garde cohérente la valeur du profil ; Linux et Windows peuvent aussi aligner l'affinité CPU des Worker.
Sommaire
- Voir la vidéo
- Ce que signale navigator.hardwareConcurrency
- Pourquoi le nombre varie d'une machine à l'autre
- Ce que le signal apporte à l'identification
- Comment un nombre de cœurs est recoupé et pourquoi les remplacements échouent
- Vérifier un nombre de cœurs issu d'un profil
- Conclusion pratique
Ce que signale navigator.hardwareConcurrency
navigator.hardwareConcurrency peut refléter un invité limité à 2 vCPU, plutôt que le nombre de processeurs de l'hôte.
La propriété renvoie un entier qui compte les processeurs logiques disponibles pour exécuter des threads. Les processeurs logiques sont les cœurs physiques multipliés par le nombre de threads matériels par coeur, de sorte qu'un processeur à quatre cœurs avec multithreading simultané indique 8. MDN décrit la propriété comme le nombre de processeurs logiques disponibles pour le navigateur, et la spécification HTML du WHATWG ajoute qu'un agent utilisateur devrait plutôt exposer le nombre réel et n'employer une valeur plus basse que lorsqu'une limite existe ou lorsque l'objectif est de réduire le fingerprinting.
// Fil principal
console.log(navigator.hardwareConcurrency);
// Dans un worker dédié, un worker partagé ou un service worker
console.log(self.navigator.hardwareConcurrency);
Ce nombre est un indice de planification, pas une mesure de vitesse. Il ne dit ni la rapidité d'un coeur, ni si les cœurs sont des cœurs d'efficacité ou de performance, ni la charge de la machine à cet instant, ni combien de threads le système d'exploitation ordonnancera réellement pour la page. Deux machines qui indiquent 8 peuvent se comporter très différemment face à la même charge parallèle.
Les applications lisent cette valeur pour de bonnes raisons, par exemple pour choisir la taille d'un ensemble de workers, donc les navigateurs ne peuvent pas simplement la supprimer sans casser du code qui fonctionne. Elle ne demande en outre aucune autorisation et elle est exposée à tous les types de worker. Cette combinaison explique pourquoi le nombre reste visible et pourquoi l'objectif pratique est la cohérence entre les contextes, et non la suppression.
Pour le code d'une application, le bon réflexe consiste à traiter la valeur comme une borne supérieure pour un ensemble de workers, à laisser de la capacité au fil principal et à mesurer le débit réel avant de fixer une taille. Un ensemble égal au nombre indiqué peut entrer en concurrence avec le rendu et la gestion des interactions, et un ensemble plus grand aide rarement un travail limité par le CPU, car les threads supplémentaires attendent un processeur. Ce même nombre ne devrait jamais servir à décider d'une autorisation ni à justifier la collecte d'un profil matériel plus détaillé.
Pourquoi le nombre varie d'une machine à l'autre
Sous Linux, un conteneur peut fournir au navigateur une allocation cpuset.cpus de 2 vCPU plutôt que le total 16-core de l'hôte.
Plusieurs facteurs déterminent ce qu'un navigateur indique.
- Modèle de processeur. Le nombre de cœurs et de threads vient du CPU. Beaucoup de processeurs de bureau courants indiquent 8, 12 ou 16 processeurs logiques, tandis que les machines anciennes ou d'entrée de gamme peuvent en indiquer 2 ou 4. Apple silicon et d'autres conceptions hybrides mêlent des cœurs d'efficacité et de performance, et le total dépend de la puce.
- Machines virtuelles. Une machine virtuelle indique les CPU virtuels attribués par l'hyperviseur. Un hôte à 16 cœurs qui donne 2 CPU virtuels à un invité affiche 2 dans l'invité, quel que soit le matériel sous-jacent.
- Conteneurs et limites du système d'exploitation. Les environnements de conteneurs et les réglages de l'ordonnanceur peuvent restreindre le nombre de processeurs qu'un processus a le droit d'utiliser. Le fait que le navigateur voie cette restriction dépend de la manière dont la limite est appliquée.
- Politique du navigateur. La spécification permet à un agent utilisateur d'indiquer une valeur plus basse lorsqu'il fixe des limites ou veut réduire le fingerprinting, et certains navigateurs ont expérimenté le plafonnement ou le regroupement du nombre. Chromium indique actuellement le nombre exposé par le système d'exploitation.
Cette variation concerne d'abord les développeurs. La valeur lue dans un conteneur d'intégration continue ou sur une instance cloud est souvent très différente de celle du même navigateur sur un ordinateur portable, si bien qu'un test qui suppose un nombre précis peut réussir à un endroit et échouer à un autre. Lisez le nombre à l'exécution et traitez-le comme une entrée, jamais comme une constante.
Les valeurs typiques suivent le marché du matériel. Sur les ordinateurs de bureau, 4 et 8 sont les plus fréquents, et 6, 12 et 16 apparaissent sur certaines familles de processeurs. Au-delà de 16, on le voit surtout sur des stations de travail et des serveurs. Les téléphones indiquent souvent 4, 6 ou 8, selon la conception de la puce. Les nombres impairs comme 7 ou 13 sont rares parmi les processeurs commercialisés, ce qui prend de l'importance quand on envisage de choisir un nombre à la main.
Lorsqu'une charge de travail passe d'un environnement à un autre, comparez le nombre indiqué plutôt que la taille d'instance annoncée. Une instance cloud vendue avec un certain nombre de CPU virtuels peut indiquer une valeur différente dans un conteneur, et un ordinateur portable doté de cœurs d'efficacité peut indiquer plus de processeurs logiques qu'une lecture rapide de sa fiche technique ne le laisse penser. Consigner la valeur observée à côté de chaque résultat de benchmark supprime une source fréquente de confusion lorsque deux exécutions diffèrent. Dans une machine virtuelle, la valeur indiquée compte aussi pour la vérification de la mise à l'échelle décrite plus bas, car un invité avec 2 CPU virtuels ne peut réellement pas exécuter plus de deux threads à la fois. Un environnement cohérent est un environnement où le nombre indiqué et les processeurs disponibles concordent.
Ce que le signal apporte à l'identification
Les études de fingerprinting mesurent dans quelle mesure chaque attribut réduit une population. Les données d'AmIUnique situent navigator.hardwareConcurrency à environ 4,5 bits d'entropie, soit l'équivalent de séparer environ 23 groupes équiprobables. La distribution réelle est loin d'être égale : quelques valeurs courantes couvrent la plupart des navigateurs et les autres sont rares, de sorte que le découpage pratique est plus grossier que ce que le chiffre laisse penser.
Pris seul, ce nombre est un signal qui contribue, pas un identifiant unique. L'entropie s'accumule lorsque les attributs sont indépendants. Chaque bit supplémentaire réduit à peu près de moitié l'ensemble des navigateurs correspondants, si bien qu'un nombre de cœurs combiné à une taille d'écran, à un fuseau horaire et à une liste de polices restreint vite une population. Les attributs corrélés apportent moins, parce qu'un agent utilisateur qui désigne un téléphone précis implique déjà une courte liste de nombres de cœurs plausibles.
Une valeur rare restreint davantage. Un nombre de 24, 32 ou 64 suggère une station de travail ou un serveur, ce qui est peu courant dans les populations de navigation quotidienne. Le nombre ne dit rien d'une personne, mais il peut rendre une session plus facile à distinguer parmi d'autres qui indiquent 4 ou 8.
Les appareils mobiles ajoutent une couche supplémentaire. Certaines familles de puces associent un nombre précis à d'autres propriétés, comme la chaîne de plateforme et l'écran. Un téléphone qui indique 8 avec un motif d'agent utilisateur précis réduit l'appareil à une courte liste de modèles, ce qui donne plus d'information que chaque valeur isolée. La même logique vaut pour les ordinateurs de bureau : un nombre courant en lui-même devient plus distinctif lorsqu'il est associé à une valeur de mémoire ou à une plateforme inhabituelles.
Les navigateurs axés sur la confidentialité traitent ce compromis différemment. Plafonner ou regrouper le nombre réduit l'information qu'il porte, au prix d'un indice moins précis pour dimensionner les ensembles de workers. Les deux choix sont légitimes. La question utile pour un développeur est de savoir dans quelle mesure l'application dépend d'un nombre exact, et pour un responsable de la revue de confidentialité, combien d'autres indices matériels sont exposés à côté de lui.
Ces nombres sont des raisons d'être prudent, pas un verdict. Un navigateur qui indique un nombre courant n'est pas protégé contre les autres signaux, et un navigateur qui indique un nombre inhabituel n'est pas automatiquement signalé. Le nombre est une entrée parmi beaucoup d'autres, et son poids dépend de ce que la page peut voir d'autre.
Comment un nombre de cœurs est recoupé et pourquoi les remplacements échouent
La comparaison commence avec navigator.hardwareConcurrency et peut inclure une valeur renvoyée par un Worker créé depuis la même page.
Au-delà du nombre lui-même, un site peut se demander s'il est plausible. Trois formes de cohérence comptent lorsqu'un nombre de cœurs est indiqué.
- Plausibilité par rapport aux autres valeurs. Un nombre de cœurs doit avoir un sens avec la plateforme, l'agent utilisateur et l'indice de mémoire de l'appareil. Deux cœurs avec 8 Go de mémoire décrivent un petit ordinateur portable ou une machine virtuelle ordinaires. Un nombre de 64 cœurs à côté d'un agent utilisateur de téléphone décrit un matériel qui n'existe pas.
- Accord entre les contextes. Le fil principal, les workers dédiés, les workers partagés et les service workers doivent indiquer une seule et même valeur. Un seul script de page peut tous les lire, donc un écart entre contextes se remarque facilement.
- Accord avec le comportement parallèle. Un script pourrait exécuter la même tâche sur un nombre croissant de Workers et observer à partir de quand le temps d'exécution cesse de s'améliorer. Une machine à 4 processeurs logiques plafonne vers quatre Workers, alors qu'une machine à 16 continue de progresser plus longtemps.
Les paires à vérifier sont concrètes. Un agent utilisateur de bureau Windows avec 8 ou 16 processeurs logiques et 8 Go de mémoire indiquée est courant. Une plateforme Linux x86_64 avec 4 cœurs évoque un matériel de bureau ou de serveur ordinaire, tandis qu'une chaîne de plateforme ARM avec 8 cœurs suggère un téléphone ou un serveur ARM précis. Aucune de ces paires ne prouve quoi que ce soit seule ; chacune doit simplement éviter de contredire le reste de la description.
L'accord entre contextes mérite de l'attention, car les workers sont créés depuis la page et partagent son origine, mais chacun possède sa propre portée globale. Un worker dédié, un worker partagé utilisé par plusieurs onglets et un service worker qui survit à une page lisent la propriété de façon indépendante, donc toute modification faite pour la page doit être appliquée dans chacun d'eux et vérifiée séparément.
La troisième vérification relève plus de la possibilité que de la mesure courante. Les navigateurs réduisent la précision des minuteurs, et les outils de mesure à mémoire partagée comme SharedArrayBuffer exigent une page isolée entre origines avec les en-têtes COOP et COEP. Ces exigences limitent la précision avec laquelle une page peut mesurer la mise à l'échelle ; il vaut donc mieux y voir une raison de plus d'aligner le nombre indiqué sur le comportement réel, et non un résultat certain.
La façon dont un site donné pondère ces vérifications ne s'observe pas de l'extérieur. Ce sont des objectifs de cohérence, pas des prédictions de ce que conclura un site particulier.
Quand le nombre de cœurs est faux, l'écart apparaît dans un ordre fixe. Le fil principal est le premier endroit à regarder, car un script injecté dans la page ne modifie généralement que cette portée. Un worker dédié créé à partir d'une URL de Blob vient ensuite, puisqu'il tient en trois lignes et révèle un remplacement qui n'a jamais atteint les portées de worker. Un worker partagé et un service worker suivent, car ils demandent plus de préparation mais lisent eux aussi la propriété depuis leur propre portée globale. La mémoire de l'appareil et la chaîne de plateforme viennent en dernier, comme contrôles de plausibilité du nombre sur lequel s'accordent les quatre contextes.
Une personne qui relit peut suivre cet ordre en quatre lectures. Notez navigator.hardwareConcurrency dans la page, puis self.navigator.hardwareConcurrency dans un worker dédié, un worker partagé et un service worker, et comparez les quatre nombres. Lisez l'indice de mémoire de l'appareil et la chaîne de plateforme dans la même session pour juger le nombre à côté du reste de la description. L'exécution de mise à l'échelle décrite plus bas est une cinquième passe et exige un hôte Linux ou Windows.
Un résultat concordant est banal : les quatre contextes renvoient 4, la mémoire de l'appareil indique 8, la chaîne de plateforme concorde avec le profil et un benchmark cesse de progresser vers quatre Workers. Un écart se lit aussi facilement. Une page qui renvoie 4 alors qu'un worker dédié renvoie 32 pointe vers un remplacement au niveau de la page, pas vers le matériel. Quatre contextes concordants avec un nombre qui contredit la plateforme ou l'indice de mémoire pointent vers un profil modifié isolément, et des contextes concordants qui dépassent encore le nombre déclaré pointent vers l'absence d'affinité CPU sous macOS.
Écraser Navigator.prototype.hardwareConcurrency dans une page ne met pas à jour WorkerNavigator.hardwareConcurrency dans le global séparé d'un worker.
La manière courante de changer la valeur consiste à écraser la propriété depuis une extension ou un script injecté. Cela change le nombre renvoyé par le fil principal et laisse trois failles.
- Écart de mise à l'échelle. Si la propriété indique 4 alors que la machine a 16 cœurs, le travail parallèle se termine plus tôt que ne le permettrait une machine à 4 cœurs. L'affirmation et le comportement divergent dès que quelqu'un mesure.
- Failles entre contextes. Un remplacement appliqué seulement à l'objet
navigatorde la page n'atteint pas les portées de worker s'il n'y est pas aussi injecté, si bien qu'un worker peut encore renvoyer la valeur réelle. - Description partielle de l'appareil. Un nouveau nombre qui n'est pas coordonné avec l'agent utilisateur, la plateforme et l'indice de mémoire peut les contredire.
Les valeurs aléatoires aggravent la troisième faille. Un nombre de 7 ou de 13 correspond rarement à un matériel commercialisé. Même une valeur courante fixe comme 8 contredit un agent utilisateur qui désigne un téléphone dont la puce a 4 cœurs. Une propriété modifiée isolément n'est digne de confiance que dans la mesure de la plus faible des autres valeurs qui l'entourent.
La faille entre contextes est la plus facile à trouver des trois. Une page de test peut créer un worker dédié à partir d'une URL de Blob, renvoyer la valeur et la comparer à celle du fil principal en quelques lignes. Un worker partagé et un service worker demandent un peu plus de préparation, mais la comparaison est la même, et toute différence est un défaut du remplacement, pas une propriété du matériel.
L'exigence est donc la cohérence : une seule valeur, indiquée dans tous les contextes, qui s'accorde avec le reste de la description de l'appareil et avec la manière dont le travail parallèle évolue. Maintenir cette cohérence à la main sur toutes ces surfaces est la partie qui devient risquée.
Vérifier un nombre de cœurs issu d'un profil
Le premier contrôle consigne navigator.hardwareConcurrency dans le fil principal et dans chaque Worker.
Une configuration fondée sur un profil prend le nombre dans un profil d'appareil complet plutôt que dans un remplacement fait à la main. Il n'existe pas d'option distincte pour le nombre de cœurs, car la valeur vient du profil. Quatre vérifications montrent si le résultat est cohérent.
- Valeur. Lisez la propriété et confirmez qu'elle est égale au nombre de cœurs du profil et non à celui de l'hôte.
- Contextes. Lisez-la dans un worker dédié, un worker partagé et un service worker, et confirmez que chacun correspond au fil principal.
- Plausibilité. Confirmez que le nombre est réaliste pour la plateforme, l'agent utilisateur et la mémoire de l'appareil du profil.
- Stabilité. Lisez-la sur plusieurs sessions avec le même profil et confirmez qu'elle ne change jamais.
| Vérification | Où la lire | Résultat attendu avec un profil de 4 cœurs |
|---|---|---|
| Valeur du fil principal | navigator.hardwareConcurrency dans la page | 4, et non le 32 de l'hôte |
| Valeur dans un worker | self.navigator.hardwareConcurrency dans un worker dédié | 4, identique au fil principal |
| Worker partagé et service worker | la même propriété dans chaque portée globale | 4 dans les deux, sans écart entre contextes |
| Plausibilité | le nombre à côté des indices de plateforme et de mémoire | 4 convient au profil mobile, 32 non |
const source = 'postMessage(self.navigator.hardwareConcurrency)';
const blob = new Blob([source], { type: 'text/javascript' });
const worker = new Worker(URL.createObjectURL(blob));
worker.onmessage = event => console.log('worker:', event.data, 'main:', navigator.hardwareConcurrency);
Si une vérification échoue, les causes habituelles sont peu nombreuses.
- La valeur affiche le nombre de cœurs de l'hôte. Le profil n'a pas été chargé ou ne contient pas le nombre de cœurs attendu. La valeur vient du profil, donc vérifiez d'abord le fichier du profil.
- Un travail parallèle reste rapide sous macOS. macOS n'expose pas l'interface d'affinité CPU que Linux et Windows utilisent, donc les Workers s'exécutent sur tous les cœurs. La valeur indiquée vient toujours du profil, mais le temps parallèle peut ne pas correspondre. Utilisez Linux ou Windows lorsque le comportement de mise à l'échelle compte.
- Les Workers semblent lents. C'est attendu lorsqu'un profil déclare moins de cœurs que l'hôte, car les Workers sont volontairement limités au nombre déclaré.
La mise à l'échelle est la cinquième vérification et elle dépend de la plateforme. Sur un hôte qui a plus de cœurs que ne le déclare le profil, un travail parallèle réparti sur plus de Workers que le nombre déclaré devrait cesser de s'accélérer près de ce nombre. Lorsque plusieurs instances du navigateur partagent un hôte, chaque instance est limitée indépendamment par son propre profil, si bien qu'un profil à 4 cœurs et un profil à 8 cœurs sur le même serveur montrent des courbes de mise à l'échelle différentes qui correspondent à leurs déclarations respectives.
Un exemple concret montre l'effet. Un serveur de compilation à 32 cœurs exécute un profil mobile qui déclare 4 cœurs. Le profil indique 4 dans tous les contextes et les Workers sont limités à quatre cœurs physiques, de sorte qu'un benchmark parallèle avec 8 Workers cesse de s'accélérer vers quatre Workers et montre la courbe de montée en charge d'une machine à 4 cœurs, et non celle que l'hôte pourrait atteindre. La vitesse absolue dépend toujours des performances par coeur de l'hôte, généralement supérieures à celles d'un téléphone.
Le même hôte à 32 cœurs peut servir un profil de 4 cœurs dans plusieurs contextes de navigateur à la fois. Ouvrez trois ou quatre pages avec le même profil, lisez navigator.hardwareConcurrency dans chaque page et ouvrez un worker depuis chaque page pour y lire self.navigator.hardwareConcurrency. Chaque page et chaque worker devraient renvoyer 4, tandis que l'hôte lu hors du navigateur contrôlé renvoie 32. Si un contexte renvoie 32, ce contexte a été créé sans le profil et non par le profil, donc comparez la façon dont chaque contexte a été lancé avant d'accuser le profil.
De bonnes habitudes gardent le résultat prévisible. Utilisez un profil complet plutôt que d'écraser une seule propriété, choisissez un profil dont le nombre de cœurs convient à sa plateforme et à sa mémoire, testez toujours les contextes de worker et évitez d'ajuster le nombre à la main. Si le nombre indiqué doit changer, changez de profil, car les autres valeurs de l'appareil relèvent de la même description. Vous trouverez plus de détails dans le guide sur la protection des propriétés de navigator, le guide de l'API de mémoire de l'appareil, le guide de planification des workers et la vue d'ensemble du fingerprinting du navigateur.
Conservez une courte trace écrite de chaque vérification pour pouvoir comparer un changement ultérieur : le profil utilisé, la plateforme de l'hôte, la valeur lue dans le fil principal et dans chaque type de worker, et le résultat de mise à l'échelle sous Linux ou Windows. Si cette trace nomme aussi la version du navigateur et celle du profil, il est facile de savoir si une différence ultérieure vient du profil, du navigateur ou de l'hôte.
BotBrowser peut maintenir cohérent le navigator.hardwareConcurrency du profil dans le fil principal et dans les workers, et sous Linux et Windows il applique l'affinité CPU aux threads de Worker pour que la mise à l'échelle des benchmarks parallèles corresponde au nombre de cœurs déclaré. Cela aide lorsqu'un hôte plus grand exécute un profil avec moins de cœurs, car le nombre indiqué et la manière dont le travail parallèle évolue restent en accord. Il ne peut pas ajouter de vrais cœurs CPU ni modifier le matériel de l'hôte, il ne contraint pas les Workers par l'affinité CPU sous macOS, où le temps parallèle peut ne pas correspondre au profil, et il ne garantit pas la façon dont un site interprète le signal.
Conclusion pratique
Traitez le nombre indiqué comme une entrée de planification bornée. Lisez-le dans chaque contexte de worker, comparez-le à la plateforme du profil et utilisez Linux ou Windows lorsque l'affinité CPU fait partie du test. Modifiez le profil plutôt que de corriger une propriété à la main.
Sources publiques
Cet article fait partie du guide : Qu'est-ce qu'une empreinte de navigateur ?
Articles Connexes
Fingerprinting Navigator : fuites du navigateur
Plateformenavigator.hardwareConcurrency : pool de Workers mesuré
EmpreinteProfondeur de pile JavaScript : un signal de confidentialité
EmpreinteFingerprinting CSS : comment les styles vous suivent
EmpreinteFingerprinting MIME et codec : signaux de prise en charge
EmpreinteFingerprinting de la Network Information API : revue de politique
Faites passer BotBrowser de la recherche à la production
Utilisez ces guides pour comprendre le modèle, puis passez à la validation multi-plateforme, aux contextes isolés et au déploiement navigateur prêt pour l'échelle.