1#include <Common/getNumberOfPhysicalCPUCores.h>
2#include <thread>
3
4#include <Common/config.h>
5#if USE_CPUID
6# include <libcpuid/libcpuid.h>
7# include <Common/Exception.h>
8 namespace DB { namespace ErrorCodes { extern const int CPUID_ERROR; }}
9#elif USE_CPUINFO
10# include <cpuinfo.h>
11#endif
12
13
14
15unsigned getNumberOfPhysicalCPUCores()
16{
17#if USE_CPUID
18 cpu_raw_data_t raw_data;
19 cpu_id_t data;
20
21 /// On Xen VMs, libcpuid returns wrong info (zero number of cores). Fallback to alternative method.
22 /// Also, libcpuid does not support some CPUs like AMD Hygon C86 7151.
23 if (0 != cpuid_get_raw_data(&raw_data) || 0 != cpu_identify(&raw_data, &data) || data.num_logical_cpus == 0)
24 return std::thread::hardware_concurrency();
25
26 unsigned res = data.num_cores * data.total_logical_cpus / data.num_logical_cpus;
27
28 /// Also, libcpuid gives strange result on Google Compute Engine VMs.
29 /// Example:
30 /// num_cores = 12, /// number of physical cores on current CPU socket
31 /// total_logical_cpus = 1, /// total number of logical cores on all sockets
32 /// num_logical_cpus = 24. /// number of logical cores on current CPU socket
33 /// It means two-way hyper-threading (24 / 12), but contradictory, 'total_logical_cpus' == 1.
34
35 if (res != 0)
36 return res;
37
38#elif USE_CPUINFO
39 uint32_t cores = 0;
40 if (cpuinfo_initialize())
41 cores = cpuinfo_get_cores_count();
42
43 if (cores)
44 return cores;
45#endif
46
47 /// As a fallback (also for non-x86 architectures) assume there are no hyper-threading on the system.
48 /// (Actually, only Aarch64 is supported).
49 return std::thread::hardware_concurrency();
50}
51