Програмно знайти кількість ядер на машині


464

Чи існує спосіб визначити, скільки ядер має машина від C / C ++ незалежно від платформи? Якщо такого не існує, що з визначенням його на платформі (Windows / * nix / Mac)?


4
Якщо ви хочете скористатися ним, дізнайтеся, скільки ниток для початку, використовуйте NUMBER_OF_PROCESSORS як основний захід. Я залишаю це як вправу для вас, чому це набагато краще (якщо люди будуть використовувати це більше), ніж використання апаратних ядер. Скільки ядер належать до вашої програми - це екологічне питання!
Лотар

Зауважте, що std::thread::hardware_concurrencyповертає кількість фізичних ядер CPU, але nprocв Linux відображається лише кількість ядер CPU, на яких може запускатися поточний процес, яким можна керувати sched_setaffinity. Я не знайшов спосіб , щоб отримати , що замість того, щоб від стандартного C ++:, дивись , наприклад , в Python: stackoverflow.com/questions/1006289 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Відповіді:


706

C ++ 11

#include <thread>

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

Довідка: std :: thread: hardware_concurrency


У C ++ до C ++ 11 немає портативного способу. Натомість вам потрібно буде скористатися одним або декількома із наведених нижче способів (захищених відповідними #ifdefрядками):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
  • Linux, Solaris, AIX та Mac OS X> = 10,4 (тобто Тигр далі)

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

    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 або iOS)

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

5
@mcandre: це залишається як вправа для читача. Якби я впроваджував, я, ймовірно, використовував шаблон-політичний підхід, де політика була визначена в директивах препроцесора. Або ... ви можете використовувати boost thread :: hardware_concurrency ().
paxos1977

3
як уточнення, рішення Win32 повертає загальну кількість ядер (те, що було запропоновано), а не загальну кількість фізичних процесорів.
Ерік

1
Шлях Linux / Solaris / AIX також працює на FreeBSD і починає працювати щонайменше з 2006 року. Крім того, це поверне процесори в Інтернеті, якщо система здатна відключити їх, вони можуть не рахуватися. Виклик sysconf з "_SC_NPROCESSORS_CONF" поверне загальну кількість налаштованих процесорів.
Кріс S

3
Пару речей, про які слід знати. HW_NCPUзастаріла в OS X. У Windows GetSystemInfoкорисно лише в тому випадку, якщо у вашій системі є 32 логічні процесори або менше, використовуйте GetLogicalProcessorInformationдля систем, які мають більше 32 логічних процесорів.

1
@Trejkaz у документаційному документі чітко говориться про "логічне" - яке завжди рахує HT ядра, слово "фізичний" завжди посилається на ядра, про які повідомляє BIOS / UEFI, оскільки ядра також можуть бути імітовані / віртуалізовані. Можна, наприклад, розрізняти ядра HT / non-HT за допомогою таких функцій, як GetLogicalProcessorInformation . Примітка: HT! = Емуляція чи віртуалізація, велика різниця, HT - це оптимізація обладнання, так би мовити
specializt

202

Ця функціональність є частиною стандарту C ++ 11.

#include <thread>

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

Для старших компіляторів ви можете використовувати бібліотеку Boost.Thread .

#include <boost/thread.hpp>

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

У будь-якому випадку hardware_concurrency()повертає кількість потоків, які апаратне забезпечення здатне виконувати одночасно, виходячи з кількості ядер CPU та гіпер-ниток.


1
Відряджений ... збирався використати зразок коду вище та деякі макроси препроцесора, щоб відкрити одну функцію, але наполеглива робота була зроблена для мене.
jkp

Для win32 - це дзвінок до GetSystemInfo. (Станом на прискорену версію 1.41.0) Чи містить ця інформація всю інформацію, щоб визначити, скільки робочих ниток буде ефективним? Чи потрібно враховувати як кількість ядер, так і гіпер-різьблення? неподписаний потік :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& інформація); повернути info.dwNumberOfProcessors; }
Jive Dadson

Згідно з MSDN, GetSystemInfo () повертає кількість "фізичних процесорів" у dwNumberOfProcessors, але він не визначає, що це означає під цим. Документація Boost, здається, стверджує, що вона включає підрозділи гіперточення.
Ферруччо

см stackoverflow.com/questions/642348 / ... для гіперпоточності
naugtur

57

OpenMP підтримується на багатьох платформах (включаючи Visual Studio 2005), і він пропонує:

int omp_get_num_procs();

функція, яка повертає кількість процесорів / ядер, доступних під час виклику.


бо це неправильна відповідь. Від gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 "omp_get_num_procs () поверне лише меншу кількість, ніж кількість системних процесорів в Інтернеті, якщо використовується GOMP_CPU_AFFINITY env var, або якщо процес виклику та / або потік має Спорідненість CPU обмежена підмножиною процесорів ". Отже, якщо ви раніше телефонували, наприклад, sched_setaffinityце не вийде.
angainor

7
Ця функція повертає кількість процесорів, доступних для виклику. Це все-таки не найпоширеніший випадок використання? Переважно використовуючи деякі непотрібні цілі звітності, фактична кількість апаратних ядер процесора для вас не відповідає, якщо ви не можете скористатися ними у своєму коді.
macbirdie

@EvanTeran Крім того, що це було метою питання, це, звичайно, може бути корисним. Наприклад, з метою встановлення спорідненості потоку. Скажімо, я хочу запустити на своїй машині 4 потоки, прив’язані до чотирьох останніх ядер процесора, замість чотирьох перших ядер. Крім того, існують і інші способи паралелізації коду, крім OpenMP. Я, можливо, захочу нереститися. Вони, безумовно, доступні та не обмежені змінними середовища OpenMP.
прихильник

2
Це повертає кількість логічних процесорів, а не ядер (фізичних процесорів) як таких.
Michael Konečný

37

Якщо у вас є доступ до мови збирання, ви можете використовувати інструкцію CPUID, щоб отримати всіляку інформацію про процесор. Він портативний між операційними системами, хоча вам потрібно буде використовувати конкретну інформацію для виробника, щоб визначити, як знайти кількість ядер. Ось документ, який описує, як це зробити на мікросхемах Intel , а на сторінці 11 цього описується специфікація AMD.


4
Можливо, це було знято з огляду на те, що питання позначено як C ++, і ця відповідь не стосується систем, на яких працює C ++ в архітектурах, що не мають x86 (ARM, PPC тощо). Я не кажу, що це вагома причина спростувати відповідь, просто можливість.
Ферруччо

3
Одним із недоліків цього методу є те, якщо ви використовуєте CPUID для виявлення HyperThreading на процесорах Intel. Я зіткнувся з цією проблемою на своєму ноутбуці: в той час як процесор, який я помістив у машину, підтримує HyperThreading (і, звичайно, повідомляє, що це відбувається через CPUID), BIOS цього не робить. Тому не слід намагатися використовувати можливості HT просто з читання CPUID. Оскільки ви не можете запитувати BIOS про підтримку HT (я не бачив), ОС слід запитувати, щоб отримати кількість логічних процесорів.
Чак Р

32

(Майже) Функція незалежної платформи в 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
}

Здається HW_NCPU, застаріло в джерелі

16

В Linux ви можете прочитати файл / proc / cpuinfo і порахувати ядра.


Окрім того, що це також вважає гіпертрезовані чи інші SMT рішення як більш ядрами ...
jakobengblom2

13
@Arafangion: Hyperthreading - це не справжнє паралельне виконання, це технологія зменшення контекстної комутації накладних витрат. Гіпертокований процесор може виконувати лише один потік одночасно, але він може зберігати архітектурний стан (реєструвати значення тощо) двох потоків одночасно. Характеристики роботи дуже відрізняються від наявності двох ядер.
Вім Коен

7
@Wim: Це не зовсім правильно. Процесори з гіперточенням зазвичай мають кілька АЛУ і можуть відправляти кілька інструкцій за цикл. Якщо через залежність від даних та стійла, не всі ALU можуть бути зайняті одним потоком, ці ALU будуть використані для одночасного виконання другого апаратного потоку.
Бен Войгт

11

Зауважте, що "кількість ядер" може бути не особливо корисним числом, можливо, вам доведеться кваліфікувати його трохи більше. Як ви хочете порахувати багатопотокові процесори, такі як Intel HT, IBM Power5 та Power6, і найвідоміше, Niagara / UltraSparc T1 і T2 Sun? Або ще цікавіше, що MIPS 1004k з двома рівнями апаратної нарізки (рівень супервізора та користувача) ... Не кажучи вже про те, що відбувається при переході в системи, підтримувані гіпервізором, де на апаратному забезпеченні можуть бути десятки процесорів, але ваша конкретна ОС бачить лише кілька.

Найкраще, на що можна сподіватися, - це повідомити кількість логічних процесорних одиниць, які є у вашому локальному розділі ОС. Забудьте побачити справжню машину, якщо ви не гіпервізор. Єдиний виняток із цього правила сьогодні знаходиться в x86 land, але кінець невіртуальних машин наближається швидко ...


7

Ще один рецепт Windows: використовувати загальносистемну змінну середовища NUMBER_OF_PROCESSORS:

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

7

Напевно, ви не зможете отримати це незалежно від платформи. У Windows ви отримуєте кількість процесорів.

Інформація про систему Win32


1
Обережно: Hyperthreed процесори кажуть, що є два. Тож вам також потрібно перевірити, чи здатний процесор підтримувати гіперпотоки.
Мартін Йорк,

6

Windows (x64 та Win32) та C ++ 11

Кількість груп логічних процесорів, що розділяють одне ядро ​​процесора. (Використовуючи GetLogicalProcessorInformationEx , див. Також 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;
}

Зауважте, що реалізація NumberOfPhysicalCoresIMHO далеко не тривіальна (тобто "використання GetLogicalProcessorInformationабо GetLogicalProcessorInformationEx"). Натомість досить тонко, якщо читати документацію (явно представлена ​​для GetLogicalProcessorInformationта неявно присутня для GetLogicalProcessorInformationEx) в MSDN.

Кількість логічних процесорів. (Використання 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);
}

Зауважте, що обидва способи можна легко перетворити на C / C ++ 98 / C ++ 03.


1
Дякую! Я шукав це через те, що GetLogicalProcessorInformationне працював з різними розмірами буфера, який я використав. Більше ніж задоволений! ^^
KeyWeeUsr

@KeyWeeUsr Спасибі Програмування Windows дещо далеко від тривіального та логічного. Тим часом я використовую дещо оновлене версію C ++ 17, яка також є більш коректною за даними статичного аналізатора PVS-Studio щодо деяких size_tролях. (Хоча, msvc ++ не скаржиться на W4.)
Маттіас

5

Більше про OS X: sysconf(_SC_NPROCESSORS_ONLN)доступні лише версії> = 10.5, а не 10.4.

Альтернативою є HW_AVAILCPU/sysctl()код BSD, який доступний у версіях> = 10.2.



4

Не пов’язаний із C ++, але в Linux я зазвичай:

grep processor /proc/cpuinfo | wc -l

Зручний для сценаріїв таких мов, як bash / perl / python / ruby.


4
Для пітона:import multiprocessing print multiprocessing.cpu_count()
initzero

3
Давно, але grepмає -cпрапор для підрахунку записів!
Лапшин Дмитро

3

hwloc (http://www.open-mpi.org/projects/hwloc/) варто переглянути. Хоча потрібна ще одна інтеграція бібліотеки у ваш код, але вона може надавати всю інформацію про ваш процесор (кількість ядер, топологія тощо)


3

На linux найкращий програмний спосіб, наскільки я знаю, це використовувати

sysconf(_SC_NPROCESSORS_CONF)

або

sysconf(_SC_NPROCESSORS_ONLN)

Вони не стандартні, але є на моїй сторінці man для Linux.


3

У Linux це може бути не безпечно використовувати, _SC_NPROCESSORS_ONLNоскільки він не є частиною стандарту POSIX, а керівництво sysconf так само зазначає. Тож існує можливість, яка _SC_NPROCESSORS_ONLNможе бути відсутня:

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

Простим підходом було б їх читання /proc/statабо /proc/cpuinfoпідрахунок:

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

Використання /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;
}

Той самий підхід до оболонки з використанням grep:

grep -c ^processor /proc/cpuinfo

Або

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

2

Альтернатива OS X: рішення, описане раніше на основі [[NSProcessInfo processInfo] ProcessCount], доступне лише в OS X 10.5.0, згідно з документами. Для більш ранніх версій OS X використовуйте функцію MPProcessors Carbon ().

Якщо ви програміст з какао, не лякайтеся, що це Карбон. Вам просто потрібно додати карбон-каркас до вашого проекту Xcode і MPProcessors () буде доступний.



-2

Ви також можете використовувати WMI в .net, але ви залежаєте від запущеної служби wmi тощо. Іноді вона працює локально, але потім виходить з ладу, коли той самий код запускається на серверах. Я вважаю, що це проблема простору імен, пов’язана з "іменами", значення яких ви читаєте.


-3

В Linux ви можете перевірити dmesg і відфільтрувати рядки, де ACPI ініціалізує процесори, приблизно так:

dmesg | grep 'ACPI: Processor'

Інша можливість - використовувати dmidecode для фільтрації інформації про процесор.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.