Encuentra programáticamente el número de núcleos en una máquina


464

¿Hay alguna manera de determinar cuántos núcleos tiene una máquina de C / C ++ de forma independiente de la plataforma? Si no existe tal cosa, ¿qué hay de determinarlo por plataforma (Windows / * nix / Mac)?


44
Si desea usarlo, averigüe cuántos hilos comenzar, use NUMBER_OF_PROCESSORS como medida principal. Les dejo como ejercicio por qué esto es mucho mejor (si la gente lo usara más) que usar núcleos de hardware. ¡Cuántos núcleos pertenecen a su programa son un problema ambiental!
Lothar

Tenga en cuenta que std::thread::hardware_concurrencydevuelve el número de núcleos de CPU físicos, pero nprocen Linux muestra solo el número de núcleos de CPU en los que se puede ejecutar el proceso actual, que se pueden controlar sched_setaffinity. No he encontrado una manera de obtener eso en lugar de C ++ estándar :, consulte, por ejemplo, en Python: stackoverflow.com/questions/1006289/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:


706

C ++ 11

#include <thread>

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

Referencia: std :: thread :: hardware_concurrency


En C ++ anterior a C ++ 11, no hay una forma portátil. En su lugar, deberá utilizar uno o más de los siguientes métodos (protegido por las #ifdeflíneas apropiadas ):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
  • Linux, Solaris, AIX y Mac OS X> = 10.4 (es decir, Tiger en adelante)

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

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

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

55
@mcandre: eso se deja como ejercicio para el lector. Si estuviera implementando, probablemente usaría el enfoque de política de plantilla donde la política se definió en las directivas de preprocesador. O ... podría usar boost thread :: hardware_concurrency ().
paxos1977

3
Como punto de aclaración, la solución Win32 devuelve el número total de núcleos (lo que se solicitó), no el número total de CPU físicas.
Eric

1
La forma Linux / Solaris / AIX también funciona en FreeBSD y lo ha hecho desde al menos 2006. Además, eso devolverá las CPU en línea, si un sistema es capaz de apagar algunas, es posible que no se cuenten. Llamar a sysconf con "_SC_NPROCESSORS_CONF" devolverá el total de CPU configuradas.
Chris S

3
Un par de cosas a tener en cuenta. HW_NCPUestá en desuso en OS X. En Windows GetSystemInfosolo es útil si su sistema tiene 32 procesadores lógicos o menos, utilícelo GetLogicalProcessorInformationpara sistemas que tengan más de 32 procesadores lógicos.

1
@Trejkaz, la documentación dice claramente "lógico", que siempre cuenta los núcleos HT, la palabra "físico" siempre se refiere a los núcleos informados por el BIOS / UEFI, ya que los núcleos también pueden ser emulados / virtualizados. Puede diferenciar entre núcleos HT / no HT con funciones como GetLogicalProcessorInformation , por ejemplo. Nota: HT! = Emulación o virtualización, eso es una gran diferencia, HT es una optimización de hardware, por así decirlo
especializt

202

Esta funcionalidad es parte del estándar C ++ 11.

#include <thread>

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

Para compiladores más antiguos, puede usar la biblioteca Boost.Thread .

#include <boost/thread.hpp>

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

En cualquier caso, hardware_concurrency()devuelve el número de subprocesos que el hardware es capaz de ejecutar simultáneamente en función del número de núcleos de CPU y unidades de hiperprocesamiento.


1
Secundado ... iba a usar el código de muestra anterior y algunas macros de preprocesador para exponer una sola función, pero el trabajo duro fue hecho por mí.
jkp

Para win32, es una llamada a GetSystemInfo. (A partir de la versión 1.41.0 de impulso) ¿Captura eso toda la información para determinar cuántos hilos de trabajo serían efectivos? ¿Es necesario tener en cuenta tanto el número de núcleos como el hiperprocesamiento? hilo sin firmar :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& info); return info.dwNumberOfProcessors; }
Jive Dadson

Según MSDN, GetSystemInfo () devuelve el número de "procesadores físicos" en dwNumberOfProcessors pero no define lo que significa con eso. La documentación de Boost parece afirmar que incluye unidades de hyperthreading.
Ferruccio


57

OpenMP es compatible con muchas plataformas (incluido Visual Studio 2005) y ofrece un

int omp_get_num_procs();

función que devuelve el número de procesadores / núcleos disponibles en el momento de la llamada.


porque es una respuesta incorrecta De gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 "omp_get_num_procs () solo devolverá un número menor que el número de CPU del sistema en línea, si se utiliza GOMP_CPU_AFFINITY env var, o si el proceso de llamada y / o el hilo tienen Afinidad de CPU limitada a un subconjunto de CPU ". Entonces, si llama anteriormente, por ejemplo, sched_setaffinityesto no funcionará.
angainor

77
Esta función devuelve el número de CPU disponibles para el proceso de llamada. ¿No es el caso de uso más común de todos modos? El tamaño real de algunos propósitos de informes inútiles, el número real de núcleos de hardware de CPU no es relevante para usted si no puede aprovecharlos en su código.
macbirdie

@EvanTeran Además del hecho de que era el propósito de la pregunta, por supuesto puede ser útil. Por ejemplo, con el fin de establecer la afinidad de hilo. Digamos, quiero ejecutar 4 hilos vinculados a los cuatro últimos núcleos de CPU en mi máquina, en lugar de cuatro primeros núcleos. Y además, hay otras formas de paralelizar el código, excepto OpenMP. Es posible que quiera generar pthreads yo mismo. Esos seguramente están disponibles y no están restringidos por las variables de entorno de OpenMP.
Angainor

2
Esto devuelve el número de CPU lógicas, no núcleos (CPU físicas) como tales.
Michael Konečný

37

Si tiene acceso en lenguaje ensamblador, puede usar la instrucción CPUID para obtener todo tipo de información sobre la CPU. Es portátil entre sistemas operativos, aunque necesitará usar información específica del fabricante para determinar cómo encontrar el número de núcleos. Aquí hay un documento que describe cómo hacerlo en chips Intel , y la página 11 de este describe la especificación AMD.


44
Es posible que se haya rechazado porque la pregunta está etiquetada como C ++ y esta respuesta no se aplica a los sistemas que ejecutan C ++ en arquitecturas que no son x86 (ARM, PPC, etc.). No digo que sea una buena razón para rechazar una respuesta, solo una posibilidad.
Ferruccio

3
Una trampa de este método es si está utilizando CPUID para detectar HyperThreading en procesadores Intel. Me encontré con este problema en mi computadora portátil: mientras que la CPU que puse en la máquina admite HyperThreading (y, por supuesto, informa que lo hace a través de CPUID), el BIOS no. Por lo tanto, no debe intentar utilizar la capacidad HT simplemente desde una lectura de CPUID. Como no puede consultar el BIOS sobre el soporte HT (de ninguna manera que haya visto), se debe consultar el sistema operativo para obtener el recuento lógico del procesador.
Chuck R

32

(Casi) Plataforma Función independiente en código 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
}

Parece que HW_NCPUestá en desuso en la fuente

16

En Linux, puede leer el archivo / proc / cpuinfo y contar los núcleos.


Excepto que que además cuenta hyperthreaded u otras soluciones SMT como más núcleos ...
jakobengblom2

13
@Arafangion: hyperthreading no es una verdadera ejecución paralela, es una tecnología para reducir la sobrecarga de cambio de contexto. Una CPU hyperthreaded solo puede ejecutar un subproceso a la vez, pero puede almacenar el estado arquitectónico (valores de registro, etc.) de dos subprocesos al mismo tiempo. Las características de rendimiento son muy diferentes de tener dos núcleos.
Wim Coenen

77
@Wim: Eso no es completamente correcto. Las CPU con hyperthreading generalmente tienen múltiples ALU y pueden enviar múltiples instrucciones por ciclo. Si debido a dependencias de datos y paradas, no todas las ALU pueden mantenerse ocupadas por un subproceso, esas ALU se utilizarán para la ejecución simultánea del segundo subproceso de hardware.
Ben Voigt

11

Tenga en cuenta que "número de núcleos" puede no ser un número particularmente útil, puede que tenga que calificarlo un poco más. ¿Cómo desea contar las CPU de subprocesos múltiples como Intel HT, IBM Power5 y Power6, y más famoso, Sun's Niagara / UltraSparc T1 y T2? O aún más interesante, el MIPS 1004k con sus dos niveles de subprocesamiento de hardware (supervisor Y nivel de usuario) ... Sin mencionar lo que sucede cuando se muda a sistemas compatibles con hipervisor donde el hardware puede tener decenas de CPU pero su sistema operativo particular solo ve unos pocos.

Lo mejor que puede esperar es decir la cantidad de unidades de procesamiento lógico que tiene en su partición local del sistema operativo. Olvídate de ver la verdadera máquina a menos que seas un hipervisor. La única excepción a esta regla hoy es en tierra x86, pero el final de las máquinas no virtuales está llegando rápidamente ...


7

Una receta más de Windows: use la variable de entorno de todo el sistema NUMBER_OF_PROCESSORS:

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

7

Probablemente no podrá obtenerlo de forma independiente de la plataforma. Windows obtienes varios procesadores.

Información del sistema Win32


1
Cuidadoso: los procesadores hiperprocesados ​​dicen que hay dos. Por lo tanto, también debe ver si el procesador es compatible con hyperthread.
Martin York

6

Windows (x64 y Win32) y C ++ 11

El número de grupos de procesadores lógicos que comparten un solo núcleo de procesador. (Usando GetLogicalProcessorInformationEx , vea también 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;
}

Tenga en cuenta que la implementación de en NumberOfPhysicalCoresmi humilde opinión está lejos de ser trivial (es decir, "uso GetLogicalProcessorInformationo GetLogicalProcessorInformationEx"). En cambio, es bastante sutil si uno lee la documentación (explícitamente presente GetLogicalProcessorInformatione implícitamente presente GetLogicalProcessorInformationEx) en MSDN.

El número de procesadores lógicos. (Usando 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);
}

Tenga en cuenta que ambos métodos se pueden convertir fácilmente a C / C ++ 98 / C ++ 03.


1
¡Gracias! Estaba buscando esto porque GetLogicalProcessorInformationno trabajaba con varios tamaños de búfer que usaba. Más que satisfecho! ^^
KeyWeeUsr

@KeyWeeUsr Gracias La programación de Windows está lejos de ser trivial y lógica. Mientras tanto, uso una versión de C ++ 17 ligeramente más actualizada que también es más correcta según el analizador estático PVS-Studio con respecto a algunos size_tmodelos. (Aunque msvc ++ no se queja en W4.)
Matthias

5

Más sobre OS X: sysconf(_SC_NPROCESSORS_ONLN)solo está disponible versiones> = 10.5, no 10.4.

Una alternativa es el HW_AVAILCPU/sysctl()código BSD que está disponible en versiones> = 10.2.



4

Sin relación con C ++, pero en Linux generalmente lo hago:

grep processor /proc/cpuinfo | wc -l

Práctico para lenguajes de script como bash / perl / python / ruby.


44
Para python:import multiprocessing print multiprocessing.cpu_count()
initzero

3
¡Ha pasado mucho tiempo, pero greptiene -cbandera para contar entradas!
Lapshin Dmitry

3

Vale la pena mirar hwloc (http://www.open-mpi.org/projects/hwloc/). Aunque requiere otra integración de biblioteca en su código, pero puede proporcionar toda la información sobre su procesador (número de núcleos, la topología, etc.)


3

En Linux, la mejor forma programática que yo sepa es usar

sysconf(_SC_NPROCESSORS_CONF)

o

sysconf(_SC_NPROCESSORS_ONLN)

Estos no son estándar, pero están en mi página de manual para Linux.


3

En Linux, es posible que no sea seguro de usar, _SC_NPROCESSORS_ONLNya que no forma parte del estándar POSIX y el manual sysconf lo dice tanto. Entonces, existe la posibilidad de que _SC_NPROCESSORS_ONLNno esté presente:

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

Un enfoque simple sería leerlos /proc/stato /proc/cpuinfocontarlos:

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

Utilizando /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;
}

El mismo enfoque en shell usando grep:

grep -c ^processor /proc/cpuinfo

O

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

2

Alternativa OS X: la solución descrita anteriormente basada en [[NSProcessInfo processInfo] processorCount] solo está disponible en OS X 10.5.0, según los documentos. Para versiones anteriores de OS X, use la función Carbon MPProcessors ().

Si eres un programador de Cocoa, no te asustes por el hecho de que se trata de carbono. Solo necesita agregar el marco Carbon a su proyecto Xcode y MPProcessors () estará disponible.



-2

también puede usar WMI en .net, pero luego depende del servicio wmi que se ejecuta, etc. A veces funciona localmente, pero luego falla cuando se ejecuta el mismo código en los servidores. Creo que es un problema de espacio de nombres, relacionado con los "nombres" cuyos valores estás leyendo.


-3

En Linux, puede pagar dmesg y filtrar las líneas donde ACPI inicializa las CPU, algo así como:

dmesg | grep 'ACPI: Processor'

Otra posibilidad es usar dmidecode para filtrar la información del procesador.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.