CppCommon  1.0.4.1
C++ Common Library
cpu.cpp
Go to the documentation of this file.
1 
9 #include "system/cpu.h"
10 #include "utility/resource.h"
11 
12 #if defined(__APPLE__)
13 #include <sys/sysctl.h>
14 #elif defined(unix) || defined(__unix) || defined(__unix__)
15 #include <unistd.h>
16 #include <fstream>
17 #include <regex>
18 #elif defined(_WIN32) || defined(_WIN64)
19 #include <windows.h>
20 #endif
21 
22 namespace CppCommon {
23 
25 namespace Internals {
26 
27 #if defined(_WIN32) || defined(_WIN64)
28 
29 // Helper function to count set bits in the processor mask
30 DWORD CountSetBits(ULONG_PTR pBitMask)
31 {
32  DWORD dwLeftShift = sizeof(ULONG_PTR) * 8 - 1;
33  DWORD dwBitSetCount = 0;
34  ULONG_PTR pBitTest = (ULONG_PTR)1 << dwLeftShift;
35 
36  for (DWORD i = 0; i <= dwLeftShift; ++i)
37  {
38  dwBitSetCount += ((pBitMask & pBitTest) ? 1 : 0);
39  pBitTest /= 2;
40  }
41 
42  return dwBitSetCount;
43 }
44 
45 #endif
46 
47 } // namespace Internals
49 
50 std::string CPU::Architecture()
51 {
52 #if defined(__APPLE__)
53  char result[1024];
54  size_t size = sizeof(result);
55  if (sysctlbyname("machdep.cpu.brand_string", result, &size, nullptr, 0) == 0)
56  return result;
57 
58  return "<unknown>";
59 #elif defined(unix) || defined(__unix) || defined(__unix__)
60  static std::regex pattern("model name(.*): (.*)");
61 
62  std::string line;
63  std::ifstream stream("/proc/cpuinfo");
64  while (getline(stream, line))
65  {
66  std::smatch matches;
67  if (std::regex_match(line, matches, pattern))
68  return matches[2];
69  }
70 
71  return "<unknown>";
72 #elif defined(_WIN32) || defined(_WIN64)
73  HKEY hKeyProcessor;
74  LONG lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKeyProcessor);
75  if (lError != ERROR_SUCCESS)
76  return "<unknown>";
77 
78  // Smart resource cleaner pattern
79  auto key = resource(hKeyProcessor, [](HKEY hKey) { RegCloseKey(hKey); });
80 
81  CHAR pBuffer[_MAX_PATH] = { 0 };
82  DWORD dwBufferSize = sizeof(pBuffer);
83  lError = RegQueryValueExA(key.get(), "ProcessorNameString", nullptr, nullptr, (LPBYTE)pBuffer, &dwBufferSize);
84  if (lError != ERROR_SUCCESS)
85  return "<unknown>";
86 
87  return std::string(pBuffer);
88 #else
89  #error Unsupported platform
90 #endif
91 }
92 
94 {
95 #if defined(__APPLE__)
96  int logical = 0;
97  size_t logical_size = sizeof(logical);
98  if (sysctlbyname("hw.logicalcpu", &logical, &logical_size, nullptr, 0) != 0)
99  logical = -1;
100 
101  return logical;
102 #elif defined(unix) || defined(__unix) || defined(__unix__)
103  long processors = sysconf(_SC_NPROCESSORS_ONLN);
104  return processors;
105 #elif defined(_WIN32) || defined(_WIN64)
106  SYSTEM_INFO si;
107  GetSystemInfo(&si);
108  return si.dwNumberOfProcessors;
109 #else
110  #error Unsupported platform
111 #endif
112 }
113 
115 {
116  return TotalCores().first;
117 }
118 
120 {
121  return TotalCores().second;
122 }
123 
124 std::pair<int, int> CPU::TotalCores()
125 {
126 #if defined(__APPLE__)
127  int logical = 0;
128  size_t logical_size = sizeof(logical);
129  if (sysctlbyname("hw.logicalcpu", &logical, &logical_size, nullptr, 0) != 0)
130  logical = -1;
131 
132  int physical = 0;
133  size_t physical_size = sizeof(physical);
134  if (sysctlbyname("hw.physicalcpu", &physical, &physical_size, nullptr, 0) != 0)
135  physical = -1;
136 
137  return std::make_pair(logical, physical);
138 #elif defined(unix) || defined(__unix) || defined(__unix__)
139  long processors = sysconf(_SC_NPROCESSORS_ONLN);
140  return std::make_pair(processors, processors);
141 #elif defined(_WIN32) || defined(_WIN64)
142  BOOL allocated = FALSE;
143  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBuffer = nullptr;
144  DWORD dwLength = 0;
145 
146  while (!allocated)
147  {
148  BOOL bResult = GetLogicalProcessorInformation(pBuffer, &dwLength);
149  if (bResult == FALSE)
150  {
151  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
152  {
153  if (pBuffer != nullptr)
154  std::free(pBuffer);
155  pBuffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)std::malloc(dwLength);
156  if (pBuffer == nullptr)
157  return std::make_pair(-1, -1);
158  }
159  else
160  return std::make_pair(-1, -1);
161  }
162  else
163  allocated = TRUE;
164  }
165 
166  std::pair<int, int> result(0, 0);
167  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pCurrent = pBuffer;
168  DWORD dwOffset = 0;
169 
170  while (dwOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= dwLength)
171  {
172  switch (pCurrent->Relationship)
173  {
174  case RelationProcessorCore:
175  result.first += Internals::CountSetBits(pCurrent->ProcessorMask);
176  result.second += 1;
177  break;
178  case RelationNumaNode:
179  case RelationCache:
180  case RelationProcessorPackage:
181  break;
182  default:
183  return std::make_pair(-1, -1);
184  }
185  dwOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
186  pCurrent++;
187  }
188 
189  std::free(pBuffer);
190 
191  return result;
192 #else
193  #error Unsupported platform
194 #endif
195 }
196 
198 {
199 #if defined(__APPLE__)
200  uint64_t frequency = 0;
201  size_t size = sizeof(frequency);
202  if (sysctlbyname("hw.cpufrequency", &frequency, &size, nullptr, 0) == 0)
203  return frequency;
204 
205  return -1;
206 #elif defined(unix) || defined(__unix) || defined(__unix__)
207  static std::regex pattern("cpu MHz(.*): (.*)");
208 
209  std::string line;
210  std::ifstream stream("/proc/cpuinfo");
211  while (getline(stream, line))
212  {
213  std::smatch matches;
214  if (std::regex_match(line, matches, pattern))
215  return (int64_t)(atof(matches[2].str().c_str()) * 1000000);
216  }
217 
218  return -1;
219 #elif defined(_WIN32) || defined(_WIN64)
220  HKEY hKeyProcessor;
221  long lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKeyProcessor);
222  if (lError != ERROR_SUCCESS)
223  return -1;
224 
225  // Smart resource cleaner pattern
226  auto key = resource(hKeyProcessor, [](HKEY hKey) { RegCloseKey(hKey); });
227 
228  DWORD dwMHz = 0;
229  DWORD dwBufferSize = sizeof(DWORD);
230  lError = RegQueryValueExA(key.get(), "~MHz", nullptr, nullptr, (LPBYTE)&dwMHz, &dwBufferSize);
231  if (lError != ERROR_SUCCESS)
232  return -1;
233 
234  return dwMHz * 1000000;
235 #else
236  #error Unsupported platform
237 #endif
238 }
239 
241 {
242  std::pair<int, int> cores = TotalCores();
243  return (cores.first != cores.second);
244 }
245 
246 } // namespace CppCommon
static int LogicalCores()
CPU logical cores count.
Definition: cpu.cpp:114
static bool HyperThreading()
Is CPU Hyper-Threading enabled?
Definition: cpu.cpp:240
static int Affinity()
CPU affinity count.
Definition: cpu.cpp:93
static std::string Architecture()
CPU architecture string.
Definition: cpu.cpp:50
static std::pair< int, int > TotalCores()
CPU total cores count.
Definition: cpu.cpp:124
static int PhysicalCores()
CPU physical cores count.
Definition: cpu.cpp:119
static int64_t ClockSpeed()
CPU clock speed in Hz.
Definition: cpu.cpp:197
CPU management definition.
C++ Common project definitions.
Definition: token_bucket.h:15
auto resource(T handle, TCleaner cleaner)
Resource smart cleaner pattern.
Definition: resource.h:43
Resource smart cleaner pattern definition.