Ermitteln Sie programmgesteuert die Anzahl der Kerne auf einer Maschine

464

Gibt es eine Möglichkeit, plattformunabhängig zu bestimmen, wie viele Kerne eine Maschine aus C / C ++ hat? Wenn es so etwas nicht gibt, wie wäre es dann mit der Ermittlung pro Plattform (Windows / * nix / Mac)?

Hazzen
quelle
4
Wenn Sie es verwenden möchten, um herauszufinden, wie viele Threads gestartet werden sollen, verwenden Sie bitte NUMBER_OF_PROCESSORS als primäre Kennzahl. Ich überlasse es Ihnen als Übung, warum dies viel besser ist (wenn die Leute es mehr verwenden würden) als Hardware-Kerne zu verwenden. Wie viele Kerne zu Ihrem Programm gehören, ist ein Umweltproblem!
Lothar
Beachten Sie, dass std::thread::hardware_concurrencydie Anzahl der physischen CPU-Kerne zurückgegeben wird, nprocunter Linux jedoch nur die Anzahl der CPU-Kerne angezeigt wird, auf denen der aktuelle Prozess ausgeführt werden kann und mit denen gesteuert werden kann sched_setaffinity. Ich habe keinen Weg gefunden, dies stattdessen aus Standard-C ++ zu erhalten: siehe z. B. in Python: stackoverflow.com/questions/1006289/…
Ciro Santilli 5 冠状 病 六四 事件 5

Antworten:

706

C ++ 11

#include <thread>

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

Referenz: std :: thread :: hardware_concurrency


In C ++ vor C ++ 11 gibt es keinen portablen Weg. Stattdessen müssen Sie eine oder mehrere der folgenden Methoden verwenden (geschützt durch entsprechende #ifdefZeilen):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
  • Linux, Solaris, AIX und Mac OS X> = 10.4 (dh Tiger ab)

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

    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 oder iOS)

    NSUInteger a = [[NSProcessInfo processInfo] processorCount];
    NSUInteger b = [[NSProcessInfo processInfo] activeProcessorCount];
paxos1977
quelle
5
@mcandre: Das bleibt als Übung für den Leser. Wenn ich implementieren würde, würde ich wahrscheinlich einen Vorlagenrichtlinienansatz verwenden, bei dem die Richtlinie in Präprozessoranweisungen definiert wurde. Oder ... Sie könnten boost thread :: hardware_concurrency () verwenden.
paxos1977
3
Zur Verdeutlichung gibt die Win32-Lösung die Gesamtzahl der Kerne (was angefordert wurde) und nicht die Gesamtzahl der physischen CPUs zurück.
Eric
1
Die Linux / Solaris / AIX-Methode funktioniert auch unter FreeBSD und ist seit mindestens 2006 verfügbar. Außerdem werden die CPUs online zurückgegeben, wenn ein System in der Lage ist, einige auszuschalten, werden sie möglicherweise nicht gezählt. Wenn Sie sysconf mit "_SC_NPROCESSORS_CONF" aufrufen, werden die insgesamt konfigurierten CPUs zurückgegeben.
Chris S
3
Ein paar Dinge, die Sie beachten sollten. HW_NCPUist unter OS X veraltet. Unter Windows GetSystemInfoist es nur nützlich, wenn Ihr System über 32 logische Prozessoren oder weniger verfügt. Verwenden Sie es GetLogicalProcessorInformationfür Systeme mit mehr als 32 logischen Prozessoren.
1
@Trejkaz die Dokumentation sagt deutlich "logisch" - was immer HT-Kerne zählt, das Wort "physisch" bezieht sich immer auf Kerne, die vom BIOS / UEFI gemeldet werden, da Kerne auch emuliert / virtualisiert werden können. Sie können beispielsweise mit Funktionen wie GetLogicalProcessorInformation zwischen HT- und Nicht-HT-Kernen unterscheiden . Hinweis: HT! = Emulation oder Virtualisierung, das ist ein großer Unterschied, HT ist sozusagen eine Hardwareoptimierung
spezialisiert auf den
202

Diese Funktionalität ist Teil des C ++ 11-Standards.

#include <thread>

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

Für ältere Compiler können Sie die Boost.Thread- Bibliothek verwenden.

#include <boost/thread.hpp>

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

Gibt in beiden Fällen hardware_concurrency()die Anzahl der Threads zurück, die die Hardware gleichzeitig ausführen kann, basierend auf der Anzahl der CPU-Kerne und Hyper-Threading-Einheiten.

Ferruccio
quelle
1
Seconded ... wollte den obigen Beispielcode und einige Präprozessor-Makros verwenden, um eine einzelne Funktion verfügbar zu machen, aber die harte Arbeit wurde für mich erledigt.
JKP
Für win32 ist es ein Aufruf von GetSystemInfo. (Ab Boost Version 1.41.0) Erfasst das alle Informationen, um zu bestimmen, wie viele Arbeitsthreads effektiv wären? Muss man sowohl die Anzahl der Kerne als auch das Hyper-Threading berücksichtigen? unsigned thread :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& info); return info.dwNumberOfProcessors; }
Jive Dadson
Laut MSDN gibt GetSystemInfo () die Anzahl der "physischen Prozessoren" in dwNumberOfProcessors zurück, definiert jedoch nicht, was dies bedeutet. Die Boost-Dokumentation scheint zu behaupten, dass sie Hyperthreading-Einheiten enthält.
Ferruccio
siehe stackoverflow.com/questions/642348/… für Hyperthreading
naugtur
57

OpenMP wird auf vielen Plattformen (einschließlich Visual Studio 2005) unterstützt und bietet eine

int omp_get_num_procs();

Funktion, die die Anzahl der zum Zeitpunkt des Aufrufs verfügbaren Prozessoren / Kerne zurückgibt.

Macbirdie
quelle
weil es eine falsche Antwort ist. Von gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 "omp_get_num_procs () gibt nur dann eine geringere Anzahl als die Anzahl der Online-System-CPUs zurück, wenn GOMP_CPU_AFFINITY env var verwendet wird oder wenn der aufrufende Prozess und / oder Thread verwendet wird CPU-Affinität auf eine Teilmenge von CPUs beschränkt ". Wenn Sie also früher anrufen, z. B. sched_setaffinityfunktioniert dies nicht.
Angainor
7
Diese Funktion gibt die Anzahl der für den aufrufenden Prozess verfügbaren CPUs zurück. Ist es nicht sowieso der häufigste Anwendungsfall? Aufgrund der Größe einiger nutzloser Berichtszwecke ist die tatsächliche Anzahl der CPU-Hardwarekerne für Sie nicht relevant, wenn Sie sie in Ihrem Code nicht nutzen können.
Macbirdie
@EvanTeran Neben der Tatsache, dass es der Zweck der Frage war, kann es natürlich nützlich sein. Zum Beispiel zum Einstellen der Thread-Affinität. Angenommen, ich möchte 4 Threads ausführen, die an vier letzte CPU-Kerne auf meinem Computer gebunden sind, anstatt vier erste Kerne. Außerdem gibt es außer OpenMP andere Möglichkeiten, den Code zu parallelisieren. Ich möchte vielleicht selbst Pthreads erzeugen. Diese sind sicherlich verfügbar und nicht durch OpenMP-Umgebungsvariablen eingeschränkt.
Angainor
2
Dies gibt die Anzahl der logischen CPUs zurück, nicht die Kerne (physische CPUs) als solche.
Michael Konečný
37

Wenn Sie Zugriff auf Assemblersprache haben, können Sie den CPUID-Befehl verwenden, um alle möglichen Informationen über die CPU abzurufen. Es ist zwischen Betriebssystemen portierbar, obwohl Sie herstellerspezifische Informationen verwenden müssen, um die Anzahl der Kerne zu ermitteln. Hier ist ein Dokument, das beschreibt, wie es auf Intel-Chips gemacht wird , und Seite 11 dieses Dokuments beschreibt die AMD-Spezifikation.

Head Geek
quelle
4
Es wurde möglicherweise abgelehnt, weil die Frage als C ++ gekennzeichnet ist und diese Antwort nicht für Systeme gilt, auf denen C ++ auf Nicht-x86-Architekturen (ARM, PPC usw.) ausgeführt wird. Ich sage nicht, dass es ein guter Grund ist, eine Antwort abzulehnen, nur eine Möglichkeit.
Ferruccio
3
Eine Gefahr dieser Methode besteht darin, dass Sie CPUT verwenden, um HyperThreading auf Intel-Prozessoren zu erkennen. Auf meinem Laptop ist dieses Problem aufgetreten: Während die CPU, die ich in den Computer eingebaut habe, HyperThreading unterstützt (und natürlich meldet, dass dies über die CPUID erfolgt), funktioniert dies im BIOS nicht. Daher sollten Sie nicht versuchen, die HT-Funktion einfach über einen CPUID-Lesevorgang zu nutzen. Da Sie das BIOS nicht nach der HT-Unterstützung abfragen können (wie ich es noch nicht gesehen habe), sollte das Betriebssystem abgefragt werden, um die Anzahl der logischen Prozessoren zu ermitteln.
Chuck R
32

(Fast) Plattformunabhängige Funktion im C-Code

#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
}
Dirk-Jan Kroon
quelle
Scheint HW_NCPUveraltet auf OS X Quelle
16

Unter Linux können Sie die Datei / proc / cpuinfo lesen und die Kerne zählen.

JesperE
quelle
Abgesehen davon, dass dies auch Hyperthreaded- oder andere SMT-Lösungen als weitere Kerne zählt ...
jakobengblom2
13
@Arafangion: Hyperthreading ist keine echte parallele Ausführung, sondern eine Technologie zur Reduzierung des Overheads bei der Kontextumschaltung. Eine Hyperthread-CPU kann jeweils nur einen Thread ausführen , jedoch den Architekturstatus (Registerwerte usw.) von zwei Threads gleichzeitig speichern. Die Leistungsmerkmale unterscheiden sich stark von denen mit zwei Kernen.
Wim Coenen
7
@ Wim: Das ist nicht ganz richtig. CPUs mit Hyperthreading haben im Allgemeinen mehrere ALUs und können mehrere Anweisungen pro Zyklus senden. Wenn aufgrund von Datenabhängigkeiten und Verzögerungen nicht alle ALUs von einem Thread belegt werden können, werden diese ALUs stattdessen für die gleichzeitige Ausführung des zweiten Hardware-Threads verwendet.
Ben Voigt
11

Beachten Sie, dass "Anzahl der Kerne" möglicherweise keine besonders nützliche Zahl ist. Möglicherweise müssen Sie sie etwas weiter qualifizieren. Wie möchten Sie Multithread-CPUs wie Intel HT, IBM Power5 und Power6 und vor allem Suns Niagara / UltraSparc T1 und T2 zählen? Oder noch interessanter ist das MIPS 1004k mit seinen zwei Hardware-Threading-Ebenen (Supervisor- UND Benutzerebene) ... Ganz zu schweigen davon, was passiert, wenn Sie auf von Hypervisor unterstützte Systeme umsteigen, auf denen die Hardware möglicherweise mehrere zehn CPUs hat, aber Ihr spezielles Betriebssystem sieht nur wenige.

Das Beste, auf das Sie hoffen können, ist, die Anzahl der logischen Verarbeitungseinheiten in Ihrer lokalen Betriebssystempartition anzugeben. Vergessen Sie, die wahre Maschine zu sehen, es sei denn, Sie sind ein Hypervisor. Die einzige Ausnahme von dieser Regel ist heute in x86-Land, aber das Ende nicht virtueller Maschinen kommt schnell ...

jakobengblom2
quelle
7

Noch ein Windows-Rezept: Verwenden Sie die systemweite Umgebungsvariable NUMBER_OF_PROCESSORS:

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

Sie werden es wahrscheinlich nicht plattformunabhängig bekommen können. Windows erhalten Sie Anzahl der Prozessoren.

Win32-Systeminformationen

Ken
quelle
1
Vorsicht: Hyperthread-Prozessoren sagen, dass es zwei gibt. Sie müssen also auch prüfen, ob der Prozessor Hyperthread-fähig ist.
Martin York
6

Windows (x64 und Win32) und C ++ 11

Die Anzahl der Gruppen logischer Prozessoren, die sich einen einzelnen Prozessorkern teilen. (Verwenden von GetLogicalProcessorInformationEx , siehe auch 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;
}

Beachten Sie, dass die Implementierung von NumberOfPhysicalCoresIMHO alles andere als trivial ist (dh "use GetLogicalProcessorInformationor GetLogicalProcessorInformationEx"). Stattdessen ist es ziemlich subtil, wenn man die Dokumentation (explizit vorhanden für GetLogicalProcessorInformationund implizit vorhanden für GetLogicalProcessorInformationEx) bei MSDN liest .

Die Anzahl der logischen Prozessoren. (Verwenden von 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);
}

Beachten Sie, dass beide Methoden problemlos in C / C ++ 98 / C ++ 03 konvertiert werden können.

Matthias
quelle
1
Vielen Dank! Ich habe danach gesucht, weil ich GetLogicalProcessorInformationnicht mit verschiedenen Puffergrößen gearbeitet habe, die ich verwendet habe. Mehr als zufrieden! ^^
KeyWeeUsr
@KeyWeeUsr Dank Windows-Programmierung ist alles andere als trivial und logisch. In der Zwischenzeit verwende ich eine etwas aktuellere C ++ 17-Version, die laut dem statischen Analysator PVS-Studio in Bezug auf einige size_tCasts auch korrekter ist . (Obwohl sich msvc ++ bei W4 nicht beschwert.)
Matthias
5

Mehr zu OS X: sysconf(_SC_NPROCESSORS_ONLN) ist nur für Versionen> = 10.5 verfügbar, nicht für 10.4.

Eine Alternative ist der HW_AVAILCPU/sysctl()BSD-Code, der in Versionen> = 10.2 verfügbar ist.

sezero
quelle
4

Nicht mit C ++ verwandt, aber unter Linux mache ich normalerweise:

grep processor /proc/cpuinfo | wc -l

Praktisch für Skriptsprachen wie bash / perl / python / ruby.

Chris
quelle
4
Für Python:import multiprocessing print multiprocessing.cpu_count()
Initzero
3
Es ist schon eine lange Zeit, aber grephat -cFlagge zu zählen Einträge!
Lapshin Dmitry
3

hwloc (http://www.open-mpi.org/projects/hwloc/) ist einen Blick wert. Erfordert zwar eine weitere Bibliotheksintegration in Ihren Code, kann jedoch alle Informationen zu Ihrem Prozessor (Anzahl der Kerne, Topologie usw.) bereitstellen.

Akhil
quelle
3

Unter Linux ist die beste programmatische Methode, soweit ich weiß, die Verwendung

sysconf(_SC_NPROCESSORS_CONF)

oder

sysconf(_SC_NPROCESSORS_ONLN)

Diese sind nicht Standard, befinden sich aber in meiner Manpage für Linux.

Evan Teran
quelle
3

Unter Linux ist die Verwendung möglicherweise nicht sicher, _SC_NPROCESSORS_ONLNda es nicht Teil des POSIX-Standards ist und das sysconf- Handbuch dies auch angibt. Es gibt also eine Möglichkeit, die _SC_NPROCESSORS_ONLNmöglicherweise nicht vorhanden ist:

 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).

Ein einfacher Ansatz wäre, sie zu lesen /proc/statoder zu /proc/cpuinfozählen:

#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;
}

Verwenden von /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;
}

Der gleiche Ansatz in der Shell mit grep:

grep -c ^processor /proc/cpuinfo

Oder

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

OS X-Alternative: Die zuvor beschriebene Lösung basierend auf [[NSProcessInfo processInfo] processorCount] ist gemäß den Dokumenten nur unter OS X 10.5.0 verfügbar. Verwenden Sie für frühere Versionen von OS X die Carbon-Funktion MPProcessors ().

Wenn Sie ein Kakao-Programmierer sind, lassen Sie sich nicht von der Tatsache ausflippen, dass dies Carbon ist. Sie müssen lediglich das Carbon-Framework zu Ihrem Xcode-Projekt hinzufügen, und MPProcessors () ist verfügbar.

gauss256
quelle
2

Für Win32:

Während GetSystemInfo () die Anzahl der logischen Prozessoren ermittelt, verwenden Sie GetLogicalProcessorInformationEx () , um die Anzahl der physischen Prozessoren abzurufen .

irrlicht_ist_toll
quelle
-2

Sie können WMI auch in .net verwenden, sind dann aber auf den ausgeführten wmi-Dienst usw. angewiesen. Manchmal funktioniert es lokal, schlägt jedoch fehl, wenn derselbe Code auf Servern ausgeführt wird. Ich glaube, das ist ein Namespace-Problem, das mit den "Namen" zusammenhängt, deren Werte Sie lesen.


quelle
-3

Unter Linux können Sie dmesg auschecken und die Zeilen filtern, in denen ACPI die CPUs initialisiert.

dmesg | grep 'ACPI: Processor'

Eine andere Möglichkeit besteht darin, dmidecode zum Herausfiltern der Prozessorinformationen zu verwenden.

Hernán
quelle