Trouver par programme le nombre de cœurs sur une machine


464

Existe-t-il un moyen de déterminer le nombre de cœurs d'une machine en C / C ++ de manière indépendante de la plate-forme? Si une telle chose n'existe pas, qu'en est-il de la déterminer par plate-forme (Windows / * nix / Mac)?


4
Si vous voulez l'utiliser, découvrez combien de threads commencer, veuillez utiliser NUMBER_OF_PROCESSORS comme mesure principale. Je vous laisse comme un exercice pourquoi cela est beaucoup mieux (si les gens l'utilisent plus) que d'utiliser des cœurs matériels. Combien de cœurs appartiennent à votre programme sont un problème environnemental!
Lothar

Notez que std::thread::hardware_concurrencyrenvoie le nombre de cœurs de processeur physiques, mais nprocsous Linux affiche uniquement le nombre de cœurs de processeur sur lesquels le processus en cours peut s'exécuter, qui peut être contrôlé avec sched_setaffinity. Je n'ai pas trouvé de moyen d'obtenir cela à la place du C ++ standard, voir par exemple dans Python: stackoverflow.com/questions/1006289/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:


706

C ++ 11

#include <thread>

//may return 0 when not able to detect
const auto processor_count = std::thread::hardware_concurrency();

Référence: std :: thread :: hardware_concurrency


En C ++ avant C ++ 11, il n'y a pas de moyen portable. À la place, vous devrez utiliser une ou plusieurs des méthodes suivantes (protégées par des #ifdeflignes appropriées ):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
  • Linux, Solaris, AIX et Mac OS X> = 10,4 (c'est-à-dire Tiger à partir de)

    int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
  • FreeBSD, MacOS X, NetBSD, OpenBSD, etc.

    int mib[4];
    int numCPU;
    std::size_t len = sizeof(numCPU); 
    
    /* set the mib for hw.ncpu */
    mib[0] = CTL_HW;
    mib[1] = HW_AVAILCPU;  // alternatively, try HW_NCPU;
    
    /* get the number of CPUs from the system */
    sysctl(mib, 2, &numCPU, &len, NULL, 0);
    
    if (numCPU < 1) 
    {
        mib[1] = HW_NCPU;
        sysctl(mib, 2, &numCPU, &len, NULL, 0);
        if (numCPU < 1)
            numCPU = 1;
    }
  • HPUX

    int numCPU = mpctl(MPC_GETNUMSPUS, NULL, NULL);
  • IRIX

    int numCPU = sysconf(_SC_NPROC_ONLN);
  • Objective-C (Mac OS X> = 10.5 ou iOS)

    NSUInteger a = [[NSProcessInfo processInfo] processorCount];
    NSUInteger b = [[NSProcessInfo processInfo] activeProcessorCount];

5
@mcandre: cela reste un exercice pour le lecteur. Si je l'implémentais, j'utiliserais probablement une approche de modèle de politique où la politique était définie dans les directives du préprocesseur. Ou ... vous pouvez utiliser boost thread :: hardware_concurrency ().
paxos1977

3
à titre de clarification, la solution Win32 renvoie le nombre total de cœurs (ce qui a été demandé) et non le nombre total de CPU physiques.
Eric

1
La méthode Linux / Solaris / AIX fonctionne également sur FreeBSD et a depuis au moins 2006. De plus, cela rendra les CPU en ligne, si un système est capable de désactiver certains, ils pourraient ne pas être comptés. L'appel de sysconf avec "_SC_NPROCESSORS_CONF" renverra le nombre total de CPU configurés.
Chris S

3
Quelques choses à savoir. HW_NCPUest déconseillé sous OS X. Sous Windows, il GetSystemInfon'est utile que si votre système dispose de 32 processeurs logiques ou moins, à utiliser GetLogicalProcessorInformationpour les systèmes qui ont plus de 32 processeurs logiques.

1
@Trejkaz la documentaion dit clairement "logique" - qui compte toujours les cœurs HT, le mot "physique" fait toujours référence aux cœurs signalés par le BIOS / UEFI car les cœurs peuvent également être émulés / virtualisés. Vous pouvez différencier les cœurs HT / non-HT avec des fonctions comme GetLogicalProcessorInformation , par exemple. Remarque: HT! = Émulation ou virtualisation, c'est une grande différence, HT est une optimisation matérielle, pour ainsi dire
specializt

202

Cette fonctionnalité fait partie de la norme C ++ 11.

#include <thread>

unsigned int nthreads = std::thread::hardware_concurrency();

Pour les compilateurs plus anciens, vous pouvez utiliser la bibliothèque Boost.Thread .

#include <boost/thread.hpp>

unsigned int nthreads = boost::thread::hardware_concurrency();

Dans les deux cas, hardware_concurrency()renvoie le nombre de threads que le matériel est capable d'exécuter simultanément en fonction du nombre de cœurs de processeur et d'unités d'hyper-threading.


1
Secondé ... allait utiliser l'exemple de code ci-dessus et certaines macros de préprocesseur pour exposer une seule fonction, mais le travail a été fait pour moi.
jkp

Pour win32, c'est un appel à GetSystemInfo. (À partir de la version 1.41.0 de boost) Est-ce que cela capture toutes les informations pour déterminer combien de threads de travail seraient efficaces? Faut-il considérer à la fois le nombre de cœurs et l'hyper-threading? thread non signé :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& info); return info.dwNumberOfProcessors; }
Jive Dadson

Selon MSDN, GetSystemInfo () renvoie le nombre de "processeurs physiques" dans dwNumberOfProcessors mais il ne définit pas ce que cela signifie par cela. La documentation Boost semble prétendre qu'elle comprend des unités d'hyperthreading.
Ferruccio

voir stackoverflow.com/questions/642348/… pour l'hyperthreading
naugtur

57

OpenMP est pris en charge sur de nombreuses plates-formes (y compris Visual Studio 2005) et il offre un

int omp_get_num_procs();

fonction qui renvoie le nombre de processeurs / cœurs disponibles au moment de l'appel.


parce que c'est une mauvaise réponse. Depuis gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 "omp_get_num_procs () ne renverra qu'un nombre inférieur au nombre de CPU système en ligne, si GOMP_CPU_AFFINITY env var est utilisé, ou si le processus d'appel et / ou le thread a Affinité CPU limitée à un sous-ensemble de CPU ". Donc, si vous appelez plus tôt, par exemple, sched_setaffinitycela ne fonctionnera pas.
angainor

7
Cette fonction renvoie le nombre de CPU disponibles pour le processus appelant. N'est-ce pas le cas d'utilisation le plus courant? Surdimensionné à des fins de rapport inutiles, le nombre réel de cœurs de matériel CPU ne vous concerne pas si vous ne pouvez pas en tirer parti dans votre code.
macbirdie

@EvanTeran Outre le fait que c'était le but de la question, cela peut bien sûr être utile. Par exemple, dans le but de définir l'affinité de thread. Dites, je veux exécuter 4 threads liés à quatre derniers cœurs de processeur sur ma machine, au lieu de quatre premiers cœurs. Et en plus, il existe d'autres façons de paralléliser le code à l'exception d'OpenMP. Je veux peut-être générer des pthreads moi-même. Celles-ci sont sûrement disponibles et ne sont pas limitées par les variables d'environnement OpenMP.
angainor

2
Cela renvoie le nombre de CPU logiques, pas les cœurs (CPU physiques) en tant que tels.
Michael Konečný

37

Si vous disposez d'un accès en langage assembleur, vous pouvez utiliser l'instruction CPUID pour obtenir toutes sortes d'informations sur le processeur. Il est portable entre les systèmes d'exploitation, mais vous devrez utiliser des informations spécifiques au fabricant pour déterminer comment trouver le nombre de cœurs. Voici un document qui décrit comment le faire sur des puces Intel , et la page 11 de celui-ci décrit la spécification AMD.


4
Il a peut-être été déclassé car la question est balisée en C ++ et cette réponse ne s'applique pas aux systèmes exécutant C ++ sur des architectures non x86 (ARM, PPC, etc.). Je ne dis pas que c'est une bonne raison de voter contre une réponse, juste une possibilité.
Ferruccio

3
Un écueil de cette méthode est que si vous utilisez CPUID pour détecter HyperThreading sur les processeurs Intel. J'ai rencontré ce problème sur mon ordinateur portable: alors que le CPU que j'ai mis dans la machine prend en charge HyperThreading (et, bien sûr, signale qu'il le fait via CPUID), le BIOS ne le fait pas. Par conséquent, vous ne devriez pas essayer d'utiliser la capacité HT simplement à partir d'une lecture CPUID. Comme vous ne pouvez pas interroger le BIOS sur la prise en charge HT (pas du tout ce que j'ai vu), le système d'exploitation doit être interrogé pour obtenir le nombre de processeurs logiques.
Chuck R

32

(Presque) Fonction indépendante de la plateforme en code C

#ifdef _WIN32
#include <windows.h>
#elif MACOS
#include <sys/param.h>
#include <sys/sysctl.h>
#else
#include <unistd.h>
#endif

int getNumCores() {
#ifdef WIN32
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    return sysinfo.dwNumberOfProcessors;
#elif MACOS
    int nm[2];
    size_t len = 4;
    uint32_t count;

    nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
    sysctl(nm, 2, &count, &len, NULL, 0);

    if(count < 1) {
        nm[1] = HW_NCPU;
        sysctl(nm, 2, &count, &len, NULL, 0);
        if(count < 1) { count = 1; }
    }
    return count;
#else
    return sysconf(_SC_NPROCESSORS_ONLN);
#endif
}

Semble HW_NCPUobsolète sur la source

16

Sous Linux, vous pouvez lire le fichier / proc / cpuinfo et compter les cœurs.


Sauf que ça compte aussi les solutions hyperthreadées ou autres solutions SMT comme plus de cœurs ...
jakobengblom2

13
@Arafangion: l'hyperthreading n'est pas une véritable exécution parallèle, c'est une technologie pour réduire les frais généraux de commutation de contexte. Un processeur hyperthreadé ne peut exécuter qu'un seul thread à la fois, mais il peut stocker l'état architectural (valeurs de registre, etc.) de deux threads en même temps. Les caractéristiques de performance sont très différentes d'avoir deux cœurs.
Wim Coenen

7
@Wim: Ce n'est pas tout à fait correct. Les CPU avec hyperthreading ont généralement plusieurs ALU et peuvent envoyer plusieurs instructions par cycle. Si, en raison des dépendances de données et des blocages, toutes les ALU ne peuvent pas être occupées par un seul thread, ces ALU seront plutôt utilisées pour l'exécution simultanée du deuxième thread matériel.
Ben Voigt

11

Notez que "nombre de cœurs" peut ne pas être un nombre particulièrement utile, vous devrez peut-être le qualifier un peu plus. Comment voulez-vous compter les processeurs multithread tels que Intel HT, IBM Power5 et Power6, et surtout, les Niagara / UltraSparc T1 et T2 de Sun? Ou encore plus intéressant, le MIPS 1004k avec ses deux niveaux de threading matériel (superviseur ET niveau utilisateur) ... Sans parler de ce qui se passe lorsque vous passez dans des systèmes supportés par hyperviseur où le matériel peut avoir des dizaines de CPU mais votre OS particulier n'en voit que quelques-uns.

Le mieux que vous puissiez espérer est d'indiquer le nombre d'unités de traitement logique que vous avez dans votre partition OS locale. Oubliez de voir la vraie machine à moins que vous ne soyez un hyperviseur. La seule exception à cette règle est aujourd'hui en terre x86, mais la fin des machines non virtuelles arrive rapidement ...


7

Encore une recette Windows: utilisez la variable d'environnement à l'échelle du système NUMBER_OF_PROCESSORS:

printf("%d\n", atoi(getenv("NUMBER_OF_PROCESSORS")));

7

Vous ne pourrez probablement pas l'obtenir de manière indépendante de la plate-forme. Windows vous obtenez un certain nombre de processeurs.

Informations système Win32


1
Attention: les processeurs hyperthread disent qu'il y en a deux. Vous devez donc également voir si le processeur est capable d'hyperthread.
Martin York

6

Windows (x64 et Win32) et C ++ 11

Nombre de groupes de processeurs logiques partageant un seul cœur de processeur. (À l'aide de GetLogicalProcessorInformationEx , consultez également GetLogicalProcessorInformation )

size_t NumberOfPhysicalCores() noexcept {

    DWORD length = 0;
    const BOOL result_first = GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &length);
    assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);

    std::unique_ptr< uint8_t[] > buffer(new uint8_t[length]);
    const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = 
            reinterpret_cast< PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX >(buffer.get());

    const BOOL result_second = GetLogicalProcessorInformationEx(RelationProcessorCore, info, &length);
    assert(result_second != FALSE);

    size_t nb_physical_cores = 0;
    size_t offset = 0;
    do {
        const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX current_info =
            reinterpret_cast< PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX >(buffer.get() + offset);
        offset += current_info->Size;
        ++nb_physical_cores;
    } while (offset < length);

    return nb_physical_cores;
}

Notez que la mise en œuvre de NumberOfPhysicalCoresest à mon humble avis loin d'être triviale (c'est-à-dire "utiliser GetLogicalProcessorInformationou GetLogicalProcessorInformationEx"). Au lieu de cela, il est plutôt subtil si on lit la documentation (explicitement présente pour GetLogicalProcessorInformationet implicitement présente pour GetLogicalProcessorInformationEx) sur MSDN.

Le nombre de processeurs logiques. (Utilisation de GetSystemInfo )

size_t NumberOfSystemCores() noexcept {
    SYSTEM_INFO system_info;
    ZeroMemory(&system_info, sizeof(system_info));

    GetSystemInfo(&system_info);

    return static_cast< size_t >(system_info.dwNumberOfProcessors);
}

Notez que les deux méthodes peuvent facilement être converties en C / C ++ 98 / C ++ 03.


1
Je vous remercie! Je cherchais cela parce que je GetLogicalProcessorInformationne travaillais pas avec les différentes tailles de tampons que j'utilisais. Plus que satisfait! ^^
KeyWeeUsr

@KeyWeeUsr Merci La programmation Windows est quelque peu loin d'être triviale et logique. En attendant, j'utilise une version C ++ 17 légèrement plus mise à jour qui est aussi plus correcte selon l'analyseur statique PVS-Studio en ce qui concerne certains size_tcasts. (Bien que msvc ++ ne se plaigne pas à W4.)
Matthias

5

Plus sur OS X: sysconf(_SC_NPROCESSORS_ONLN)est disponible uniquement les versions> = 10.5, pas 10.4.

Une alternative est le HW_AVAILCPU/sysctl()code BSD qui est disponible sur les versions> = 10.2.



4

Sans rapport avec C ++, mais sous Linux, je fais habituellement:

grep processor /proc/cpuinfo | wc -l

Pratique pour les langages de script comme bash / perl / python / ruby.


4
Pour python:import multiprocessing print multiprocessing.cpu_count()
initzero

3
Cela fait longtemps, mais grepa un -cdrapeau pour compter les entrées!
Lapshin Dmitry

3

hwloc (http://www.open-mpi.org/projects/hwloc/) mérite d'être examiné. Bien qu'il nécessite une autre intégration de bibliothèque dans votre code mais il peut fournir toutes les informations sur votre processeur (nombre de cœurs, topologie, etc.)


3

Sous Linux, la meilleure façon de programmation, pour autant que je sache, est d'utiliser

sysconf(_SC_NPROCESSORS_CONF)

ou

sysconf(_SC_NPROCESSORS_ONLN)

Ce ne sont pas standard, mais sont dans ma page de manuel pour Linux.


3

Sous Linux, il n'est peut-être pas sûr de l'utiliser _SC_NPROCESSORS_ONLNcar il ne fait pas partie de la norme POSIX et le manuel sysconf l' indique autant. Il y a donc une possibilité qui _SC_NPROCESSORS_ONLNpeut ne pas être présente:

 These values also exist, but may not be standard.

     [...]     

     - _SC_NPROCESSORS_CONF
              The number of processors configured.   
     - _SC_NPROCESSORS_ONLN
              The number of processors currently online (available).

Une approche simple serait de les lire /proc/statou de les /proc/cpuinfocompter:

#include<unistd.h>
#include<stdio.h>

int main(void)
{
char str[256];
int procCount = -1; // to offset for the first entry
FILE *fp;

if( (fp = fopen("/proc/stat", "r")) )
{
  while(fgets(str, sizeof str, fp))
  if( !memcmp(str, "cpu", 3) ) procCount++;
}

if ( procCount == -1) 
{ 
printf("Unable to get proc count. Defaulting to 2");
procCount=2;
}

printf("Proc Count:%d\n", procCount);
return 0;
}

En utilisant /proc/cpuinfo:

#include<unistd.h>
#include<stdio.h>

int main(void)
{
char str[256];
int procCount = 0;
FILE *fp;

if( (fp = fopen("/proc/cpuinfo", "r")) )
{
  while(fgets(str, sizeof str, fp))
  if( !memcmp(str, "processor", 9) ) procCount++;
}

if ( !procCount ) 
{ 
printf("Unable to get proc count. Defaulting to 2");
procCount=2;
}

printf("Proc Count:%d\n", procCount);
return 0;
}

La même approche en shell utilisant grep:

grep -c ^processor /proc/cpuinfo

Ou

grep -c ^cpu /proc/stat # subtract 1 from the result

2

Alternative à OS X: La solution décrite précédemment basée sur [[NSProcessInfo processInfo] processorCount] n'est disponible que sur OS X 10.5.0, selon la documentation. Pour les versions antérieures d'OS X, utilisez la fonction Carbon MPProcessors ().

Si vous êtes un programmeur Cocoa, ne soyez pas paniqué par le fait qu'il s'agit de Carbon. Vous avez juste besoin d'ajouter le framework Carbon à votre projet Xcode et MPProcessors () sera disponible.



-2

vous pouvez également utiliser WMI dans .net mais vous dépendez alors du service wmi en cours d'exécution, etc. Parfois, cela fonctionne localement, mais échoue lorsque le même code est exécuté sur des serveurs. Je crois que c'est un problème d'espace de noms, lié aux "noms" dont vous lisez les valeurs.


-3

Sous Linux, vous pouvez extraire dmesg et filtrer les lignes où ACPI initialise les CPU, quelque chose comme:

dmesg | grep 'ACPI: Processor"

Une autre possibilité consiste à utiliser dmidecode pour filtrer les informations du processeur.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.