Есть ли способ определить, сколько ядер у машины на C / C++, независимо от платформы? Если такой вещи не существует, как насчет ее определения для каждой платформы (Windows / * nix / Mac)?
Обратите внимание, что std::thread::hardware_concurrency возвращает количество физических ядер ЦП, но nproc в Linux показывает только количество ядер ЦП, на которых может выполняться текущий процесс, которым можно управлять с помощью sched_setaffinity. Я не нашел способа получить это вместо стандартного C++ :, см., Например, в Python: stackoverflow.com/questions/1006289/…





Windows Server 2003 и более поздние версии позволяют использовать функцию GetLogicalProcessorInformation.
В Linux вы можете прочитать файл / proc / cpuinfo и подсчитать количество ядер.
За исключением того, что это также учитывает гиперпоточные или другие решения SMT как большее количество ядер ...
@Arafangion: гиперпоточность - это не настоящее параллельное выполнение, это технология для уменьшения накладных расходов на переключение контекста. Гиперпоточный процессор может использовать выполнять только для одного потока за раз, но он может одновременно хранить архитектурное состояние (значения регистров и т. д.) Двух потоков. Характеристики производительности сильно отличаются от двухъядерных.
@Wim: Это не совсем правильно. Процессоры с гиперпоточностью обычно имеют несколько ALU и могут отправлять несколько инструкций за цикл. Если из-за зависимостей данных и остановок не все ALU могут быть заняты одним потоком, эти ALU вместо этого будут использоваться для одновременного выполнения второго аппаратного потока.
Вы, вероятно, не сможете получить его независимым от платформы способом. Windows вы получаете количество процессоров.
Внимание! Гиперпоточные процессоры говорят, что их два. Таким образом, вам также необходимо проверить, поддерживает ли процессор гиперпоточность.
Эта функциональность является частью стандарта 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() возвращает количество потоков, которые аппаратное обеспечение способно выполнять одновременно, в зависимости от количества ядер ЦП и блоков гиперпоточности.
Seconded ... собирался использовать приведенный выше пример кода и несколько макросов препроцессора, чтобы раскрыть одну функцию, но тяжелая работа была сделана за меня.
Для win32 это вызов GetSystemInfo. (Начиная с версии boost 1.41.0) Захватывает ли это всю информацию, чтобы определить, сколько рабочих потоков будет эффективным? Нужно ли учитывать количество ядер и гиперпоточность? неподписанный поток :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& информация); return info.dwNumberOfProcessors; }
Согласно MSDN, GetSystemInfo () возвращает количество «физических процессоров» в dwNumberOfProcessors, но не определяет, что это значит. Документация Boost, кажется, утверждает, что она включает в себя гиперпоточность.
см. stackoverflow.com/questions/642348/… для гиперпоточности
Насколько я знаю, в Linux лучший программный способ - использовать
sysconf(_SC_NPROCESSORS_CONF)
или же
sysconf(_SC_NPROCESSORS_ONLN)
Они не стандартные, но есть на моей странице руководства для Linux.
Если у вас есть доступ к языку ассемблера, вы можете использовать инструкцию CPUID для получения всевозможной информации о процессоре. Он переносится между операционными системами, хотя вам нужно будет использовать информацию производителя, чтобы определить, как определить количество ядер. Здесь документ, описывающий, как это сделать на чипах Intel, а страница 11 Вот этот описывает спецификацию AMD.
Возможно, он был отклонен, потому что вопрос помечен как C++, и этот ответ не относится к системам, работающим на C++ на архитектурах, отличных от x86 (ARM, PPC и т. д.). Я не говорю, что это хорошая причина для того, чтобы отрицать ответ, просто возможность.
Одна из ловушек этого метода заключается в том, что вы используете CPUID для обнаружения HyperThreading на процессорах Intel. Я столкнулся с этой проблемой на своем ноутбуке: в то время как процессор, который я установил в машину, поддерживает HyperThreading (и, конечно же, сообщает об этом через CPUID), BIOS этого не делает. Следовательно, вам не следует пытаться использовать возможности HT просто из чтения CPUID. Поскольку вы не можете запросить BIOS о поддержке HT (я этого не видел), ОС следует запросить, чтобы получить количество логических процессоров.
#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):
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
int numCPU = sysinfo.dwNumberOfProcessors;
int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
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;
}
int numCPU = mpctl(MPC_GETNUMSPUS, NULL, NULL);
int numCPU = sysconf(_SC_NPROC_ONLN);
NSUInteger a = [[NSProcessInfo processInfo] processorCount];
NSUInteger b = [[NSProcessInfo processInfo] activeProcessorCount];
Добавьте директивы препроцессора, чтобы выполнялся только код, специфичный для ОС.
@mcandre: это оставлено в качестве упражнения для читателя. Если бы я реализовывал, я бы, вероятно, использовал подход шаблонной политики, когда политика была определена в директивах препроцессора. Или ... вы можете использовать boost thread :: hardware_concurrency ().
в качестве пояснения, решение Win32 возвращает общее количество ядер (то, что было запрошено), а не общее количество физических процессоров.
Способ Linux / Solaris / AIX также работает во FreeBSD и работает по крайней мере с 2006 года. Кроме того, это вернет процессоры в оперативный режим, если система способна отключать некоторые из них, они могут не учитываться. Вызов sysconf с "_SC_NPROCESSORS_CONF" вернет общее количество сконфигурированных процессоров.
Обратите внимание, что версия fbsd намного проще - это комбинированный пример, поэтому он выглядит сложным.
Несколько вещей, о которых нужно знать. HW_NCPU не рекомендуется в OS X. В Windows GetSystemInfo полезен только в том случае, если в вашей системе 32 логических процессора или меньше, используйте GetLogicalProcessorInformation для систем, которые имеют более 32 логических процессоров.
@Eric Предположительно, это хуже, чем это, и он фактически возвращает количество логических ядер, поэтому, если у вас включена гиперпоточность, оно может быть больше, чем вы ожидаете. Это не очень ясно, потому что в документации Microsoft по двум разным версиям одного и того же API говорится о двух разных вещах (в одной это сформулировано как «физическое», а в другом - как «логическое»).
@Trejkaz документ четко говорит «логический» - который всегда считает HT-ядра, слово "физический"всегда относится к ядрам, о которых сообщает BIOS / UEFI, поскольку ядра также могут быть эмулированы / виртуализированы. Вы можете различать HT / не-HT ядра, например, с помощью таких функций, как GetLogicalProcessorInformation. Примечание: HT! = Эмуляция или виртуализация, это разница большой, HT - это аппаратная оптимизация, так сказать
@specializt да, если вы проигнорируете бит об одной странице в документах, где она написана как «физическая», а другая - как «логическая», это будет довольно ясно по своему значению. Или, в качестве альтернативы, если бы документы были исправлены между мной, сделав этот комментарий, и вашим ответом, это также решило бы проблему.
@Trejkaz, я бы хотел увидеть этот документ - MSDN обычно не имеет таких серьезных проблем, я очень сомневаюсь, что они действительно перепутали его, на самом деле они даже упоминают разницу и связь между этими терминами: «Для получения информации о физических процессорах, совместно используемых логическими процессорами, вызовите GetLogicalProcessorInformationEx с параметром RelationshipType, установленным на RelationProcessorPackage (3)».
@specializt да, жаль, что в то время я не связывался с этим. Маловероятно, что я найду его сейчас, даже если искал. : /
потому что его не существует.
Добавление необходимых заголовков (например, #include <unistd.h> для linux) сделает ответ идеальным для будущих поисковиков.
std::thread::hardware_concurrency implementations differ; Visual Studio takes into account affinity (returns 1 if process is restricted to one core etc.) whereas g++ does not.
Если вы используете современную Windows и вам нужны все процессоры независимо от группы процессоров (например, вы работаете с системой с более чем 64 процессорами), и вы ориентируетесь на Windows 7/2008 R2 или выше, вы можете использовать GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS) для получения полный подсчет. См. Пример github.com/python/cpython/commit/….
Обратите внимание, что «количество ядер» может быть не особенно полезным числом, вам, возможно, придется уточнить его немного больше. Как вы хотите считать многопоточные процессоры, такие как Intel HT, IBM Power5 и Power6, и, что наиболее известно, Sun Niagara / UltraSparc T1 и T2? Или, что еще интереснее, MIPS 1004k с двумя уровнями аппаратной обработки потоков (супервизор И уровень пользователя) ... Не говоря уже о том, что происходит, когда вы переходите в системы с поддержкой гипервизора, где оборудование может иметь десятки процессоров, но ваша конкретная ОС видит только несколько.
Лучшее, на что вы можете надеяться, - это указать количество логических процессоров, которые есть в вашем локальном разделе ОС. Забудьте о том, чтобы видеть настоящую машину, если вы не гипервизор. Единственное исключение из этого правила сегодня - страна x86, но конец невиртуальных машин приближается ...
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 используется, или если вызывающий процесс и / или поток имеют привязку к процессору, ограниченную подмножеством процессоров». Поэтому, если вы ранее позвонили, например, sched_setaffinity, это не сработает.
Эта функция возвращает количество процессоров, доступных вызывающему процессу. В любом случае, разве это не самый распространенный вариант использования? Из-за некоторых бесполезных целей отчетности фактическое количество аппаратных ядер ЦП не имеет значения для вас, если вы не можете использовать их в своем коде.
@EvanTeran Помимо того, что это была цель вопроса, это, конечно, может быть полезно. Например, с целью настройки сходства потоков. Скажем, я хочу запустить 4 потока, привязанных к четырем последним ядрам ЦП на моей машине, вместо четырех первых ядер. Кроме того, есть и другие способы распараллеливания кода, кроме OpenMP. Я могу сам создавать потоки pthreads. Они, безусловно, доступны и не ограничиваются переменными среды OpenMP.
Это возвращает количество логических процессоров, а не ядер (физических процессоров) как таковых.
Еще один рецепт Windows: используйте общесистемную переменную среды NUMBER_OF_PROCESSORS:
printf("%d\n", atoi(getenv("NUMBER_OF_PROCESSORS")));
вы также можете использовать WMI в .net, но тогда вы зависите от запущенной службы wmi и т.д. Иногда он работает локально, но затем не работает, когда тот же код запускается на серверах. Я считаю, что это проблема пространства имен, связанная с «именами», значения которых вы читаете.
Альтернатива OS X: описанное ранее решение на основе [[NSProcessInfo processInfo] processorCount] доступно только в OS X 10.5.0, согласно документации. Для более ранних версий OS X используйте функцию Carbon MPProcessors ().
Если вы программист на Cocoa, не пугайтесь того факта, что это Carbon. Вам просто нужно добавить фреймворк Carbon в ваш проект Xcode, и MPProcessors () будет доступен.
(Почти) независимая от платформы функция в 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 источник
Не имеет отношения к C++, но в Linux я обычно делаю:
grep processor /proc/cpuinfo | wc -l
Удобно для таких языков сценариев, как bash / perl / python / ruby.
Для питона: import multiprocessingprint multiprocessing.cpu_count()
Прошло много времени, но grep имеет флаг -c для подсчета записей!
Прошло много времени, но мой Raspberry Pi имеет model name : ARMv6-compatible processor rev 7 (v6l) в своей cpuinfo, поэтому, вероятно, можно использовать grep -c ^processor /proc/cpuinfo.
hwloc (http://www.open-mpi.org/projects/hwloc/) заслуживает внимания. Хотя требуется интеграция другой библиотеки в ваш код, но она может предоставить всю информацию о вашем процессоре (количество ядер, топология и т. д.)
Подробнее об OS X: sysconf(_SC_NPROCESSORS_ONLN) доступен только в версиях> = 10.5, но не 10.4.
Альтернативой является код BSD HW_AVAILCPU/sysctl(), который доступен в версиях> = 10.2.
В 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
Для Win32:
Пока GetSystemInfo () дает вам количество процессоров логичный, используйте GetLogicalProcessorInformationEx () чтобы получить количество процессоров физический.
Количество групп логических процессоров, совместно использующих одно ядро процессора. (используя 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;
}
Обратите внимание, что реализация NumberOfPhysicalCores, IMHO, далеко не тривиальна (например, «используйте 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.
Спасибо! Я искал это, потому что GetLogicalProcessorInformation не работал с различными размерами буфера, которые я использовал. Более чем доволен! ^^
@KeyWeeUsr Спасибо. Программирование для Windows далеко не тривиально и логично. А пока я использую чуть более обновленный Версия C++ 17, который также более правильный по данным статического анализатора PVS-Studio в отношении некоторых приведений size_t. (Хотя msvC++ не жалуется на W4.)
Если вы хотите использовать его, чтобы узнать, сколько потоков нужно запустить, используйте NUMBER_OF_PROCESSORS в качестве основного показателя. Я оставляю это вам в качестве упражнения, почему это намного лучше (если бы люди использовали его чаще), чем использование аппаратных ядер. Сколько ядер принадлежит вашей программе - это экологическая проблема!