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.