Lập trình tìm số lõi trên máy


464

Có cách nào để xác định có bao nhiêu lõi máy có từ C / C ++ theo cách độc lập với nền tảng không? Nếu không có thứ đó tồn tại, vậy còn việc xác định nó trên mỗi nền tảng (Windows / * nix / Mac) thì sao?


4
Nếu bạn muốn sử dụng nó, hãy tìm hiểu có bao nhiêu chủ đề để bắt đầu, vui lòng sử dụng NUMBER_OF_PROCESSORS làm thước đo chính. Tôi để nó như một lời khuyên cho bạn tại sao điều này tốt hơn nhiều (nếu mọi người sẽ sử dụng nó nhiều hơn) sau đó sử dụng lõi phần cứng. Bao nhiêu lõi thuộc về chương trình của bạn là một vấn đề môi trường!
Lothar

Lưu ý rằng std::thread::hardware_concurrencytrả về số lượng lõi CPU vật lý, nhưng nproctrong Linux chỉ hiển thị số lượng lõi CPU mà quy trình hiện tại có thể chạy, có thể được kiểm soát sched_setaffinity. Tôi đã không tìm thấy một cách để có được điều đó thay vì từ tiêu chuẩn C ++ :, thấy ví dụ bằng Python: stackoverflow.com/questions/1006289/...
Ciro Santilli郝海东冠状病六四事件法轮功

Câu trả lời:


706

C ++ 11

#include <thread>

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

Tham khảo: std :: thread :: phần cứng_concurrency


Trong C ++ trước C ++ 11, không có cách di động. Thay vào đó, bạn sẽ cần sử dụng một hoặc nhiều phương pháp sau (được bảo vệ bởi các #ifdefdòng thích hợp ):

  • Win32

    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
  • Linux, Solaris, AIX và Mac OS X> = 10,4 (tức là Tiger trở đi)

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

    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);
  • Mục tiêu-C (Mac OS X> = 10.5 hoặc iOS)

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

5
@mcandre: đó là một bài tập cho người đọc. Nếu tôi đang triển khai, có lẽ tôi sẽ sử dụng cách tiếp cận chính sách mẫu trong đó chính sách được xác định trong các chỉ thị tiền xử lý. Hoặc ... bạn có thể sử dụng boost thread :: phần cứng_concurrency ().
paxos1977

3
như một điểm để làm rõ, giải pháp Win32 trả về tổng số lõi (những gì được yêu cầu) chứ không phải tổng số CPU vật lý.
Eric

1
Cách Linux / Solaris / AIX cũng hoạt động trên FreeBSD và kể từ ít nhất là năm 2006. Ngoài ra, điều đó sẽ trả lại CPU trực tuyến, nếu một hệ thống có khả năng tắt một số thì chúng có thể không được tính. Gọi sysconf bằng "_SC_NPROCESSORS_CONF" sẽ trả về tổng số CPU được định cấu hình.
Chris S

3
Một vài điều cần lưu ý. HW_NCPUkhông được dùng trên OS X. Trên Windows GetSystemInfochỉ hữu ích nếu hệ thống của bạn có 32 bộ xử lý logic trở xuống, sử dụng GetLogicalProcessorInformationcho các hệ thống có nhiều hơn 32 bộ xử lý logic.

1
@Trejkaz tài liệu nói rõ ràng "logic" - vốn luôn luôn đếm các lõi HT, từ "vật lý" luôn đề cập đến các lõi được BIOS / UEFI báo cáo vì các lõi cũng có thể được mô phỏng / ảo hóa. Bạn có thể phân biệt giữa các lõi HT / không phải HT với các chức năng như GetLogicalProcessorInform chẳng hạn. Lưu ý: HT! = Giả lập hoặc ảo hóa, đó là một sự khác biệt lớn , HT là một tối ưu hóa phần cứng, có thể nói
đặc biệt

202

Chức năng này là một phần của tiêu chuẩn C ++ 11.

#include <thread>

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

Đối với các trình biên dịch cũ hơn, bạn có thể sử dụng thư viện Boost.Thread .

#include <boost/thread.hpp>

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

Trong cả hai trường hợp, hardware_concurrency()trả về số lượng luồng mà phần cứng có khả năng thực thi đồng thời dựa trên số lượng lõi CPU và các đơn vị siêu phân luồng.


1
Thứ hai ... sẽ sử dụng mã mẫu ở trên và một số macro tiền xử lý để hiển thị một chức năng duy nhất, nhưng công việc khó khăn đã được thực hiện cho tôi.
jkp

Đối với win32, đó là một cuộc gọi đến GetSystemInfo. (Kể từ phiên bản boost 1.41.0) Điều đó có nắm bắt được tất cả thông tin để xác định có bao nhiêu luồng công nhân sẽ có hiệu quả không? Có ai cần phải xem xét cả số lượng lõi và siêu phân luồng không? chuỗi không dấu :: phần cứng_concurrency () {HỆ THỐNG THÔNG TIN HỆ THỐNG = {0}; GetSystemInfo (& thông tin); trả về thông tin.dwNumberOfProcessors; }
Jive Dadson

Theo MSDN, GetSystemInfo () trả về số lượng "bộ xử lý vật lý" trong dwNumberOfProcessors nhưng nó không xác định ý nghĩa của nó. Tài liệu Boost dường như tuyên bố rằng nó bao gồm các đơn vị siêu phân luồng.
Ferruccio

xem stackoverflow.com/questions/642348/ cấp để biết siêu phân luồng
naugtur

57

OpenMP được hỗ trợ trên nhiều nền tảng (bao gồm Visual Studio 2005) và nó cung cấp một

int omp_get_num_procs();

Hàm trả về số lượng bộ xử lý / lõi khả dụng tại thời điểm gọi.


bởi vì đó là một câu trả lời sai Từ gcc.gnu.org/ormszilla/show_orms.cgi?id=37586 "omp_get_num_procs () sẽ chỉ trả về số lượng nhỏ hơn số lượng CPU hệ thống trực tuyến, nếu GOMP_CPU_AFFINITY env var được sử dụng hoặc nếu quá trình gọi và / Ái lực CPU giới hạn trong một tập hợp con của CPU ". Vì vậy, nếu bạn gọi sớm hơn, ví dụ, sched_setaffinityđiều này sẽ không hoạt động.
angainor

7
Hàm này trả về số lượng CPU có sẵn cho quá trình gọi. Nó không phải là trường hợp sử dụng phổ biến nhất anyway? Lớn hơn một số mục đích báo cáo vô dụng, số lượng lõi phần cứng CPU thực tế không liên quan đến bạn nếu bạn không thể tận dụng chúng trong mã của mình.
macbirdie

@EvanTeran Bên cạnh thực tế đó là mục đích của câu hỏi, tất nhiên nó có thể hữu ích. Ví dụ, với mục đích thiết lập ái lực của luồng. Nói rằng, tôi muốn chạy 4 luồng liên kết với bốn lõi CPU cuối cùng trên máy của tôi, thay vì bốn lõi đầu tiên. Và bên cạnh đó, có nhiều cách khác để song song mã ngoại trừ OpenMP. Tôi có thể muốn sinh ra pthreads mình. Chúng chắc chắn có sẵn và không bị hạn chế bởi các biến môi trường OpenMP.
angainor

2
Điều này trả về số lượng CPU logic, không phải lõi (CPU vật lý) như vậy.
Michael Konečný

37

Nếu bạn có quyền truy cập ngôn ngữ lắp ráp, bạn có thể sử dụng lệnh CPUID để nhận tất cả các loại thông tin về CPU. Nó di động giữa các hệ điều hành, mặc dù bạn sẽ cần sử dụng thông tin cụ thể của nhà sản xuất để xác định cách tìm số lượng lõi. Đây là một tài liệu mô tả cách thực hiện trên chip Intel và trang 11 của tài liệu này mô tả đặc điểm kỹ thuật của AMD.


4
Nó có thể đã bị hạ cấp vì câu hỏi được gắn thẻ là C ++ và câu trả lời này không áp dụng cho các hệ thống chạy C ++ trên các kiến ​​trúc không phải là x86 (ARM, PPC, v.v.). Tôi không nói đó là một lý do tốt để hạ thấp câu trả lời, chỉ là một khả năng.
Ferruccio

3
Một nhược điểm của phương pháp này là nếu bạn đang sử dụng CPUID để phát hiện HyperThreading trên bộ xử lý Intel. Tôi gặp phải vấn đề này trên máy tính xách tay của mình: trong khi CPU mà tôi đặt vào máy hỗ trợ HyperThreading (và tất nhiên, báo cáo rằng nó thông qua CPUID), BIOS thì không. Do đó, bạn không nên cố gắng sử dụng khả năng HT chỉ bằng cách đọc CPUID. Vì bạn không thể truy vấn BIOS về hỗ trợ HT (không có cách nào tôi đã thấy), nên hệ điều hành nên được truy vấn để có được số lượng bộ xử lý logic.
Chuck R

32

(Hầu hết) Nền tảng Chức năng độc lập trong mã 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
}

Có vẻ HW_NCPUkhông được chấp nhận trên nguồn

16

Trên Linux, bạn có thể đọc tệp / Proc / cpuinfo và đếm số lõi.


Ngoại trừ việc cũng tính các siêu phân luồng hoặc các giải pháp khác của SMT là nhiều lõi hơn ...
jakobengblom2

13
@Arafangion: siêu phân luồng không phải là thực thi song song thực sự, đó là một công nghệ để giảm chi phí chuyển đổi ngữ cảnh. Một cpu siêu phân luồng chỉ có thể thực thi một luồng tại một thời điểm, nhưng nó có thể lưu trữ trạng thái kiến ​​trúc (giá trị đăng ký, v.v.) của hai luồng cùng một lúc. Các đặc tính hiệu suất rất khác với việc có hai lõi.
Wim Coenen

7
@Wim: Điều đó không hoàn toàn chính xác. Các CPU có siêu phân luồng thường có nhiều ALU và có thể gửi nhiều lệnh cho mỗi chu kỳ. Nếu do phụ thuộc dữ liệu và quầy hàng, không phải tất cả ALU có thể được giữ bận bởi một luồng, thay vào đó, các ALU đó sẽ được sử dụng để thực thi đồng thời luồng xử lý phần cứng thứ hai.
Ben Voigt

11

Lưu ý rằng "số lõi" có thể không phải là một số đặc biệt hữu ích, bạn có thể phải đủ điều kiện hơn một chút. Bạn muốn đếm các CPU đa luồng như Intel HT, IBM Power5 và Power6 và nổi tiếng nhất là Niagara / UltraSparc T1 và T2 của Sun? Hay thú vị hơn nữa, MIPS 1004k với hai cấp độ phân luồng phần cứng (cấp độ giám sát và cấp độ người dùng) ... Chưa kể đến những gì xảy ra khi bạn chuyển sang các hệ thống hỗ trợ hypanneror nơi phần cứng có thể có hàng chục CPU nhưng hệ điều hành cụ thể của bạn chỉ thấy một vài

Điều tốt nhất bạn có thể hy vọng là cho biết số lượng đơn vị xử lý logic mà bạn có trong phân vùng HĐH cục bộ. Hãy quên việc nhìn thấy máy thật sự trừ khi bạn là một nhà ảo thuật. Ngoại lệ duy nhất cho quy tắc này ngày nay là ở vùng đất x86, nhưng sự kết thúc của các máy không ảo đang đến nhanh ...


7

Thêm một công thức Windows: sử dụng biến môi trường toàn hệ thống NUMBER_OF_PROCESSORS:

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

7

Bạn có thể sẽ không thể có được nó theo cách độc lập với nền tảng. Windows bạn nhận được số lượng bộ xử lý.

Thông tin hệ thống Win32


1
Carefull: Bộ xử lý siêu phân luồng cho biết có hai. Vì vậy, bạn cũng cần phải xem bộ xử lý có khả năng siêu phân luồng hay không.
Martin York

6

Windows (x64 và Win32) và C ++ 11

Số lượng các nhóm bộ xử lý logic chia sẻ một lõi bộ xử lý. (Sử dụng GetLogicalProcessorIn informationEx , hãy xem GetLogicalProcessorIn information )

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

Lưu ý rằng việc triển khai NumberOfPhysicalCoreslà IMHO khác xa với tầm thường (nghĩa là "sử dụng GetLogicalProcessorInformationhoặc GetLogicalProcessorInformationEx"). Thay vào đó, nó khá tinh tế nếu một người đọc tài liệu (trình bày rõ ràng GetLogicalProcessorInformationvà trình bày ngầm cho GetLogicalProcessorInformationEx) tại MSDN.

Số lượng bộ xử lý logic. (Sử dụng 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);
}

Lưu ý rằng cả hai phương pháp có thể dễ dàng được chuyển đổi thành C / C ++ 98 / C ++ 03.


1
Cảm ơn bạn! Tôi đã tìm kiếm điều này vì GetLogicalProcessorInformationkhông làm việc với các kích thước bộ đệm khác nhau mà tôi đã sử dụng. Hơn cả hài lòng! ^^
KeyWeeUsr

@KeyWeeUsr Cảm ơn lập trình Windows hơi xa tầm thường và logic. Trong khi đó, tôi sử dụng phiên bản C ++ 17 được cập nhật hơn một chút , điều này cũng đúng hơn theo phân tích tĩnh PVS-Studio liên quan đến một số size_tdiễn viên. (Mặc dù, msvc ++ không phàn nàn tại W4.)
Matthias

5

Thông tin thêm về OS X: sysconf(_SC_NPROCESSORS_ONLN)chỉ có các phiên bản> = 10,5, không phải 10,4.

Một thay thế là HW_AVAILCPU/sysctl()mã BSD có sẵn trên các phiên bản> = 10.2.



4

Không liên quan đến C ++, nhưng trên Linux tôi thường làm:

grep processor /proc/cpuinfo | wc -l

Tiện dụng cho các ngôn ngữ script như bash / perl / python / ruby.


4
Đối với trăn:import multiprocessing print multiprocessing.cpu_count()
initzero

3
Đó là một thời gian dài, nhưng grep-ccờ để đếm các mục!
Lapshin Dmitry

3

hwloc (http://www.open-mpi.org/projects/hwloc/) đáng để xem xét. Mặc dù yêu cầu tích hợp thư viện khác vào mã của bạn nhưng nó có thể cung cấp tất cả thông tin về bộ xử lý của bạn (số lượng lõi, cấu trúc liên kết, v.v.)


3

Trên linux cách lập trình tốt nhất theo như tôi biết là sử dụng

sysconf(_SC_NPROCESSORS_CONF)

hoặc là

sysconf(_SC_NPROCESSORS_ONLN)

Đây không phải là tiêu chuẩn, nhưng là trong trang người đàn ông của tôi cho Linux.


3

Trên Linux, có thể không an toàn khi sử dụng _SC_NPROCESSORS_ONLNvì nó không phải là một phần của tiêu chuẩn POSIX và hướng dẫn sử dụng sysconf nhiều như vậy. Vì vậy, có khả năng _SC_NPROCESSORS_ONLNcó thể không có mặt:

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

Một cách tiếp cận đơn giản sẽ là đọc /proc/stathoặc /proc/cpuinfođếm chúng:

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

Sử dụng /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;
}

Cách tiếp cận tương tự trong shell bằng grep:

grep -c ^processor /proc/cpuinfo

Hoặc là

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

2

Thay thế OS X: Giải pháp được mô tả trước đó dựa trên [[NSProcessInfo processInfo] bộ xử lý] chỉ khả dụng trên OS X 10.5.0, theo các tài liệu. Đối với các phiên bản trước của OS X, hãy sử dụng chức năng MPProcessors () của Carbon.

Nếu bạn là một lập trình viên của Cacao, đừng bối rối bởi thực tế đây là Carbon. Bạn chỉ cần thêm khung Carbon vào dự án Xcode của mình và MPProcessors () sẽ khả dụng.



-2

bạn cũng có thể sử dụng WMI trong .net nhưng sau đó bạn phụ thuộc vào dịch vụ wmi đang chạy, v.v. Đôi khi, nó hoạt động cục bộ, nhưng sau đó không thành công khi mã tương tự được chạy trên máy chủ. Tôi tin rằng đó là một vấn đề không gian tên, liên quan đến "tên" có giá trị bạn đang đọc.


-3

Trong Linux, bạn có thể kiểm tra dmesg và lọc các dòng nơi ACPI khởi tạo CPU, đại loại như:

dmesg | grep 'ACPI: Processor'

Khả năng khác là sử dụng dmidecode để lọc thông tin bộ xử lý.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.