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