11 #if defined(__APPLE__)
12 #include <mach/mach.h>
13 #include <mach/mach_time.h>
14 #include <sys/sysctl.h>
17 #elif defined(unix) || defined(__unix) || defined(__unix__)
23 #if defined(_WIN32) || defined(_WIN64)
33 #if defined(__APPLE__)
35 uint32_t CeilLog2(uint32_t x)
52 mach_timebase_info_data_t BestFrac(
double a,
double b)
54 if (floor(a) < floor(b))
56 mach_timebase_info_data_t rv = { (uint32_t)ceil(a), 1 };
61 mach_timebase_info_data_t next = BestFrac(1 / (b - m), 1 / (a - m));
62 mach_timebase_info_data_t rv = { (int)m * next.numer + next.denom, next.numer };
68 uint64_t GetExpressibleSpan(uint32_t numer, uint32_t denom)
70 uint64_t maxDiffWithoutOverflow = ((uint64_t)1 << (64 - CeilLog2(numer))) - 1;
71 return maxDiffWithoutOverflow * numer / denom;
77 uint64_t PrepareTimebaseInfo(mach_timebase_info_data_t& tb)
82 kern_return_t mtiStatus = mach_timebase_info(&tb);
83 if (mtiStatus != KERN_SUCCESS)
86 double frac = (double)tb.numer / tb.denom;
87 uint64_t spanTarget = 315360000000000000llu;
88 if (GetExpressibleSpan(tb.numer, tb.denom) >= spanTarget)
91 for (
double errorTarget = 1 / 1024.0; errorTarget > 0.000001;)
93 mach_timebase_info_data_t newFrac = BestFrac((1 - errorTarget) * frac, (1 + errorTarget) * frac);
94 if (GetExpressibleSpan(newFrac.numer, newFrac.denom) < spanTarget)
97 errorTarget = fabs((
double)tb.numer / tb.denom - frac) / frac / 8;
105 #if defined(_WIN32) || defined(_WIN64)
108 DWORD CountSetBits(ULONG_PTR pBitMask)
110 DWORD dwLeftShift =
sizeof(ULONG_PTR) * 8 - 1;
111 DWORD dwBitSetCount = 0;
112 ULONG_PTR pBitTest = (ULONG_PTR)1 << dwLeftShift;
114 for (DWORD i = 0; i <= dwLeftShift; ++i)
116 dwBitSetCount += ((pBitMask & pBitTest) ? 1 : 0);
120 return dwBitSetCount;
130 #if defined(__APPLE__)
132 size_t size =
sizeof(result);
133 if (sysctlbyname(
"machdep.cpu.brand_string", result, &size,
nullptr, 0) == 0)
137 #elif defined(unix) || defined(__unix) || defined(__unix__)
138 static std::regex pattern(
"model name(.*): (.*)");
141 std::ifstream stream(
"/proc/cpuinfo");
142 while (getline(stream, line))
145 if (std::regex_match(line, matches, pattern))
150 #elif defined(_WIN32) || defined(_WIN64)
152 LONG lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKeyProcessor);
153 if (lError != ERROR_SUCCESS)
157 auto clearer = [](HKEY hKey) { RegCloseKey(hKey); };
158 auto key = std::unique_ptr<std::remove_pointer<HKEY>::type, decltype(clearer)>(hKeyProcessor, clearer);
160 CHAR pBuffer[_MAX_PATH] = { 0 };
161 DWORD dwBufferSize =
sizeof(pBuffer);
162 lError = RegQueryValueExA(key.get(),
"ProcessorNameString",
nullptr,
nullptr, (LPBYTE)pBuffer, &dwBufferSize);
163 if (lError != ERROR_SUCCESS)
166 return std::string(pBuffer);
168 #error Unsupported platform
184 #if defined(__APPLE__)
186 size_t logical_size =
sizeof(logical);
187 if (sysctlbyname(
"hw.logicalcpu", &logical, &logical_size,
nullptr, 0) != 0)
191 size_t physical_size =
sizeof(physical);
192 if (sysctlbyname(
"hw.physicalcpu", &physical, &physical_size,
nullptr, 0) != 0)
195 return std::make_pair(logical, physical);
196 #elif defined(unix) || defined(__unix) || defined(__unix__)
197 long processors = sysconf(_SC_NPROCESSORS_ONLN);
198 return std::make_pair(processors, processors);
199 #elif defined(_WIN32) || defined(_WIN64)
200 BOOL allocated = FALSE;
201 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pBuffer =
nullptr;
206 BOOL bResult = GetLogicalProcessorInformation(pBuffer, &dwLength);
207 if (bResult == FALSE)
209 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
211 if (pBuffer !=
nullptr)
213 pBuffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)std::malloc(dwLength);
214 if (pBuffer ==
nullptr)
215 return std::make_pair(-1, -1);
218 return std::make_pair(-1, -1);
224 std::pair<int, int> result(0, 0);
225 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pCurrent = pBuffer;
228 while (dwOffset +
sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= dwLength)
230 switch (pCurrent->Relationship)
232 case RelationProcessorCore:
233 result.first += Internals::CountSetBits(pCurrent->ProcessorMask);
236 case RelationNumaNode:
238 case RelationProcessorPackage:
241 return std::make_pair(-1, -1);
243 dwOffset +=
sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
251 #error Unsupported platform
257 #if defined(__APPLE__)
258 uint64_t frequency = 0;
259 size_t size =
sizeof(frequency);
260 if (sysctlbyname(
"hw.cpufrequency", &frequency, &size,
nullptr, 0) == 0)
264 #elif defined(unix) || defined(__unix) || defined(__unix__)
265 static std::regex pattern(
"cpu MHz(.*): (.*)");
268 std::ifstream stream(
"/proc/cpuinfo");
269 while (getline(stream, line))
272 if (std::regex_match(line, matches, pattern))
273 return (int64_t)(atof(matches[2].str().c_str()) * 1000000);
277 #elif defined(_WIN32) || defined(_WIN64)
279 long lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKeyProcessor);
280 if (lError != ERROR_SUCCESS)
284 auto clearer = [](HKEY hKey) { RegCloseKey(hKey); };
285 auto key = std::unique_ptr<std::remove_pointer<HKEY>::type, decltype(clearer)>(hKeyProcessor, clearer);
288 DWORD dwBufferSize =
sizeof(DWORD);
289 lError = RegQueryValueExA(key.get(),
"~MHz",
nullptr,
nullptr, (LPBYTE)&dwMHz, &dwBufferSize);
290 if (lError != ERROR_SUCCESS)
293 return dwMHz * 1000000;
295 #error Unsupported platform
302 return (cores.first != cores.second);
307 #if defined(__APPLE__)
309 size_t size =
sizeof(memsize);
310 if (sysctlbyname(
"hw.memsize", &memsize, &size,
nullptr, 0) == 0)
314 #elif defined(unix) || defined(__unix) || defined(__unix__)
315 int64_t pages = sysconf(_SC_PHYS_PAGES);
316 int64_t page_size = sysconf(_SC_PAGESIZE);
317 if ((pages > 0) && (page_size > 0))
318 return pages * page_size;
321 #elif defined(_WIN32) || defined(_WIN64)
322 MEMORYSTATUSEX status;
323 status.dwLength =
sizeof(status);
324 GlobalMemoryStatusEx(&status);
325 return status.ullTotalPhys;
327 #error Unsupported platform
333 #if defined(__APPLE__)
334 mach_port_t host_port = mach_host_self();
335 if (host_port == MACH_PORT_NULL)
338 vm_size_t page_size = 0;
339 host_page_size(host_port, &page_size);
341 vm_statistics_data_t vmstat;
342 mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
343 kern_return_t kernReturn = host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vmstat, &count);
344 if (kernReturn != KERN_SUCCESS)
347 [[maybe_unused]] int64_t used_mem = (vmstat.active_count + vmstat.inactive_count + vmstat.wire_count) * page_size;
348 int64_t free_mem = vmstat.free_count * page_size;
350 #elif defined(unix) || defined(__unix) || defined(__unix__)
351 int64_t pages = sysconf(_SC_AVPHYS_PAGES);
352 int64_t page_size = sysconf(_SC_PAGESIZE);
353 if ((pages > 0) && (page_size > 0))
354 return pages * page_size;
357 #elif defined(_WIN32) || defined(_WIN64)
358 MEMORYSTATUSEX status;
359 status.dwLength =
sizeof(status);
360 GlobalMemoryStatusEx(&status);
361 return status.ullAvailPhys;
363 #error Unsupported platform
369 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
370 return (uint64_t)pthread_self();
371 #elif defined(_WIN32) || defined(_WIN64)
372 return GetCurrentThreadId();
374 #error Unsupported platform
380 #if defined(__APPLE__)
381 static mach_timebase_info_data_t info;
382 static uint64_t bias = Internals::PrepareTimebaseInfo(info);
383 return ((mach_absolute_time() - bias) * info.numer) / info.denom;
384 #elif defined(unix) || defined(__unix) || defined(__unix__)
385 struct timespec timestamp = { 0 };
386 clock_gettime(CLOCK_MONOTONIC, ×tamp);
387 return (timestamp.tv_sec * 1000000000) + timestamp.tv_nsec;
388 #elif defined(_WIN32) || defined(_WIN64)
389 static uint64_t offset = 0;
390 static LARGE_INTEGER first = { 0 };
391 static LARGE_INTEGER frequency = { 0 };
392 static bool initialized =
false;
393 static bool qpc =
true;
399 GetSystemTimePreciseAsFileTime(×tamp);
401 ULARGE_INTEGER result;
402 result.LowPart = timestamp.dwLowDateTime;
403 result.HighPart = timestamp.dwHighDateTime;
406 result.QuadPart -= 116444736000000000ll;
407 offset = result.QuadPart * 100;
410 qpc = QueryPerformanceFrequency(&frequency) && QueryPerformanceCounter(&first);
417 LARGE_INTEGER timestamp = { 0 };
418 QueryPerformanceCounter(×tamp);
419 timestamp.QuadPart -= first.QuadPart;
420 return offset +
MulDiv64(timestamp.QuadPart, 1000000000, frequency.QuadPart);
425 #error Unsupported platform
431 #if defined(__GNUC__) && defined(__SIZEOF_INT128__)
432 __uint128_t a = operant;
433 __uint128_t b = multiplier;
434 __uint128_t c = divider;
436 return (uint64_t)(a * b / c);
437 #elif defined(_MSC_VER)
446 #define REMAINDER quotient
452 mov eax, dword ptr[operant+4]
453 xor eax, dword ptr[multiplier+4]
454 xor eax, dword ptr[divider+4]
461 mov eax, dword ptr[divider+4]
462 or eax, dword ptr[divider]
469 cmp eax, dword ptr[multiplier+4]
471 cmp eax, dword ptr[multiplier]
479 mov dword ptr[edi+12], eax
480 mov dword ptr[edi+8], eax
482 cmp eax, dword ptr[multiplier]
485 mov eax, dword ptr[operant+4]
486 mov dword ptr[edi+4], eax
487 mov eax, dword ptr[operant]
488 mov dword ptr[edi], eax
493 mov ecx, dword ptr[operant+4]
494 or ecx, eax ;test
for both hiwords zero.
497 mov ecx, dword ptr[multiplier]
498 mov eax, dword ptr[operant]
500 mov dword ptr[edi+4], edx
501 mov dword ptr[edi], eax
506 mov eax, dword ptr[multiplier]
507 mul dword ptr[operant]
508 mov dword ptr[edi], eax
511 mov eax, dword ptr[multiplier]
512 mul dword ptr[operant+4]
518 mov eax, dword ptr[multiplier+4]
519 mul dword ptr[operant]
521 mov dword ptr[edi+4], eax
525 mov eax, dword ptr[multiplier+4]
526 mul dword ptr[operant+4]
530 mov dword ptr[edi+8], eax
531 mov dword ptr[edi+12], edx
536 mov eax, dword ptr[divider+4]
539 mov ecx, dword ptr[divider]
544 mov eax, dword ptr[edi+12]
547 mov dword ptr[quotient+12], eax
549 mov eax, dword ptr[edi+8]
551 mov dword ptr[quotient+8], eax
553 mov eax, dword ptr[edi+4]
555 mov dword ptr[quotient+4], eax
557 mov eax, dword ptr[edi]
559 mov dword ptr[quotient], eax
562 mov eax, dword ptr[quotient+12]
563 mov dword ptr[edi+12], eax
564 mov eax, dword ptr[quotient+8]
565 mov dword ptr[edi+8], eax
566 mov eax, dword ptr[quotient+4]
567 mov dword ptr[edi+4], eax
568 mov eax, dword ptr[quotient]
569 mov dword ptr[edi], eax
576 mov dword ptr[REMAINDER+12], eax
577 mov dword ptr[REMAINDER+8], eax
578 mov dword ptr[REMAINDER+4], eax
579 mov dword ptr[REMAINDER], eax
584 shl dword ptr[QUOTIENT], 1
585 rcl dword ptr[QUOTIENT+4], 1
586 rcl dword ptr[QUOTIENT+8], 1
587 rcl dword ptr[QUOTIENT+12], 1
588 rcl dword ptr[REMAINDER], 1
589 rcl dword ptr[REMAINDER+4], 1
590 rcl dword ptr[REMAINDER+8], 1
591 rcl dword ptr[REMAINDER+12], 1
595 cmp dword ptr[REMAINDER+12], eax
599 cmp dword ptr[REMAINDER+8], eax
603 mov eax, dword ptr[REMAINDER+4]
604 cmp eax, dword ptr[divider+4]
608 mov eax, dword ptr[REMAINDER]
609 cmp eax, dword ptr[divider]
613 mov eax, dword ptr[divider]
614 sub dword ptr[REMAINDER], eax
615 mov eax, dword ptr[divider+4]
616 sbb dword ptr[REMAINDER+4], eax
618 sbb dword ptr[REMAINDER+8], eax
619 sbb dword ptr[REMAINDER+12], eax
621 add dword ptr[QUOTIENT], 1
622 adc dword ptr[QUOTIENT+4], 0
623 adc dword ptr[QUOTIENT+8], 0
624 adc dword ptr[QUOTIENT+12], 0
633 not dword ptr[edi+12]
634 not dword ptr[edi+ 8]
635 not dword ptr[edi+ 4]
637 add dword ptr[edi], 1
638 adc dword ptr[edi+ 4], 0
639 adc dword ptr[edi+ 8], 0
640 adc dword ptr[edi+12], 0
644 mov edx, dword ptr[edi+4]
645 mov eax, dword ptr[edi]
649 #elif defined (_M_X64 )
650 #pragma warning(push)
651 #pragma warning(disable: 4018)
652 #pragma warning(disable: 4244)
653 #pragma warning(disable: 4389)
654 uint64_t a = operant;
655 uint64_t b = multiplier;
656 uint64_t c = divider;
660 _BitScanReverse64(&shift, c);
666 a = _umul128(a, b, &b);
667 if (((b << shift) >> shift) != b)
670 return 0xFFFFFFFFFFFFFFFF;
672 b = __shiftleft128(a, b, shift);
680 div = (uint32_t)(c >> 32);
687 t0 = _umul128(c, (uint64_t)q1 << 32, &t1);
688 if (t1 < b || (t1 == b && t0 <= a))
700 return 0xFFFFFFFFFFFFFFFF;
704 t0 = ((b << 32) | (a >> 32)) / div;
711 t0 = _umul128(c, q0, &t1);
712 if (t1 < b || (t1 == b && t0 <= a))
717 return ((uint64_t)q1 << 32) | q0;
721 #error MulDiv64 is no supported!
static std::pair< int, int > CpuTotalCores()
CPU total cores count.
static uint64_t Timestamp()
Get the current timestamp in nanoseconds.
static int CpuPhysicalCores()
CPU physical cores count.
static std::string CpuArchitecture()
CPU architecture string.
static uint64_t CurrentThreadId()
Current thread Id.
static int64_t RamFree()
Free RAM in bytes.
static int64_t CpuClockSpeed()
CPU clock speed in Hz.
static bool CpuHyperThreading()
Is CPU Hyper-Threading enabled?
static int64_t RamTotal()
Total RAM in bytes.
static uint64_t MulDiv64(uint64_t operant, uint64_t multiplier, uint64_t divider)
Calculate (operant * multiplier / divider) with 64-bit unsigned integer values.
static int CpuLogicalCores()
CPU logical cores count.
C++ Benchmark project definitions.
System management definition.