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