CppBenchmark  1.0.4.0
C++ Benchmark Library
system.cpp
Go to the documentation of this file.
1 
9 #include "benchmark/system.h"
10 
11 #if defined(__APPLE__)
12 #include <mach/mach.h>
13 #include <mach/mach_time.h>
14 #include <sys/sysctl.h>
15 #include <math.h>
16 #include <pthread.h>
17 #elif defined(unix) || defined(__unix) || defined(__unix__)
18 #include <pthread.h>
19 #include <unistd.h>
20 #include <fstream>
21 #include <regex>
22 #endif
23 #if defined(_WIN32) || defined(_WIN64)
24 #include <windows.h>
25 #include <memory>
26 #endif
27 
28 namespace CppBenchmark {
29 
31 namespace Internals {
32 
33 #if defined(__APPLE__)
34 
35 uint32_t CeilLog2(uint32_t x)
36 {
37  uint32_t result = 0;
38 
39  --x;
40  while (x > 0)
41  {
42  ++result;
43  x >>= 1;
44  }
45 
46  return result;
47 }
48 
49 // This function returns the rational number inside the given interval with
50 // the smallest denominator (and smallest numerator breaks ties; correctness
51 // proof neglects floating-point errors).
52 mach_timebase_info_data_t BestFrac(double a, double b)
53 {
54  if (floor(a) < floor(b))
55  {
56  mach_timebase_info_data_t rv = { (uint32_t)ceil(a), 1 };
57  return rv;
58  }
59 
60  double m = floor(a);
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 };
63  return rv;
64 }
65 
66 // This is just less than the smallest thing we can multiply numer by without
67 // overflowing. CeilLog2(numer) = 64 - number of leading zeros of numer
68 uint64_t GetExpressibleSpan(uint32_t numer, uint32_t denom)
69 {
70  uint64_t maxDiffWithoutOverflow = ((uint64_t)1 << (64 - CeilLog2(numer))) - 1;
71  return maxDiffWithoutOverflow * numer / denom;
72 }
73 
74 // The clock may run up to 0.1% faster or slower than the "exact" tick count.
75 // However, although the bound on the error is the same as for the pragmatic
76 // answer, the error is actually minimized over the given accuracy bound.
77 uint64_t PrepareTimebaseInfo(mach_timebase_info_data_t& tb)
78 {
79  tb.numer = 0;
80  tb.denom = 1;
81 
82  kern_return_t mtiStatus = mach_timebase_info(&tb);
83  if (mtiStatus != KERN_SUCCESS)
84  return 0;
85 
86  double frac = (double)tb.numer / tb.denom;
87  uint64_t spanTarget = 315360000000000000llu;
88  if (GetExpressibleSpan(tb.numer, tb.denom) >= spanTarget)
89  return 0;
90 
91  for (double errorTarget = 1 / 1024.0; errorTarget > 0.000001;)
92  {
93  mach_timebase_info_data_t newFrac = BestFrac((1 - errorTarget) * frac, (1 + errorTarget) * frac);
94  if (GetExpressibleSpan(newFrac.numer, newFrac.denom) < spanTarget)
95  break;
96  tb = newFrac;
97  errorTarget = fabs((double)tb.numer / tb.denom - frac) / frac / 8;
98  }
99 
100  return 0;
101 }
102 
103 #endif
104 
105 #if defined(_WIN32) || defined(_WIN64)
106 
107 // Helper function to count set bits in the processor mask
108 DWORD CountSetBits(ULONG_PTR pBitMask)
109 {
110  DWORD dwLeftShift = sizeof(ULONG_PTR) * 8 - 1;
111  DWORD dwBitSetCount = 0;
112  ULONG_PTR pBitTest = (ULONG_PTR)1 << dwLeftShift;
113 
114  for (DWORD i = 0; i <= dwLeftShift; ++i)
115  {
116  dwBitSetCount += ((pBitMask & pBitTest) ? 1 : 0);
117  pBitTest /= 2;
118  }
119 
120  return dwBitSetCount;
121 }
122 
123 #endif
124 
125 } // namespace Internals
127 
129 {
130 #if defined(__APPLE__)
131  char result[1024];
132  size_t size = sizeof(result);
133  if (sysctlbyname("machdep.cpu.brand_string", result, &size, nullptr, 0) == 0)
134  return result;
135 
136  return "<unknown>";
137 #elif defined(unix) || defined(__unix) || defined(__unix__)
138  static std::regex pattern("model name(.*): (.*)");
139 
140  std::string line;
141  std::ifstream stream("/proc/cpuinfo");
142  while (getline(stream, line))
143  {
144  std::smatch matches;
145  if (std::regex_match(line, matches, pattern))
146  return matches[2];
147  }
148 
149  return "<unknown>";
150 #elif defined(_WIN32) || defined(_WIN64)
151  HKEY hKeyProcessor;
152  LONG lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKeyProcessor);
153  if (lError != ERROR_SUCCESS)
154  return "<unknown>";
155 
156  // Smart resource cleaner pattern
157  auto clearer = [](HKEY hKey) { RegCloseKey(hKey); };
158  auto key = std::unique_ptr<std::remove_pointer<HKEY>::type, decltype(clearer)>(hKeyProcessor, clearer);
159 
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)
164  return "<unknown>";
165 
166  return std::string(pBuffer);
167 #else
168  #error Unsupported platform
169 #endif
170 }
171 
173 {
174  return CpuTotalCores().first;
175 }
176 
178 {
179  return CpuTotalCores().second;
180 }
181 
182 std::pair<int, int> System::CpuTotalCores()
183 {
184 #if defined(__APPLE__)
185  int logical = 0;
186  size_t logical_size = sizeof(logical);
187  if (sysctlbyname("hw.logicalcpu", &logical, &logical_size, nullptr, 0) != 0)
188  logical = -1;
189 
190  int physical = 0;
191  size_t physical_size = sizeof(physical);
192  if (sysctlbyname("hw.physicalcpu", &physical, &physical_size, nullptr, 0) != 0)
193  physical = -1;
194 
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;
202  DWORD dwLength = 0;
203 
204  while (!allocated)
205  {
206  BOOL bResult = GetLogicalProcessorInformation(pBuffer, &dwLength);
207  if (bResult == FALSE)
208  {
209  if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
210  {
211  if (pBuffer != nullptr)
212  std::free(pBuffer);
213  pBuffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)std::malloc(dwLength);
214  if (pBuffer == nullptr)
215  return std::make_pair(-1, -1);
216  }
217  else
218  return std::make_pair(-1, -1);
219  }
220  else
221  allocated = TRUE;
222  }
223 
224  std::pair<int, int> result(0, 0);
225  PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pCurrent = pBuffer;
226  DWORD dwOffset = 0;
227 
228  while (dwOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= dwLength)
229  {
230  switch (pCurrent->Relationship)
231  {
232  case RelationProcessorCore:
233  result.first += Internals::CountSetBits(pCurrent->ProcessorMask);
234  result.second += 1;
235  break;
236  case RelationNumaNode:
237  case RelationCache:
238  case RelationProcessorPackage:
239  break;
240  default:
241  return std::make_pair(-1, -1);
242  }
243  dwOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
244  pCurrent++;
245  }
246 
247  std::free(pBuffer);
248 
249  return result;
250 #else
251  #error Unsupported platform
252 #endif
253 }
254 
256 {
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)
261  return frequency;
262 
263  return -1;
264 #elif defined(unix) || defined(__unix) || defined(__unix__)
265  static std::regex pattern("cpu MHz(.*): (.*)");
266 
267  std::string line;
268  std::ifstream stream("/proc/cpuinfo");
269  while (getline(stream, line))
270  {
271  std::smatch matches;
272  if (std::regex_match(line, matches, pattern))
273  return (int64_t)(atof(matches[2].str().c_str()) * 1000000);
274  }
275 
276  return -1;
277 #elif defined(_WIN32) || defined(_WIN64)
278  HKEY hKeyProcessor;
279  long lError = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKeyProcessor);
280  if (lError != ERROR_SUCCESS)
281  return -1;
282 
283  // Smart resource cleaner pattern
284  auto clearer = [](HKEY hKey) { RegCloseKey(hKey); };
285  auto key = std::unique_ptr<std::remove_pointer<HKEY>::type, decltype(clearer)>(hKeyProcessor, clearer);
286 
287  DWORD dwMHz = 0;
288  DWORD dwBufferSize = sizeof(DWORD);
289  lError = RegQueryValueExA(key.get(), "~MHz", nullptr, nullptr, (LPBYTE)&dwMHz, &dwBufferSize);
290  if (lError != ERROR_SUCCESS)
291  return -1;
292 
293  return dwMHz * 1000000;
294 #else
295  #error Unsupported platform
296 #endif
297 }
298 
300 {
301  std::pair<int, int> cores = CpuTotalCores();
302  return (cores.first != cores.second);
303 }
304 
306 {
307 #if defined(__APPLE__)
308  int64_t memsize = 0;
309  size_t size = sizeof(memsize);
310  if (sysctlbyname("hw.memsize", &memsize, &size, nullptr, 0) == 0)
311  return memsize;
312 
313  return -1;
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;
319 
320  return -1;
321 #elif defined(_WIN32) || defined(_WIN64)
322  MEMORYSTATUSEX status;
323  status.dwLength = sizeof(status);
324  GlobalMemoryStatusEx(&status);
325  return status.ullTotalPhys;
326 #else
327  #error Unsupported platform
328 #endif
329 }
330 
332 {
333 #if defined(__APPLE__)
334  mach_port_t host_port = mach_host_self();
335  if (host_port == MACH_PORT_NULL)
336  return -1;
337 
338  vm_size_t page_size = 0;
339  host_page_size(host_port, &page_size);
340 
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)
345  return -1;
346 
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;
349  return free_mem;
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;
355 
356  return -1;
357 #elif defined(_WIN32) || defined(_WIN64)
358  MEMORYSTATUSEX status;
359  status.dwLength = sizeof(status);
360  GlobalMemoryStatusEx(&status);
361  return status.ullAvailPhys;
362 #else
363  #error Unsupported platform
364 #endif
365 }
366 
368 {
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();
373 #else
374  #error Unsupported platform
375 #endif
376 }
377 
379 {
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, &timestamp);
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;
394 
395  if (!initialized)
396  {
397  // Calculate timestamp offset
398  FILETIME timestamp;
399  GetSystemTimePreciseAsFileTime(&timestamp);
400 
401  ULARGE_INTEGER result;
402  result.LowPart = timestamp.dwLowDateTime;
403  result.HighPart = timestamp.dwHighDateTime;
404 
405  // Convert 01.01.1601 to 01.01.1970
406  result.QuadPart -= 116444736000000000ll;
407  offset = result.QuadPart * 100;
408 
409  // Setup performance counter
410  qpc = QueryPerformanceFrequency(&frequency) && QueryPerformanceCounter(&first);
411 
412  initialized = true;
413  }
414 
415  if (qpc)
416  {
417  LARGE_INTEGER timestamp = { 0 };
418  QueryPerformanceCounter(&timestamp);
419  timestamp.QuadPart -= first.QuadPart;
420  return offset + MulDiv64(timestamp.QuadPart, 1000000000, frequency.QuadPart);
421  }
422  else
423  return offset;
424 #else
425  #error Unsupported platform
426 #endif
427 }
428 
429 uint64_t System::MulDiv64(uint64_t operant, uint64_t multiplier, uint64_t divider)
430 {
431 #if defined(__GNUC__) && defined(__SIZEOF_INT128__)
432  __uint128_t a = operant;
433  __uint128_t b = multiplier;
434  __uint128_t c = divider;
435 
436  return (uint64_t)(a * b / c);
437 #elif defined(_MSC_VER)
438 #if defined(_M_IX86)
439  // Declare 128bit storage
440  struct
441  {
442  unsigned long DW[4];
443  } var128, quotient;
444 
445  // Change semantics for intermediate results for Full Div by renaming the vars
446  #define REMAINDER quotient
447  #define QUOTIENT edi
448 
449  // Save combined sign on stack
450  _asm
451  {
452  mov eax, dword ptr[operant+4]
453  xor eax, dword ptr[multiplier+4]
454  xor eax, dword ptr[divider+4]
455  pushfd
456  }
457 
458  _asm
459  {
460  // First check divider for 0
461  mov eax, dword ptr[divider+4]
462  or eax, dword ptr[divider]
463  jnz dividerOK
464  div eax
465 dividerOK:
466  lea edi,[var128] // edi = &var128
467  // Check multiplier for 1 or 0
468  xor eax, eax
469  cmp eax, dword ptr[multiplier+4]
470  jnz startMUL
471  cmp eax, dword ptr[multiplier]
472  jnz multiNotNUL
473  xor edx, edx
474  popfd // cleanup stack
475  jmp done
476 multiNotNUL:
477  // Set result HI part to 0
478  xor eax,eax
479  mov dword ptr[edi+12], eax
480  mov dword ptr[edi+8], eax
481  mov eax, 1
482  cmp eax, dword ptr[multiplier]
483  jnz smallMUL
484  // Multiplier is 1 so just copy operant to result
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
489  jmp startDIV
490 smallMUL:
491  // Test for 32/32 bit multiplication
492  xor eax, eax
493  mov ecx, dword ptr[operant+4]
494  or ecx, eax ;test for both hiwords zero.
495  jnz startMUL
496  // Do 32/32 bit multiplication
497  mov ecx, dword ptr[multiplier]
498  mov eax, dword ptr[operant]
499  mul ecx
500  mov dword ptr[edi+4], edx
501  mov dword ptr[edi], eax
502  jmp startDIV
503 startMUL:
504  // Check signs
505  // Multiply: var128 = operant * multiplier
506  mov eax, dword ptr[multiplier] // eax = LO(multiplier)
507  mul dword ptr[operant] // edx:eax = eax * LO(operant)
508  mov dword ptr[edi], eax // var128.DW0 = eax
509  mov ecx, edx // ecx = edx
510 
511  mov eax, dword ptr[multiplier] // eax = LO(multiplier)
512  mul dword ptr[operant+4] // edx:eax = eax * HI(operant)
513  add eax, ecx // eax = eax + ecx
514  adc edx, 0 // edx = edx + 0 + carry
515  mov ebx, eax
516  mov ecx, edx
517 
518  mov eax, dword ptr[multiplier+4]
519  mul dword ptr[operant]
520  add eax, ebx
521  mov dword ptr[edi+4], eax
522  adc ecx, edx
523  pushfd
524 
525  mov eax, dword ptr[multiplier+4]
526  mul dword ptr[operant+4]
527  popfd
528  adc eax, ecx
529  adc edx, 0
530  mov dword ptr[edi+8], eax
531  mov dword ptr[edi+12], edx
532 startDIV:
533  // Divide: var128 = var128 / divider
534  //
535  // Test divider = 32bit value
536  mov eax, dword ptr[divider+4]
537  cmp eax, 0
538  jnz fullDIV
539  mov ecx, dword ptr[divider]
540  cmp ecx, 1
541  jz applySign
542 
543  // Start 128/32 bit division
544  mov eax, dword ptr[edi+12]
545  xor edx, edx
546  div ecx
547  mov dword ptr[quotient+12], eax
548 
549  mov eax, dword ptr[edi+8]
550  div ecx
551  mov dword ptr[quotient+8], eax
552 
553  mov eax, dword ptr[edi+4]
554  div ecx
555  mov dword ptr[quotient+4], eax
556 
557  mov eax, dword ptr[edi]
558  div ecx
559  mov dword ptr[quotient], eax
560 
561  // Copy the quotient to the result storage (var128)
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
570  // To sign correction and return
571  jmp applySign
572 
573 fullDIV:
574  // Full 128/64 bit division
575  xor eax, 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
580 
581  mov ecx, 128
582 loop1:
583  // Compute REMAINDER:QUOTIENT = REMAINDER:QUOTIENT shl 1
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
592 
593  // Test (REMAINDER >= Divider)
594  xor eax, eax
595  cmp dword ptr[REMAINDER+12], eax
596  ja iftrue
597  jb iffalse
598 
599  cmp dword ptr[REMAINDER+8], eax
600  ja iftrue
601  jb iffalse
602 
603  mov eax, dword ptr[REMAINDER+4]
604  cmp eax, dword ptr[divider+4]
605  ja iftrue
606  jb iffalse
607 
608  mov eax, dword ptr[REMAINDER]
609  cmp eax, dword ptr[divider]
610  jb iffalse
611 iftrue:
612  // Remainder = remainder - 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
617  xor eax, eax
618  sbb dword ptr[REMAINDER+8], eax
619  sbb dword ptr[REMAINDER+12], eax
620  // Quotient = quotient +1
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
625 iffalse:
626  // Loop size = 101 bytes, is less than 127 so loop is possible
627  loop loop1
628 
629 applySign:
630  // Correct the sign of the result based on the stored combined sign
631  popfd
632  jns storeRes
633  not dword ptr[edi+12]
634  not dword ptr[edi+ 8]
635  not dword ptr[edi+ 4]
636  not dword ptr[edi]
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
641 
642 storeRES:
643  // Get low order qword from var128
644  mov edx, dword ptr[edi+4]
645  mov eax, dword ptr[edi]
646 done:
647  }
648  // result is returned in edx:eax
649 #elif defined (_M_X64 )
650 #pragma warning(push)
651 #pragma warning(disable: 4018) // C4018: 'expression' : signed/unsigned mismatch
652 #pragma warning(disable: 4244) // C4244: 'conversion' conversion from 'type1' to 'type2', possible loss of data
653 #pragma warning(disable: 4389) // C4389: 'operator' : signed/unsigned mismatch
654  uint64_t a = operant;
655  uint64_t b = multiplier;
656  uint64_t c = divider;
657 
658  // Normalize divisor
659  unsigned long shift;
660  _BitScanReverse64(&shift, c);
661  shift = 63 - shift;
662 
663  c <<= shift;
664 
665  // Multiply
666  a = _umul128(a, b, &b);
667  if (((b << shift) >> shift) != b)
668  {
669  // Overflow
670  return 0xFFFFFFFFFFFFFFFF;
671  }
672  b = __shiftleft128(a, b, shift);
673  a <<= shift;
674 
675  uint32_t div;
676  uint32_t q0, q1;
677  uint64_t t0, t1;
678 
679  // 1st Reduction
680  div = (uint32_t)(c >> 32);
681  t0 = b / div;
682  if (t0 > 0xFFFFFFFF)
683  t0 = 0xFFFFFFFF;
684  q1 = (uint32_t)t0;
685  while (1)
686  {
687  t0 = _umul128(c, (uint64_t)q1 << 32, &t1);
688  if (t1 < b || (t1 == b && t0 <= a))
689  break;
690  q1--;
691  }
692  b -= t1;
693  if (t0 > a)
694  b--;
695  a -= t0;
696 
697  if (b > 0xFFFFFFFF)
698  {
699  // Overflow
700  return 0xFFFFFFFFFFFFFFFF;
701  }
702 
703  // 2nd reduction
704  t0 = ((b << 32) | (a >> 32)) / div;
705  if (t0 > 0xFFFFFFFF)
706  t0 = 0xFFFFFFFF;
707  q0 = (uint32_t)t0;
708 
709  while (1)
710  {
711  t0 = _umul128(c, q0, &t1);
712  if (t1 < b || (t1 == b && t0 <= a))
713  break;
714  q0--;
715  }
716 
717  return ((uint64_t)q1 << 32) | q0;
718 #pragma warning(pop)
719 #endif
720 #else
721  #error MulDiv64 is no supported!
722 #endif
723 }
724 
725 } // namespace CppBenchmark
static std::pair< int, int > CpuTotalCores()
CPU total cores count.
Definition: system.cpp:182
static uint64_t Timestamp()
Get the current timestamp in nanoseconds.
Definition: system.cpp:378
static int CpuPhysicalCores()
CPU physical cores count.
Definition: system.cpp:177
static std::string CpuArchitecture()
CPU architecture string.
Definition: system.cpp:128
static uint64_t CurrentThreadId()
Current thread Id.
Definition: system.cpp:367
static int64_t RamFree()
Free RAM in bytes.
Definition: system.cpp:331
static int64_t CpuClockSpeed()
CPU clock speed in Hz.
Definition: system.cpp:255
static bool CpuHyperThreading()
Is CPU Hyper-Threading enabled?
Definition: system.cpp:299
static int64_t RamTotal()
Total RAM in bytes.
Definition: system.cpp:305
static uint64_t MulDiv64(uint64_t operant, uint64_t multiplier, uint64_t divider)
Calculate (operant * multiplier / divider) with 64-bit unsigned integer values.
Definition: system.cpp:429
static int CpuLogicalCores()
CPU logical cores count.
Definition: system.cpp:172
C++ Benchmark project definitions.
Definition: barrier.h:15
System management definition.