Programowo znajdź liczbę rdzeni na maszynie

464

Czy istnieje sposób na określenie liczby rdzeni maszyny w C / C ++ w sposób niezależny od platformy? Jeśli nic takiego nie istnieje, co powiesz na określenie tego na platformę (Windows / * nix / Mac)?

Hazzen
źródło
4
Jeśli chcesz go użyć, dowiedz się, ile wątków zacząć, użyj NUMBER_OF_PROCESSORS jako podstawowej miary. Pozostawiam wam jako wytłumaczenie, dlaczego jest to o wiele lepsze (jeśli ludzie używają go częściej) niż używanie rdzeni sprzętowych. Ile rdzeni należy do twojego programu to problem środowiskowy!
Lothar
Zauważ, że std::thread::hardware_concurrencyzwraca liczbę fizycznych rdzeni procesora, ale nprocw Linuksie pokazuje tylko liczbę rdzeni procesora, na których może działać bieżący proces, którymi można sterować sched_setaffinity. Nie znalazłem sposobu na uzyskanie tego zamiast standardowego C ++: patrz np. W Pythonie: stackoverflow.com/questions/1006289/...
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Odpowiedzi:

706

C ++ 11

#include <thread>

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

Odniesienie: std :: thread :: hardware_concurrency


W C ++ przed C ++ 11 nie ma przenośnego sposobu. Zamiast tego musisz użyć jednej lub więcej z następujących metod (strzeżonych odpowiednimi #ifdefliniami):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
  • Linux, Solaris, AIX i Mac OS X> = 10,4 (tj. Tiger i nowsze)

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

    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);
  • Cel C (Mac OS X> = 10.5 lub iOS)

    NSUInteger a = [[NSProcessInfo processInfo] processorCount];
    NSUInteger b = [[NSProcessInfo processInfo] activeProcessorCount];
paxos1977
źródło
5
@mcandre: pozostawia to ćwiczenie czytelnikowi. Gdybym wdrażał, prawdopodobnie użyłbym podejścia opartego na szablonach, gdzie zasady zostały zdefiniowane w dyrektywach preprocesora. Lub ... możesz użyć boost thread :: hardware_concurrency ().
paxos1977
3
dla wyjaśnienia rozwiązanie Win32 zwraca całkowitą liczbę rdzeni (o co poproszono), a nie całkowitą liczbę fizycznych procesorów.
Eric
1
Sposób Linux / Solaris / AIX działa również na FreeBSD i działa od co najmniej 2006 roku. To również spowoduje powrót procesorów do trybu online, jeśli system jest w stanie wyłączyć niektóre z nich, mogą nie zostać policzone. Wywołanie sysconf z „_SC_NPROCESSORS_CONF” zwróci całkowitą liczbę skonfigurowanych procesorów.
Chris S
3
Kilka rzeczy, o których należy pamiętać. HW_NCPUjest przestarzały w systemie OS X. W systemie Windows GetSystemInfojest przydatny tylko wtedy, gdy twój system ma 32 procesory logiczne lub mniej, używaj GetLogicalProcessorInformationw systemach, które mają więcej niż 32 procesory logiczne.
1
@Trejkaz dokumentacja wyraźnie mówi „logiczny” - co zawsze liczy rdzenie HT, słowo „fizyczny” zawsze odnosi się do rdzeni zgłaszanych przez BIOS / UEFI, ponieważ rdzenie mogą być również emulowane / wirtualizowane. Można odróżnić rdzenie HT / non-HT za pomocą funkcji takich jak GetLogicalProcessorInformation , na przykład. Uwaga: HT! = Emulacja lub wirtualizacja, to duża różnica, HT to optymalizacja sprzętowa, że ​​tak powiem
specjalizacja
202

Ta funkcjonalność jest częścią standardu C ++ 11.

#include <thread>

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

W przypadku starszych kompilatorów możesz użyć biblioteki Boost.Thread .

#include <boost/thread.hpp>

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

W obu przypadkach hardware_concurrency()zwraca liczbę wątków, które sprzęt może wykonywać jednocześnie, w oparciu o liczbę rdzeni procesora i jednostek hiperwątkowości.

Ferruccio
źródło
1
Seconded ... zamierzał użyć powyższego przykładowego kodu i niektórych makr preprocesora, aby ujawnić jedną funkcję, ale ciężka praca została dla mnie wykonana.
jkp
W przypadku win32 jest to wywołanie GetSystemInfo. (Od wersji boost 1.41.0) Czy to przechwytuje wszystkie informacje, aby określić, ile wątków roboczych będzie efektywnych? Czy trzeba wziąć pod uwagę zarówno liczbę rdzeni, jak i hiperwątkowość? niepodpisany wątek :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (i informacje); return info.dwNumberOfProcessors; }
Jive Dadson
Według MSDN GetSystemInfo () zwraca liczbę „fizycznych procesorów” w dwNumberOfProcessors, ale nie definiuje co to oznacza. Dokumentacja Boost wydaje się twierdzić, że obejmuje jednostki hipertekstowe.
Ferruccio
patrz
hyperoverreading
57

OpenMP jest obsługiwany na wielu platformach (w tym Visual Studio 2005) i oferuje

int omp_get_num_procs();

funkcja zwracająca liczbę procesorów / rdzeni dostępnych w momencie połączenia.

macbirdie
źródło
ponieważ jest to zła odpowiedź. Z gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 „omp_get_num_procs () zwróci tylko mniejszą liczbę niż liczba procesorów systemowych w trybie online, jeśli użyto GOMP_CPU_AFFINITY env var lub jeśli proces wywołujący i / lub wątek ma Powinowactwo procesora ograniczone do podzbioru procesorów ". Więc jeśli wcześniej zadzwonisz, np. sched_setaffinityTo nie zadziała.
angainor
7
Ta funkcja zwraca liczbę procesorów dostępnych dla procesu wywołującego. Czy to zresztą nie jest najczęstszy przypadek użycia? Poza niektórymi bezużytecznymi celami raportowania, faktyczna liczba rdzeni procesora nie jest dla ciebie istotna, jeśli nie możesz z nich skorzystać w swoim kodzie.
macbirdie
@EvanTeran Oprócz tego, że był to cel pytania, może być oczywiście użyteczny. Na przykład w celu ustawienia powinowactwa wątku. Powiedzmy, że chcę uruchomić 4 wątki powiązane z czterema ostatnimi rdzeniami procesora na moim komputerze, zamiast z czterema pierwszymi rdzeniami. Poza tym istnieją inne sposoby zrównoleglenia kodu oprócz OpenMP. Mogę sam chcieć spawnować wątki. Są one z pewnością dostępne i nie są ograniczone zmiennymi środowiskowymi OpenMP.
angainor
2
Zwraca liczbę procesorów logicznych, a nie rdzeni (procesorów fizycznych) jako takich.
Michael Konečný
37

Jeśli masz dostęp w języku asemblera, możesz użyć instrukcji CPUID, aby uzyskać wszelkiego rodzaju informacje o CPU. Jest przenośny między systemami operacyjnymi, ale musisz użyć informacji specyficznych dla producenta, aby ustalić, jak znaleźć liczbę rdzeni. Oto dokument opisujący, jak to zrobić na układach Intel , a strona 11 tego opisu opisuje specyfikację AMD.

Head Geek
źródło
4
Być może zostało to odrzucone, ponieważ pytanie jest oznaczone jako C ++, a ta odpowiedź nie dotyczy systemów z C ++ na architekturze innej niż x86 (ARM, PPC itp.). Nie twierdzę, że to dobry powód, by głosować za odpowiedzią, tylko taka możliwość.
Ferruccio
3
Jedną z pułapek tej metody jest użycie CPUID do wykrywania HyperThreading na procesorach Intel. Napotkałem ten problem na moim laptopie: podczas gdy procesor, który wkładam do komputera, obsługuje HyperThreading (i, oczywiście, informuje, że robi to przez CPUID), BIOS nie. Dlatego nie powinieneś próbować wykorzystywać możliwości HT po prostu z odczytu CPUID. Ponieważ nie można zapytać BIOS-u o obsługę HT (nie ma mowy, żebym widział), system operacyjny powinien zostać zapytany, aby uzyskać logiczną liczbę procesorów.
Chuck R
32

(Prawie) Niezależna od platformy funkcja w kodzie 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
}
Dirk-Jan Kroon
źródło
Wydaje się, że HW_NCPUjest przestarzałe w źródle
16

W systemie Linux możesz odczytać plik / proc / cpuinfo i policzyć rdzenie.

JesperE
źródło
Z wyjątkiem, że liczy się także hyperthreaded lub inne rozwiązania SMT jak więcej rdzeni ...
jakobengblom2
13
@Arafangion: hyperthreading nie jest prawdziwym równoległym wykonywaniem, jest technologią zmniejszającą obciążenie związane z przełączaniem kontekstu. Hyperthreaded procesor może wykonywać tylko jeden wątek na raz, ale może przechowywać stan architektury (wartości rejestru itp.) Dwóch wątków jednocześnie. Charakterystyka wydajności bardzo różni się od posiadania dwóch rdzeni.
Wim Coenen,
7
@Wim: To nie do końca poprawne. Procesory z hiperwątkiem mają na ogół wiele jednostek ALU i mogą wysyłać wiele instrukcji na cykl. Jeśli z powodu zależności danych i przeciągnięć, nie wszystkie jednostki ALU mogą być zajęte przez jeden wątek, te jednostki ALU zostaną zamiast tego wykorzystane do jednoczesnego wykonania drugiego wątku sprzętowego.
Ben Voigt,
11

Zauważ, że „liczba rdzeni” może nie być szczególnie przydatną liczbą, być może będziesz musiał ją jeszcze bardziej zakwalifikować. Jak chcesz policzyć wielowątkowe procesory, takie jak Intel HT, IBM Power5 i Power6, a najbardziej znany, Sun's Niagara / UltraSparc T1 i T2? Lub jeszcze bardziej interesujące, MIPS 1004k z dwoma poziomami wątków sprzętowych (nadzorca ORAZ poziom użytkownika) ... Nie wspominając o tym, co dzieje się, gdy przejdziesz do systemów obsługiwanych przez hypervisor, w których sprzęt może mieć dziesiątki procesorów, ale twój system operacyjny widzi tylko kilka.

Najlepsze, na co możesz liczyć, to podanie liczby jednostek przetwarzania logicznego na lokalnej partycji systemu operacyjnego. Zapomnij o zobaczeniu prawdziwej maszyny, chyba że jesteś hiperwizorem. Jedyny wyjątek od tej reguły jest dzisiaj na ziemi x86, ale koniec maszyn nie-wirtualnych nadchodzi szybko ...

jakobengblom2
źródło
7

Jeszcze jeden przepis na Windows: użyj ogólnosystemowej zmiennej środowiskowej NUMBER_OF_PROCESSORS:

printf("%d\n", atoi(getenv("NUMBER_OF_PROCESSORS")));
Constantin
źródło
7

Prawdopodobnie nie będziesz w stanie uzyskać go w sposób niezależny od platformy. Windows dostajesz liczbę procesorów.

Informacje o systemie Win32

Rozpoznać
źródło
1
Ostrożnie: procesory Hyperthreaded twierdzą, że są dwa. Musisz więc również sprawdzić, czy procesor obsługuje hiperwątek.
Martin York,
6

Windows (x64 i Win32) oraz C ++ 11

Liczba grup procesorów logicznych współużytkujących jeden rdzeń procesora. (Używając GetLogicalProcessorInformationEx , zobacz także 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;
}

Zauważ, że implementacja NumberOfPhysicalCoresIMHO jest daleka od trywialnej (tj. „Use GetLogicalProcessorInformationor GetLogicalProcessorInformationEx”). Zamiast tego jest raczej subtelne, jeśli czyta się dokumentację (jawnie obecną GetLogicalProcessorInformationi niejawnie obecną GetLogicalProcessorInformationEx) w MSDN.

Liczba procesorów logicznych. (Korzystanie z 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);
}

Zauważ, że obie metody można łatwo przekonwertować na C / C ++ 98 / C ++ 03.

Matthias
źródło
1
Dziękuję Ci! Szukałem tego, ponieważ GetLogicalProcessorInformationnie pracowałem z różnymi rozmiarami buforów, których użyłem. Więcej niż zadowolony! ^^
KeyWeeUsr
@KeyWeeUsr Dzięki Programowanie w systemie Windows jest nieco dalekie od trywialnych i logicznych. Tymczasem używam nieco zaktualizowanej wersji C ++ 17, która jest również bardziej poprawna według analizatora statycznego PVS-Studio w odniesieniu do niektórych size_trzutów. (Chociaż msvc ++ nie narzeka na W4.)
Matthias
5

Więcej informacji na temat systemu OS X: sysconf(_SC_NPROCESSORS_ONLN)dostępne są tylko wersje> = 10,5, a nie 10,4.

Alternatywą jest HW_AVAILCPU/sysctl()kod BSD, który jest dostępny w wersjach> = 10.2.

sezero
źródło
4

Nie jest związany z C ++, ale w Linuksie zwykle robię:

grep processor /proc/cpuinfo | wc -l

Przydatny do języków skryptowych, takich jak bash / perl / python / ruby.

Chris
źródło
4
W przypadku pytona:import multiprocessing print multiprocessing.cpu_count()
initzero
3
Minęło dużo czasu, ale grepma -cflagę do liczenia wpisów!
Lapshin Dmitry
3

Warto przyjrzeć się hwloc (http://www.open-mpi.org/projects/hwloc/). Chociaż wymaga kolejnej integracji biblioteki z twoim kodem, ale może dostarczyć wszystkich informacji o twoim procesorze (liczba rdzeni, topologia itp.)

Ach
źródło
3

Na Linuksie najlepszym sposobem programistycznym, o ile wiem, jest użycie

sysconf(_SC_NPROCESSORS_CONF)

lub

sysconf(_SC_NPROCESSORS_ONLN)

Nie są to standardowe, ale są na mojej stronie podręcznika użytkownika dla systemu Linux.

Evan Teran
źródło
3

W Linuksie korzystanie z niego może nie być bezpieczne, _SC_NPROCESSORS_ONLNponieważ nie jest ono częścią standardu POSIX, a instrukcja sysconf podaje tyle samo. Istnieje więc możliwość, że _SC_NPROCESSORS_ONLNmoże nie być obecna:

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

Prostym podejściem byłoby ich przeczytanie /proc/statlub /proc/cpuinfopoliczenie:

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

Używanie /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;
}

To samo podejście w powłoce przy użyciu grep:

grep -c ^processor /proc/cpuinfo

Lub

grep -c ^cpu /proc/stat # subtract 1 from the result
PP
źródło
2

Alternatywa dla OS X: Rozwiązanie opisane wcześniej w oparciu o [[NSProcessInfo processInfo] processCount] jest dostępne tylko w OS X 10.5.0, zgodnie z dokumentacją. W przypadku wcześniejszych wersji OS X użyj funkcji Carbon MPProcessors ().

Jeśli jesteś programistą Cocoa, nie przejmuj się faktem, że jest to Carbon. Musisz tylko dodać platformę Carbon do swojego projektu Xcode, a MPProcessors () będzie dostępny.

gauss256
źródło
2

Dla Win32:

Podczas gdy GetSystemInfo () uzyskuje liczbę procesorów logicznych , użyj GetLogicalProcessorInformationEx (), aby uzyskać liczbę procesorów fizycznych .

irrlicht_ist_toll
źródło
-2

możesz również używać WMI w .net, ale jesteś zależny od działającej usługi wmi itp. Czasami działa ona lokalnie, ale potem kończy się niepowodzeniem, gdy ten sam kod jest uruchamiany na serwerach. Uważam, że jest to problem związany z przestrzenią nazw, związany z „nazwami”, których wartości czytasz.


źródło
-3

W systemie Linux możesz pobrać dmesg i filtrować wiersze, w których ACPI inicjuje procesory, na przykład:

dmesg | grep 'ACPI: Processor

Inną możliwością jest użycie dmidecode do odfiltrowania informacji o procesorze.

Hernán
źródło