Программно найти количество ядер на машине

464

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

hazzen
источник
4
Если вы хотите использовать его, выясните, сколько потоков нужно запустить, используйте NUMBER_OF_PROCESSORS в качестве основного показателя. Я оставляю вам в качестве упражнения, почему это намного лучше (если люди будут использовать его чаще), чем использование аппаратных ядер. Сколько ядер принадлежит вашей программе - экологическая проблема!
Лотар
Обратите внимание, что std::thread::hardware_concurrencyвозвращает количество физических ядер ЦП, но nprocв Linux отображается только количество ядер ЦП, на которых может выполняться текущий процесс, которыми можно управлять sched_setaffinity. Я не нашел способа получить это вместо стандартного C ++: см., Например, в Python: stackoverflow.com/questions/1006289/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ответы:

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 (т. Е. Tiger и выше)

    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];
paxos1977
источник
5
@mcandre: это оставлено в качестве упражнения для читателя. Если бы я реализовывал, я бы, вероятно, использовал бы подход политики шаблона, где политика была определена в директивах препроцессора. Или ... вы можете использовать boost thread :: hardware_concurrency ().
paxos1977
3
В качестве пояснения решение Win32 возвращает общее количество ядер (что было запрошено), а не общее количество физических процессоров.
Eric
1
Способ Linux / Solaris / AIX также работает на FreeBSD и существует по крайней мере с 2006 года. Кроме того, он вернет ЦП в оперативный режим, если система способна отключать некоторые из них, они могут не учитываться. Вызов sysconf с "_SC_NPROCESSORS_CONF" вернет общее количество настроенных процессоров.
Крис С
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()возвращает количество потоков, которые аппаратное обеспечение способно выполнять одновременно, исходя из количества ядер ЦП и модулей гиперпоточности.

Ферруччо
источник
1
Seconded ... собирался использовать приведенный выше пример кода и некоторые макросы препроцессора для раскрытия одной функции, но тяжелая работа для меня была сделана.
JKP
Для win32 это вызов GetSystemInfo. (Начиная с версии Boost 1.41.0). Собирает ли она всю информацию, чтобы определить, сколько рабочих потоков будет эффективным? Нужно ли учитывать как количество ядер, так и гиперпоточность? неподписанный поток :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& информация); return info.dwNumberOfProcessors; }
Джайв Дадсон
Согласно MSDN, GetSystemInfo () возвращает количество «физических процессоров» в dwNumberOfProcessors, но не определяет, что это означает. Документация Boost, кажется, утверждает, что она включает в себя модули гиперпоточности.
Ферруччо
см. stackoverflow.com/questions/642348/… для гиперпоточности
naugtur
57

OpenMP поддерживается на многих платформах (включая Visual Studio 2005) и предлагает

int omp_get_num_procs();

функция, которая возвращает количество процессоров / ядер, доступных на момент вызова.

macbirdie
источник
потому что это неправильный ответ. От gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 "omp_get_num_procs () будет возвращать только меньшее число, чем количество системных процессоров в сети, если используется env var GOMP_CPU_AFFINITY или если вызывающий процесс и / или поток имеет Сродство процессора ограничено подмножеством процессоров ». Так что, если вы ранее позвоните, например, sched_setaffinityэто не будет работать.
angainor
7
Эта функция возвращает количество процессоров, доступных для вызывающего процесса. Разве это не самый распространенный вариант использования? Помимо некоторых бесполезных целей отчетности, фактическое количество аппаратных ядер ЦП не имеет к вам отношения, если вы не можете использовать их в своем коде.
Macbirdie
@EvanTeran Помимо того, что это было целью вопроса, это, конечно, может быть полезно. Например, с целью установки сходства потоков. Скажем, я хочу запустить 4 потока, привязанных к четырем последним ядрам процессора на моей машине, вместо четырех первых ядер. Кроме того, существуют другие способы распараллеливания кода, кроме OpenMP. Я могу хотеть порождать себя. Они, безусловно, доступны и не ограничены переменными среды OpenMP.
angainor
2
Это возвращает количество логических процессоров, а не ядер (физических процессоров) как таковых.
Михаил Конечны
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, устарела на OS X источник
16

В Linux вы можете прочитать файл / proc / cpuinfo и подсчитать количество ядер.

JesperE
источник
За исключением того, что это также считает гиперпоточные или другие решения SMT как больше ядер ...
jakobengblom2
13
@Arafangion: гиперпоточность - это не совсем параллельное выполнение, это технология для снижения издержек переключения контекста. Многопоточный процессор может одновременно выполнять только один поток, но он может хранить архитектурное состояние (значения регистров и т. Д.) Двух потоков одновременно. Характеристики производительности сильно отличаются от двух ядер.
Вим Коенен
7
@Wim: Это не совсем правильно. Процессоры с гиперпоточностью обычно имеют несколько ALU и могут отправлять несколько команд за цикл. Если из-за зависимостей данных и остановок не все ALU могут быть заняты одним потоком, эти ALU вместо этого будут использоваться для одновременного выполнения второго аппаратного потока.
Бен Фойгт
11

Обратите внимание, что «число ядер» может быть не особенно полезным числом, вам, возможно, придется уточнить его немного больше. Как вы хотите сосчитать многопоточные процессоры, такие как Intel HT, IBM Power5 и Power6, и наиболее известные из них - Sun Niagara / UltraSparc T1 и T2? Или, что еще интереснее, MIPS 1004k с двумя уровнями аппаратного потока (супервизор и пользовательский уровень) ... Не говоря уже о том, что происходит, когда вы переходите в системы с поддержкой гипервизора, где на оборудовании могут быть десятки процессоров, но ваша конкретная ОС видит только несколько.

Лучшее, на что вы можете надеяться, - это указать количество логических процессоров, которые есть в вашем локальном разделе ОС. Забудьте о том, чтобы увидеть настоящую машину, если вы не являетесь гипервизором. Единственное исключение из этого правила сегодня на земле x86, но конец не виртуальных машин скоро наступит ...

jakobengblom2
источник
7

Еще один рецепт Windows: используйте общесистемную переменную среды NUMBER_OF_PROCESSORS:

printf("%d\n", atoi(getenv("NUMBER_OF_PROCESSORS")));
Constantin
источник
7

Вы, вероятно, не сможете получить его независимо от платформы. Windows вы получаете количество процессоров.

Win32 Системная информация

кругозор
источник
1
Осторожно: процессоры Hyperthreaded говорят, что их два. Таким образом, вам также необходимо проверить, поддерживает ли процессор технологию Hyperthread.
Мартин Йорк,
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.

sezero
источник
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/) стоит посмотреть. Хотя требуется интеграция другой библиотеки в ваш код, но она может предоставить всю информацию о вашем процессоре (количество ядер, топология и т. Д.)

Akhil
источник
3

Насколько мне известно, в Linux лучший программный способ - это использовать

sysconf(_SC_NPROCESSORS_CONF)

или

sysconf(_SC_NPROCESSORS_ONLN)

Они не являются стандартными, но есть в моей справочной странице по 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
PP
источник
2

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

Если вы программист какао, не пугайтесь того факта, что это Carbon. Вам просто нужно добавить платформу Carbon в ваш проект Xcode, и MPProcessors () будет доступен.

gauss256
источник
2

Для Win32:

В то время как GetSystemInfo () возвращает количество логических процессоров, используйте GetLogicalProcessorInformationEx () для получения количества физических процессоров.

irrlicht_ist_toll
источник
-2

вы также можете использовать WMI в .net, но в этом случае вы зависите от работающей службы wmi и т. д. Иногда она работает локально, но затем перестает работать, когда тот же код выполняется на серверах. Я считаю, что это проблема пространства имен, связанная с «именами», значения которых вы читаете.


источник
-3

В Linux вы можете извлекать dmesg и фильтровать строки, в которых ACPI инициализирует процессоры, что-то вроде:

dmesg | grep 'ACPI: Processor'

Другая возможность - использовать dmidecode для фильтрации информации о процессоре.

Эрнан
источник