qb  2.0.0.0
C++17 Actor Framework
qb Issue Watch Star Fork Follow @isndev
Loading...
Searching...
No Matches
cpu.h
Go to the documentation of this file.
1
24
25#ifndef FEATURES_CPU_H
26#define FEATURES_CPU_H
27
28#include <memory>
29#include <thread>
30#if defined(__APPLE__)
31#include <sys/sysctl.h>
32#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
33#include <fstream>
34#include <regex>
35#include <unistd.h>
36#elif defined(_WIN32) || defined(_WIN64)
37#ifndef NOMINMAX
38#define NOMINMAX
39#endif
40#ifndef WIN32_LEAN_AND_MEAN
41#define WIN32_LEAN_AND_MEAN
42#include <windows.h>
43#endif
44#endif
45
50namespace Internals {
51
52#if defined(_WIN32) || defined(_WIN64)
61DWORD
62CountSetBits(ULONG_PTR pBitMask) {
63 DWORD dwLeftShift = sizeof(ULONG_PTR) * 8 - 1;
64 DWORD dwBitSetCount = 0;
65 ULONG_PTR pBitTest = (ULONG_PTR) 1 << dwLeftShift;
66
67 for (DWORD i = 0; i <= dwLeftShift; ++i) {
68 dwBitSetCount += ((pBitMask & pBitTest) ? 1 : 0);
69 pBitTest /= 2;
70 }
71
72 return dwBitSetCount;
73}
74#endif
75
76} // namespace Internals
77
78namespace qb {
79
92template <typename T, typename TCleaner>
93auto
94resource(T handle, TCleaner cleaner) {
95 return std::unique_ptr<typename std::remove_pointer<T>::type, TCleaner>(handle,
96 cleaner);
97}
98
109template <typename TCleaner>
110auto
111resource(void *handle, TCleaner cleaner) {
112 return std::unique_ptr<void, TCleaner>(handle, cleaner);
113}
114
124template <typename TCleaner>
125auto
126resource(TCleaner cleaner) {
127 return std::unique_ptr<void, TCleaner>(&cleaner, cleaner);
128}
129
137class CPU {
138public:
139 CPU() = delete;
140 CPU(const CPU &) = delete;
141 CPU(CPU &&) noexcept = delete;
142 ~CPU() = delete;
143
144 CPU &operator=(const CPU &) = delete;
145 CPU &operator=(CPU &&) noexcept = delete;
146
152 static std::string
154#if defined(__APPLE__)
155 char result[1024];
156 size_t size = sizeof(result);
157 if (sysctlbyname("machdep.cpu.brand_string", result, &size, nullptr, 0) == 0)
158 return result;
159
160 return "<unknown>";
161#elif defined(unix) || defined(__unix) || defined(__unix__)
162 static std::regex pattern("model name(.*): (.*)");
163
164 std::string line;
165 std::ifstream stream("/proc/cpuinfo");
166 while (getline(stream, line)) {
167 std::smatch matches;
168 if (std::regex_match(line, matches, pattern))
169 return matches[2];
170 }
171
172 return "<unknown>";
173#elif defined(_WIN32) || defined(_WIN64)
174 HKEY hKeyProcessor;
175 LONG lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
176 "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
177 0, KEY_READ, &hKeyProcessor);
178 if (lError != ERROR_SUCCESS)
179 return "<unknown>";
180
181 // Smart resource cleaner pattern
182 auto key = resource(hKeyProcessor, [](HKEY hKey) { RegCloseKey(hKey); });
183
184 CHAR pBuffer[_MAX_PATH] = {0};
185 DWORD dwBufferSize = sizeof(pBuffer);
186 lError = RegQueryValueExA(key.get(), "ProcessorNameString", nullptr, nullptr,
187 (LPBYTE) pBuffer, &dwBufferSize);
188 if (lError != ERROR_SUCCESS)
189 return "<unknown>";
190
191 return std::string(pBuffer);
192#else
193#error Unsupported platform
194#endif
195 }
196
201 static int
203#if defined(__APPLE__)
204 int logical = 0;
205 size_t logical_size = sizeof(logical);
206 if (sysctlbyname("hw.logicalcpu", &logical, &logical_size, nullptr, 0) != 0)
207 logical = -1;
208
209 return logical;
210#elif defined(unix) || defined(__unix) || defined(__unix__)
211 long processors = sysconf(_SC_NPROCESSORS_ONLN);
212 return processors;
213#elif defined(_WIN32) || defined(_WIN64)
214 SYSTEM_INFO si;
215 GetSystemInfo(&si);
216 return si.dwNumberOfProcessors;
217#else
218#error Unsupported platform
219#endif
220 }
221
226 static int
228 return TotalCores().first;
229 }
230
235 static int
237 return TotalCores().second;
238 }
239
244 static std::pair<int, int>
246#if defined(__APPLE__)
247 int logical = 0;
248 size_t logical_size = sizeof(logical);
249 if (sysctlbyname("hw.logicalcpu", &logical, &logical_size, nullptr, 0) != 0)
250 logical = -1;
251
252 int physical = 0;
253 size_t physical_size = sizeof(physical);
254 if (sysctlbyname("hw.physicalcpu", &physical, &physical_size, nullptr, 0) != 0)
255 physical = -1;
256
257 return std::make_pair(logical, physical);
258#elif defined(unix) || defined(__unix) || defined(__unix__)
259 long processors = sysconf(_SC_NPROCESSORS_ONLN);
260 return std::make_pair(processors, processors);
261#elif defined(_WIN32) || defined(_WIN64)
262 BOOL allocated = FALSE;
263 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBuffer = nullptr;
264 DWORD dwLength = 0;
265
266 while (!allocated) {
267 BOOL bResult = GetLogicalProcessorInformation(pBuffer, &dwLength);
268 if (bResult == FALSE) {
269 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
270 if (pBuffer != nullptr)
271 std::free(pBuffer);
272 pBuffer =
273 (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) std::malloc(dwLength);
274 if (pBuffer == nullptr)
275 return std::make_pair(-1, -1);
276 } else
277 return std::make_pair(-1, -1);
278 } else
279 allocated = TRUE;
280 }
281
282 std::pair<int, int> result(0, 0);
283 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pCurrent = pBuffer;
284 DWORD dwOffset = 0;
285
286 while (dwOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= dwLength) {
287 switch (pCurrent->Relationship) {
288 case RelationProcessorCore:
289 result.first += Internals::CountSetBits(pCurrent->ProcessorMask);
290 result.second += 1;
291 break;
292 case RelationNumaNode:
293 case RelationCache:
294 case RelationProcessorPackage:
295 break;
296 default:
297 return std::make_pair(-1, -1);
298 }
299 dwOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
300 pCurrent++;
301 }
302
303 std::free(pBuffer);
304
305 return result;
306#else
307#error Unsupported platform
308#endif
309 }
310
315 static int64_t
317#if defined(__APPLE__)
318 uint64_t frequency = 0;
319 size_t size = sizeof(frequency);
320 if (sysctlbyname("hw.cpufrequency", &frequency, &size, nullptr, 0) == 0)
321 return frequency;
322
323 return -1;
324#elif defined(unix) || defined(__unix) || defined(__unix__)
325 static std::regex pattern("cpu MHz(.*): (.*)");
326
327 std::string line;
328 std::ifstream stream("/proc/cpuinfo");
329 while (getline(stream, line)) {
330 std::smatch matches;
331 if (std::regex_match(line, matches, pattern))
332 return (int64_t) (atof(matches[2].str().c_str()) * 1000000);
333 }
334
335 return -1;
336#elif defined(_WIN32) || defined(_WIN64)
337 HKEY hKeyProcessor;
338 long lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
339 "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
340 0, KEY_READ, &hKeyProcessor);
341 if (lError != ERROR_SUCCESS)
342 return -1;
343
344 // Smart resource cleaner pattern
345 auto key = resource(hKeyProcessor, [](HKEY hKey) { RegCloseKey(hKey); });
346
347 DWORD dwMHz = 0;
348 DWORD dwBufferSize = sizeof(DWORD);
349 lError = RegQueryValueExA(key.get(), "~MHz", nullptr, nullptr, (LPBYTE) &dwMHz,
350 &dwBufferSize);
351 if (lError != ERROR_SUCCESS)
352 return -1;
353
354 return dwMHz * 1000000;
355#else
356#error Unsupported platform
357#endif
358 }
359
364 static bool
366 std::pair<int, int> cores = TotalCores();
367 return (cores.first != cores.second);
368 }
369};
370
371} // namespace qb
372
373#ifdef __SSE2__
374#include <emmintrin.h>
375namespace qb {
386inline void
387spin_loop_pause() noexcept {
388 _mm_pause();
389}
390} // namespace qb
391#elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86))
392#include <intrin.h>
393namespace qb {
399inline void
400spin_loop_pause() noexcept {
401 _mm_pause();
402}
403} // namespace qb
404#else
405namespace qb {
411inline void
412spin_loop_pause() noexcept {
413 std::this_thread::yield();
414}
415} // namespace qb
416#endif
417
418#endif // FEATURES_CPU_H
static std::string Architecture()
Gets the CPU architecture name/description.
Definition cpu.h:153
static bool HyperThreading()
Checks if hyperthreading is enabled.
Definition cpu.h:365
static int Affinity()
Gets the number of logical processors available to the process.
Definition cpu.h:202
static std::pair< int, int > TotalCores()
Gets both logical and physical core counts.
Definition cpu.h:245
static int LogicalCores()
Gets the number of logical CPU cores.
Definition cpu.h:227
static int PhysicalCores()
Gets the number of physical CPU cores.
Definition cpu.h:236
static int64_t ClockSpeed()
Gets the CPU clock speed in Hz.
Definition cpu.h:316
auto resource(T handle, TCleaner cleaner)
Creates a unique_ptr with a custom deleter for a resource.
Definition cpu.h:94
void spin_loop_pause() noexcept
Fallback implementation of spin_loop_pause for platforms without CPU pause.
Definition cpu.h:412
Internal helper functions for CPU information.