Encontre programaticamente o número de núcleos em uma máquina


464

Existe uma maneira de determinar quantos núcleos uma máquina possui do C / C ++ de maneira independente da plataforma? Se isso não existe, que tal determiná-lo por plataforma (Windows / * nix / Mac)?


4
Se você quiser usá-lo, descubra quantos threads iniciar, use NUMBER_OF_PROCESSORS como medida principal. Deixo como exercício para você porque isso é muito melhor (se as pessoas o usassem mais) do que usar núcleos de hardware. A quantidade de núcleos pertencentes ao seu programa é uma questão ambiental!
Lothar

Observe que std::thread::hardware_concurrencyretorna o número de núcleos físicos da CPU, mas nprocno Linux mostra apenas o número de núcleos da CPU nos quais o processo atual pode ser executado, que pode ser controlado sched_setaffinity. Eu não encontrei uma maneira de conseguir que, em vez de C ++ padrão :, ver, por exemplo, em Python: stackoverflow.com/questions/1006289/...
Ciro Santilli郝海东冠状病六四事件法轮功

Respostas:


706

C ++ 11

#include <thread>

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

Referência: std :: thread :: hardware_concurrency


No C ++ anterior ao C ++ 11, não há maneira portátil. Em vez disso, você precisará usar um ou mais dos seguintes métodos (protegidos pelas #ifdeflinhas apropriadas ):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
    
  • Linux, Solaris, AIX e Mac OS X> = 10.4 (ou seja, Tiger em diante)

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

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

5
@ MCANDRE: isso é deixado como um exercício para o leitor. Se eu estivesse implementando, provavelmente usaria a abordagem de política de modelo, onde a política foi definida nas diretivas de pré-processador. Ou ... você pode usar o boost thread :: hardware_concurrency ().
paxos1977

3
como um ponto de esclarecimento, a solução Win32 retorna o número total de núcleos (o que foi solicitado) e não o número total de CPUs físicas.
Eric

1
A maneira Linux / Solaris / AIX também funciona no FreeBSD e tem desde pelo menos 2006. Além disso, isso retornará as CPUs on-line, se um sistema for capaz de desligar algumas, elas podem não ser contadas. Chamar sysconf com "_SC_NPROCESSORS_CONF" retornará o total de CPUs configuradas.
Chris S

3
Algumas coisas para estar ciente. HW_NCPUfoi descontinuado no OS X. No Windows, GetSystemInfoapenas é útil se o seu sistema tiver 32 processadores lógicos ou menos, use GetLogicalProcessorInformationpara sistemas que tenham mais de 32 processadores lógicos.

1
@Trejkaz, a documentação diz claramente "lógico" - que está sempre contando núcleos HT, a palavra "físico" sempre se refere aos núcleos relatados pelo BIOS / UEFI, pois os núcleos também podem ser emulados / virtualizados. Você pode diferenciar núcleos HT / não HT com funções como GetLogicalProcessorInformation , por exemplo. Nota: HT! = Emulação ou virtualização, isso é uma grande diferença, HT é uma otimização de hardware, por assim dizer
specializt

202

Essa funcionalidade faz parte do padrão C ++ 11.

#include <thread>

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

Para compiladores mais antigos, você pode usar a biblioteca Boost.Thread .

#include <boost/thread.hpp>

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

Nos dois casos, hardware_concurrency()retorna o número de threads que o hardware é capaz de executar simultaneamente, com base no número de núcleos da CPU e unidades de hyperthreading.


1
Destacado ... ia usar o código de exemplo acima e algumas macros do pré-processador para expor uma única função, mas o trabalho duro foi feito para mim.
jkp

Para o win32, é uma chamada para GetSystemInfo. (A partir da versão 1.41.0 do boost) Isso captura todas as informações para determinar quantos threads de trabalho seriam eficazes? É necessário considerar o número de núcleos e o hyperthreading? thread não assinado :: hardware_concurrency () {SYSTEM_INFO info = {0}; GetSystemInfo (& info); retornar info.dwNumberOfProcessors; }
Jive Dadson,

De acordo com o MSDN, GetSystemInfo () retorna o número de "processadores físicos" em dwNumberOfProcessors, mas não define o que significa isso. A documentação do Boost parece alegar que inclui unidades de hyperthreading.
Ferruccio


57

O OpenMP é suportado em muitas plataformas (incluindo o Visual Studio 2005) e oferece um

int omp_get_num_procs();

função que retorna o número de processadores / núcleos disponíveis no momento da chamada.


porque é uma resposta errada. Em gcc.gnu.org/bugzilla/show_bug.cgi?id=37586 "omp_get_num_procs () retornará apenas um número menor que o número de CPUs do sistema on-line, se GOMP_CPU_AFFINITY env var for usado, ou se o processo de chamada e / ou o thread tiver Afinidade de CPU limitada a um subconjunto de CPUs ". Portanto, se você ligar anteriormente, por exemplo, sched_setaffinityisso não funcionará.
angainor

7
Esta função retorna o número de CPUs disponíveis para o processo de chamada. Não é o caso de uso mais comum, afinal? Fora do tamanho de algumas finalidades inúteis para relatórios, o número real de núcleos de hardware da CPU não é relevante para você se você não puder tirar proveito deles em seu código.
macbirdie

@EvanTeran Além do fato de ter sido o objetivo da pergunta, é claro que pode ser útil. Por exemplo, com a finalidade de definir a afinidade do encadeamento. Digamos, quero executar 4 threads vinculados aos quatro últimos núcleos da CPU em minha máquina, em vez dos quatro primeiros núcleos. Além disso, existem outras maneiras de paralelizar o código, exceto o OpenMP. Eu posso querer criar pthreads eu mesmo. Eles certamente estão disponíveis e não são restritos pelas variáveis ​​de ambiente do OpenMP.
angainor

2
Isso retorna o número de CPUs lógicas, não de núcleos (CPUs físicas) como tal.
Michael Konečný

37

Se você tiver acesso à linguagem assembly, poderá usar a instrução CPUID para obter todos os tipos de informações sobre a CPU. É portátil entre sistemas operacionais, embora você precise usar informações específicas do fabricante para determinar como encontrar o número de núcleos. Aqui está um documento que descreve como fazê-lo em chips Intel , e a página 11 deste descreve a especificação da AMD.


4
Pode ter sido recusado porque a pergunta está marcada como C ++ e esta resposta não se aplica a sistemas executando C ++ em arquiteturas não-x86 (ARM, PPC, etc.). Não estou dizendo que é uma boa razão para votar uma resposta, apenas uma possibilidade.
Ferruccio

3
Uma armadilha desse método é se você estiver usando o CPUID para detectar o HyperThreading nos processadores Intel. Eu me deparei com esse problema no meu laptop: enquanto a CPU que eu coloco na máquina suporta HyperThreading (e, é claro, relata isso via CPUID), o BIOS não. Portanto, você não deve tentar utilizar o recurso HT simplesmente a partir de uma leitura de CPUID. Como você não pode consultar o BIOS sobre suporte a HT (de jeito nenhum que eu tenha visto), o sistema operacional deve ser consultado para obter a contagem lógica do processador.
Chuck R

32

Função (quase) independente de plataforma no 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_NCPUfoi descontinuado na origem do

16

No Linux, você pode ler o arquivo / proc / cpuinfo e contar os núcleos.


Só que que também conta HyperThreaded ou outras soluções de SMT como mais núcleos ...
jakobengblom2

13
@Arafangion: hyperthreading não é uma execução paralela verdadeira, é uma tecnologia para reduzir a sobrecarga da alternância de contexto. Uma CPU com hyperthread pode executar apenas um encadeamento por vez, mas pode armazenar o estado arquitetural (valores de registro etc.) de dois encadeamentos ao mesmo tempo. As características de desempenho são muito diferentes de ter dois núcleos.
Wim Coenen

7
@ Wim: Isso não está completamente correto. As CPUs com hyperthreading geralmente têm várias ALUs e podem enviar várias instruções por ciclo. Se, devido a dependências e paralisações de dados, nem todas as ALUs puderem ser mantidas ocupadas por um encadeamento, essas ALUs serão usadas para execução simultânea do segundo encadeamento de hardware.
precisa

11

Observe que "número de núcleos" pode não ser um número particularmente útil; talvez seja necessário qualificá-lo um pouco mais. Como você deseja contar com CPUs multithread, como Intel HT, IBM Power5 e Power6, e mais famoso, Niagara / UltraSparc T1 e T2 da Sun? Ou ainda mais interessante, o MIPS 1004k com seus dois níveis de encadeamento de hardware (supervisor E nível de usuário) ... Sem mencionar o que acontece quando você se muda para sistemas suportados por hipervisor, nos quais o hardware pode ter dezenas de CPUs, mas seu SO específico só vê alguns.

O melhor que você pode esperar é informar o número de unidades de processamento lógico que você possui na partição do sistema operacional local. Esqueça de ver a máquina verdadeira, a menos que você seja um hipervisor. Hoje, a única exceção a essa regra está no terreno x86, mas o fim das máquinas não virtuais está chegando rapidamente ...


7

Mais uma receita do Windows: use a variável de ambiente de todo o sistema NUMBER_OF_PROCESSORS:

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

7

Você provavelmente não conseguirá obtê-lo de maneira independente da plataforma. Windows você obtém número de processadores.

Informações do sistema Win32


1
Cuidado: Os processadores com hyperthread dizem que existem dois. Portanto, você também precisa ver se o processador é capaz de hyperthread.
Martin York

6

Windows (x64 e Win32) e C ++ 11

O número de grupos de processadores lógicos que compartilham um único núcleo de processador. (Usando GetLogicalProcessorInformationEx , consulte GetLogicalProcessorInformation também)

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

Observe que a implementação do NumberOfPhysicalCoresIMHO está longe de ser trivial (ou seja, "use GetLogicalProcessorInformationor GetLogicalProcessorInformationEx"). Em vez disso, é bastante sutil se alguém ler a documentação (explicitamente presente para GetLogicalProcessorInformatione implicitamente presente para GetLogicalProcessorInformationEx) no MSDN.

O número de processadores 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);
}

Observe que ambos os métodos podem ser facilmente convertidos em C / C ++ 98 / C ++ 03.


1
Obrigado! Eu estava procurando isso por GetLogicalProcessorInformationnão trabalhar com vários tamanhos de buffer que usei. Mais do que satisfeito! ^^
KeyWeeUsr

@KeyWeeUsr Obrigado A programação do Windows está um pouco longe de trivial e lógica. Enquanto isso, uso uma versão C ++ 17 um pouco mais atualizada, que também é mais correta de acordo com o analisador estático PVS-Studio em relação a alguns size_tmodelos. (Embora, msvc ++ não reclamar na W4.)
Matthias

5

Mais informações sobre o OS X: sysconf(_SC_NPROCESSORS_ONLN)está disponível apenas nas versões> = 10.5, não 10.4.

Uma alternativa é o HW_AVAILCPU/sysctl()código BSD que está disponível nas versões> = 10.2.



4

Não relacionado ao C ++, mas no Linux eu costumo fazer:

grep processor /proc/cpuinfo | wc -l

Útil para linguagens de script como bash / perl / python / ruby.


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

3
Já faz muito tempo, mas greptem -csinalizador para contar entradas!
Lapshin Dmitry

3

vale a pena ver o hwloc (http://www.open-mpi.org/projects/hwloc/). Embora exija outra integração de biblioteca em seu código, ele pode fornecer todas as informações sobre seu processador (número de núcleos, topologia etc.)


3

No linux, a melhor maneira programática, até onde eu sei, é usar

sysconf(_SC_NPROCESSORS_CONF)

ou

sysconf(_SC_NPROCESSORS_ONLN)

Estes não são padrão, mas estão na minha página de manual do Linux.


3

No Linux, pode não ser seguro usá- _SC_NPROCESSORS_ONLNlo, pois não faz parte do padrão POSIX e o manual sysconf afirma o mesmo. Portanto, há uma possibilidade que _SC_NPROCESSORS_ONLNpode não estar 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).

Uma abordagem simples seria ler /proc/statou /proc/cpuinfocontá-los:

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

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

A mesma abordagem no shell usando grep:

grep -c ^processor /proc/cpuinfo

Ou

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

2

Alternativa para OS X: a solução descrita anteriormente com base em [[NSProcessInfo processInfo] processorCount] está disponível apenas no OS X 10.5.0, de acordo com a documentação. Para versões anteriores do OS X, use a função Carbon MPProcessors ().

Se você é um programador de cacau, não se assuste com o fato de ser carbono. Você só precisa adicionar a estrutura Carbon ao seu projeto Xcode e o MPProcessors () estará disponível.



-2

você também pode usar o WMI no .net, mas depende do serviço wmi em execução etc. Às vezes, funciona localmente, mas falha quando o mesmo código é executado nos servidores. Acredito que seja um problema de espaço para nome, relacionado aos "nomes" cujos valores você está lendo.


-3

No Linux, você pode verificar o dmesg e filtrar as linhas onde a ACPI inicializa as CPUs, algo como:

dmesg | grep 'ACPI: Processor"

Outra possibilidade é usar o dmidecode para filtrar as informações do processador.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.