1 // Copyright 2015 Google Inc. All rights reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
16 // FIXME: This must be defined before any other includes to disable deprecation
17 // warnings for use of codecvt from C++17. We should remove our reliance on
18 // the deprecated functionality instead.
19 #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
22 #include "internal_macros.h"
24 #ifdef BENCHMARK_OS_WINDOWS
26 #undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
27 #include <versionhelpers.h>
33 #ifndef BENCHMARK_OS_FUCHSIA
34 #include <sys/resource.h>
37 #include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
39 #if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX || \
40 defined BENCHMARK_OS_NETBSD || defined BENCHMARK_OS_OPENBSD || \
41 defined BENCHMARK_OS_DRAGONFLY
42 #define BENCHMARK_HAS_SYSCTL
43 #include <sys/sysctl.h>
46 #if defined(BENCHMARK_OS_SOLARIS)
49 #if defined(BENCHMARK_OS_QNX)
50 #include <sys/syspage.h>
72 #include "cycleclock.h"
73 #include "internal_macros.h"
76 #include "string_util.h"
81 void PrintImp(std::ostream
& out
) { out
<< std::endl
; }
83 template <class First
, class... Rest
>
84 void PrintImp(std::ostream
& out
, First
&& f
, Rest
&&... rest
) {
85 out
<< std::forward
<First
>(f
);
86 PrintImp(out
, std::forward
<Rest
>(rest
)...);
89 template <class... Args
>
90 BENCHMARK_NORETURN
void PrintErrorAndDie(Args
&&... args
) {
91 PrintImp(std::cerr
, std::forward
<Args
>(args
)...);
92 std::exit(EXIT_FAILURE
);
95 #ifdef BENCHMARK_HAS_SYSCTL
97 /// ValueUnion - A type used to correctly alias the byte-for-byte output of
98 /// `sysctl` with the result type it's to be interpreted as.
101 uint32_t uint32_value
;
102 uint64_t uint64_value
;
103 // For correct aliasing of union members from bytes.
106 using DataPtr
= std::unique_ptr
<DataT
, decltype(&std::free
)>;
108 // The size of the data union member + its trailing array size.
113 ValueUnion() : Size(0), Buff(nullptr, &std::free
) {}
115 explicit ValueUnion(size_t BuffSize
)
116 : Size(sizeof(DataT
) + BuffSize
),
117 Buff(::new (std::malloc(Size
)) DataT(), &std::free
) {}
119 ValueUnion(ValueUnion
&& other
) = default;
121 explicit operator bool() const { return bool(Buff
); }
123 char* data() const { return Buff
->bytes
; }
125 std::string
GetAsString() const { return std::string(data()); }
127 int64_t GetAsInteger() const {
128 if (Size
== sizeof(Buff
->uint32_value
))
129 return static_cast<int32_t>(Buff
->uint32_value
);
130 else if (Size
== sizeof(Buff
->uint64_value
))
131 return static_cast<int64_t>(Buff
->uint64_value
);
132 BENCHMARK_UNREACHABLE();
135 uint64_t GetAsUnsigned() const {
136 if (Size
== sizeof(Buff
->uint32_value
))
137 return Buff
->uint32_value
;
138 else if (Size
== sizeof(Buff
->uint64_value
))
139 return Buff
->uint64_value
;
140 BENCHMARK_UNREACHABLE();
143 template <class T
, int N
>
144 std::array
<T
, N
> GetAsArray() {
145 const int ArrSize
= sizeof(T
) * N
;
146 BM_CHECK_LE(ArrSize
, Size
);
147 std::array
<T
, N
> Arr
;
148 std::memcpy(Arr
.data(), data(), ArrSize
);
153 ValueUnion
GetSysctlImp(std::string
const& Name
) {
154 #if defined BENCHMARK_OS_OPENBSD
158 if ((Name
== "hw.ncpu") || (Name
== "hw.cpuspeed")) {
159 ValueUnion
buff(sizeof(int));
161 if (Name
== "hw.ncpu") {
164 mib
[1] = HW_CPUSPEED
;
167 if (sysctl(mib
, 2, buff
.data(), &buff
.Size
, nullptr, 0) == -1) {
174 size_t CurBuffSize
= 0;
175 if (sysctlbyname(Name
.c_str(), nullptr, &CurBuffSize
, nullptr, 0) == -1)
178 ValueUnion
buff(CurBuffSize
);
179 if (sysctlbyname(Name
.c_str(), buff
.data(), &buff
.Size
, nullptr, 0) == 0)
185 BENCHMARK_MAYBE_UNUSED
186 bool GetSysctl(std::string
const& Name
, std::string
* Out
) {
188 auto Buff
= GetSysctlImp(Name
);
189 if (!Buff
) return false;
190 Out
->assign(Buff
.data());
195 class = typename
std::enable_if
<std::is_integral
<Tp
>::value
>::type
>
196 bool GetSysctl(std::string
const& Name
, Tp
* Out
) {
198 auto Buff
= GetSysctlImp(Name
);
199 if (!Buff
) return false;
200 *Out
= static_cast<Tp
>(Buff
.GetAsUnsigned());
204 template <class Tp
, size_t N
>
205 bool GetSysctl(std::string
const& Name
, std::array
<Tp
, N
>* Out
) {
206 auto Buff
= GetSysctlImp(Name
);
207 if (!Buff
) return false;
208 *Out
= Buff
.GetAsArray
<Tp
, N
>();
213 template <class ArgT
>
214 bool ReadFromFile(std::string
const& fname
, ArgT
* arg
) {
216 std::ifstream
f(fname
.c_str());
217 if (!f
.is_open()) return false;
222 CPUInfo::Scaling
CpuScaling(int num_cpus
) {
223 // We don't have a valid CPU count, so don't even bother.
224 if (num_cpus
<= 0) return CPUInfo::Scaling::UNKNOWN
;
225 #if defined(BENCHMARK_OS_QNX)
226 return CPUInfo::Scaling::UNKNOWN
;
227 #elif !defined(BENCHMARK_OS_WINDOWS)
228 // On Linux, the CPUfreq subsystem exposes CPU information as files on the
229 // local file system. If reading the exported files fails, then we may not be
230 // running on Linux, so we silently ignore all the read errors.
232 for (int cpu
= 0; cpu
< num_cpus
; ++cpu
) {
233 std::string governor_file
=
234 StrCat("/sys/devices/system/cpu/cpu", cpu
, "/cpufreq/scaling_governor");
235 if (ReadFromFile(governor_file
, &res
) && res
!= "performance")
236 return CPUInfo::Scaling::ENABLED
;
238 return CPUInfo::Scaling::DISABLED
;
240 return CPUInfo::Scaling::UNKNOWN
;
244 int CountSetBitsInCPUMap(std::string Val
) {
245 auto CountBits
= [](std::string Part
) {
246 using CPUMask
= std::bitset
<sizeof(std::uintptr_t) * CHAR_BIT
>;
248 CPUMask
Mask(benchmark::stoul(Part
, nullptr, 16));
249 return static_cast<int>(Mask
.count());
253 while ((Pos
= Val
.find(',')) != std::string::npos
) {
254 total
+= CountBits(Val
.substr(0, Pos
));
255 Val
= Val
.substr(Pos
+ 1);
258 total
+= CountBits(Val
);
263 BENCHMARK_MAYBE_UNUSED
264 std::vector
<CPUInfo::CacheInfo
> GetCacheSizesFromKVFS() {
265 std::vector
<CPUInfo::CacheInfo
> res
;
266 std::string dir
= "/sys/devices/system/cpu/cpu0/cache/";
269 CPUInfo::CacheInfo info
;
270 std::string FPath
= StrCat(dir
, "index", Idx
++, "/");
271 std::ifstream
f(StrCat(FPath
, "size").c_str());
272 if (!f
.is_open()) break;
276 PrintErrorAndDie("Failed while reading file '", FPath
, "size'");
281 "Invalid cache size format: failed to read size suffix");
282 else if (f
&& suffix
!= "K")
283 PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix
);
284 else if (suffix
== "K")
287 if (!ReadFromFile(StrCat(FPath
, "type"), &info
.type
))
288 PrintErrorAndDie("Failed to read from file ", FPath
, "type");
289 if (!ReadFromFile(StrCat(FPath
, "level"), &info
.level
))
290 PrintErrorAndDie("Failed to read from file ", FPath
, "level");
292 if (!ReadFromFile(StrCat(FPath
, "shared_cpu_map"), &map_str
))
293 PrintErrorAndDie("Failed to read from file ", FPath
, "shared_cpu_map");
294 info
.num_sharing
= CountSetBitsInCPUMap(map_str
);
301 #ifdef BENCHMARK_OS_MACOSX
302 std::vector
<CPUInfo::CacheInfo
> GetCacheSizesMacOSX() {
303 std::vector
<CPUInfo::CacheInfo
> res
;
304 std::array
<uint64_t, 4> CacheCounts
{{0, 0, 0, 0}};
305 GetSysctl("hw.cacheconfig", &CacheCounts
);
311 uint64_t num_sharing
;
312 } Cases
[] = {{"hw.l1dcachesize", "Data", 1, CacheCounts
[1]},
313 {"hw.l1icachesize", "Instruction", 1, CacheCounts
[1]},
314 {"hw.l2cachesize", "Unified", 2, CacheCounts
[2]},
315 {"hw.l3cachesize", "Unified", 3, CacheCounts
[3]}};
316 for (auto& C
: Cases
) {
318 if (!GetSysctl(C
.name
, &val
)) continue;
319 CPUInfo::CacheInfo info
;
321 info
.level
= C
.level
;
323 info
.num_sharing
= static_cast<int>(C
.num_sharing
);
324 res
.push_back(std::move(info
));
328 #elif defined(BENCHMARK_OS_WINDOWS)
329 std::vector
<CPUInfo::CacheInfo
> GetCacheSizesWindows() {
330 std::vector
<CPUInfo::CacheInfo
> res
;
331 DWORD buffer_size
= 0;
332 using PInfo
= SYSTEM_LOGICAL_PROCESSOR_INFORMATION
;
333 using CInfo
= CACHE_DESCRIPTOR
;
335 using UPtr
= std::unique_ptr
<PInfo
, decltype(&std::free
)>;
336 GetLogicalProcessorInformation(nullptr, &buffer_size
);
337 UPtr
buff((PInfo
*)malloc(buffer_size
), &std::free
);
338 if (!GetLogicalProcessorInformation(buff
.get(), &buffer_size
))
339 PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ",
342 PInfo
* it
= buff
.get();
343 PInfo
* end
= buff
.get() + (buffer_size
/ sizeof(PInfo
));
345 for (; it
!= end
; ++it
) {
346 if (it
->Relationship
!= RelationCache
) continue;
347 using BitSet
= std::bitset
<sizeof(ULONG_PTR
) * CHAR_BIT
>;
348 BitSet
B(it
->ProcessorMask
);
349 // To prevent duplicates, only consider caches where CPU 0 is specified
350 if (!B
.test(0)) continue;
351 CInfo
* Cache
= &it
->Cache
;
352 CPUInfo::CacheInfo C
;
353 C
.num_sharing
= static_cast<int>(B
.count());
354 C
.level
= Cache
->Level
;
355 C
.size
= Cache
->Size
;
357 switch (Cache
->Type
) {
361 case CacheInstruction
:
362 C
.type
= "Instruction";
375 #elif BENCHMARK_OS_QNX
376 std::vector
<CPUInfo::CacheInfo
> GetCacheSizesQNX() {
377 std::vector
<CPUInfo::CacheInfo
> res
;
378 struct cacheattr_entry
* cache
= SYSPAGE_ENTRY(cacheattr
);
379 uint32_t const elsize
= SYSPAGE_ELEMENT_SIZE(cacheattr
);
380 int num
= SYSPAGE_ENTRY_SIZE(cacheattr
) / elsize
;
381 for (int i
= 0; i
< num
; ++i
) {
382 CPUInfo::CacheInfo info
;
383 switch (cache
->flags
) {
384 case CACHE_FLAG_INSTR
:
385 info
.type
= "Instruction";
388 case CACHE_FLAG_DATA
:
392 case CACHE_FLAG_UNIFIED
:
393 info
.type
= "Unified";
396 case CACHE_FLAG_SHARED
:
397 info
.type
= "Shared";
404 info
.size
= cache
->line_size
* cache
->num_lines
;
405 info
.num_sharing
= 0;
406 res
.push_back(std::move(info
));
407 cache
= SYSPAGE_ARRAY_ADJ_OFFSET(cacheattr
, cache
, elsize
);
413 std::vector
<CPUInfo::CacheInfo
> GetCacheSizes() {
414 #ifdef BENCHMARK_OS_MACOSX
415 return GetCacheSizesMacOSX();
416 #elif defined(BENCHMARK_OS_WINDOWS)
417 return GetCacheSizesWindows();
418 #elif defined(BENCHMARK_OS_QNX)
419 return GetCacheSizesQNX();
421 return GetCacheSizesFromKVFS();
425 std::string
GetSystemName() {
426 #if defined(BENCHMARK_OS_WINDOWS)
428 const unsigned COUNT
= MAX_COMPUTERNAME_LENGTH
+ 1;
429 TCHAR hostname
[COUNT
] = {'\0'};
430 DWORD DWCOUNT
= COUNT
;
431 if (!GetComputerName(hostname
, &DWCOUNT
)) return std::string("");
433 str
= std::string(hostname
, DWCOUNT
);
435 // Using wstring_convert, Is deprecated in C++17
436 using convert_type
= std::codecvt_utf8
<wchar_t>;
437 std::wstring_convert
<convert_type
, wchar_t> converter
;
438 std::wstring
wStr(hostname
, DWCOUNT
);
439 str
= converter
.to_bytes(wStr
);
442 #else // defined(BENCHMARK_OS_WINDOWS)
443 #ifndef HOST_NAME_MAX
444 #ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac Doesnt have HOST_NAME_MAX defined
445 #define HOST_NAME_MAX 64
446 #elif defined(BENCHMARK_OS_NACL)
447 #define HOST_NAME_MAX 64
448 #elif defined(BENCHMARK_OS_QNX)
449 #define HOST_NAME_MAX 154
450 #elif defined(BENCHMARK_OS_RTEMS)
451 #define HOST_NAME_MAX 256
453 #pragma message("HOST_NAME_MAX not defined. using 64")
454 #define HOST_NAME_MAX 64
456 #endif // def HOST_NAME_MAX
457 char hostname
[HOST_NAME_MAX
];
458 int retVal
= gethostname(hostname
, HOST_NAME_MAX
);
459 if (retVal
!= 0) return std::string("");
460 return std::string(hostname
);
461 #endif // Catch-all POSIX block.
465 #ifdef BENCHMARK_HAS_SYSCTL
467 if (GetSysctl("hw.ncpu", &NumCPU
)) return NumCPU
;
468 fprintf(stderr
, "Err: %s\n", strerror(errno
));
469 std::exit(EXIT_FAILURE
);
470 #elif defined(BENCHMARK_OS_WINDOWS)
472 // Use memset as opposed to = {} to avoid GCC missing initializer false
474 std::memset(&sysinfo
, 0, sizeof(SYSTEM_INFO
));
475 GetSystemInfo(&sysinfo
);
476 return sysinfo
.dwNumberOfProcessors
; // number of logical
477 // processors in the current
479 #elif defined(BENCHMARK_OS_SOLARIS)
480 // Returns -1 in case of a failure.
481 int NumCPU
= sysconf(_SC_NPROCESSORS_ONLN
);
483 fprintf(stderr
, "sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n",
487 #elif defined(BENCHMARK_OS_QNX)
488 return static_cast<int>(_syspage_ptr
->num_cpu
);
492 std::ifstream
f("/proc/cpuinfo");
494 std::cerr
<< "failed to open /proc/cpuinfo\n";
497 const std::string Key
= "processor";
499 while (std::getline(f
, ln
)) {
500 if (ln
.empty()) continue;
501 size_t SplitIdx
= ln
.find(':');
503 #if defined(__s390__)
504 // s390 has another format in /proc/cpuinfo
505 // it needs to be parsed differently
506 if (SplitIdx
!= std::string::npos
)
507 value
= ln
.substr(Key
.size() + 1, SplitIdx
- Key
.size() - 1);
509 if (SplitIdx
!= std::string::npos
) value
= ln
.substr(SplitIdx
+ 1);
511 if (ln
.size() >= Key
.size() && ln
.compare(0, Key
.size(), Key
) == 0) {
513 if (!value
.empty()) {
514 int CurID
= benchmark::stoi(value
);
515 MaxID
= std::max(CurID
, MaxID
);
520 std::cerr
<< "Failure reading /proc/cpuinfo\n";
524 std::cerr
<< "Failed to read to end of /proc/cpuinfo\n";
529 if ((MaxID
+ 1) != NumCPUs
) {
531 "CPU ID assignments in /proc/cpuinfo seem messed up."
532 " This is usually caused by a bad BIOS.\n");
536 BENCHMARK_UNREACHABLE();
539 double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling
) {
540 // Currently, scaling is only used on linux path here,
541 // suppress diagnostics about it being unused on other paths.
544 #if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
547 // If the kernel is exporting the tsc frequency use that. There are issues
548 // where cpuinfo_max_freq cannot be relied on because the BIOS may be
549 // exporintg an invalid p-state (on x86) or p-states may be used to put the
550 // processor in a new mode (turbo mode). Essentially, those frequencies
551 // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as
553 if (ReadFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq
)
554 // If CPU scaling is disabled, use the *current* frequency.
555 // Note that we specifically don't want to read cpuinfo_cur_freq,
556 // because it is only readable by root.
557 || (scaling
== CPUInfo::Scaling::DISABLED
&&
558 ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
560 // Otherwise, if CPU scaling may be in effect, we want to use
561 // the *maximum* frequency, not whatever CPU speed some random processor
562 // happens to be using now.
563 || ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
565 // The value is in kHz (as the file name suggests). For example, on a
566 // 2GHz warpstation, the file contains the value "2000000".
567 return freq
* 1000.0;
570 const double error_value
= -1;
571 double bogo_clock
= error_value
;
573 std::ifstream
f("/proc/cpuinfo");
575 std::cerr
<< "failed to open /proc/cpuinfo\n";
579 auto startsWithKey
= [](std::string
const& Value
, std::string
const& Key
) {
580 if (Key
.size() > Value
.size()) return false;
581 auto Cmp
= [&](char X
, char Y
) {
582 return std::tolower(X
) == std::tolower(Y
);
584 return std::equal(Key
.begin(), Key
.end(), Value
.begin(), Cmp
);
588 while (std::getline(f
, ln
)) {
589 if (ln
.empty()) continue;
590 size_t SplitIdx
= ln
.find(':');
592 if (SplitIdx
!= std::string::npos
) value
= ln
.substr(SplitIdx
+ 1);
593 // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only
594 // accept positive values. Some environments (virtual machines) report zero,
595 // which would cause infinite looping in WallTime_Init.
596 if (startsWithKey(ln
, "cpu MHz")) {
597 if (!value
.empty()) {
598 double cycles_per_second
= benchmark::stod(value
) * 1000000.0;
599 if (cycles_per_second
> 0) return cycles_per_second
;
601 } else if (startsWithKey(ln
, "bogomips")) {
602 if (!value
.empty()) {
603 bogo_clock
= benchmark::stod(value
) * 1000000.0;
604 if (bogo_clock
< 0.0) bogo_clock
= error_value
;
609 std::cerr
<< "Failure reading /proc/cpuinfo\n";
613 std::cerr
<< "Failed to read to end of /proc/cpuinfo\n";
617 // If we found the bogomips clock, but nothing better, we'll use it (but
618 // we're not happy about it); otherwise, fallback to the rough estimation
620 if (bogo_clock
>= 0.0) return bogo_clock
;
622 #elif defined BENCHMARK_HAS_SYSCTL
623 constexpr auto* FreqStr
=
624 #if defined(BENCHMARK_OS_FREEBSD) || defined(BENCHMARK_OS_NETBSD)
626 #elif defined BENCHMARK_OS_OPENBSD
628 #elif defined BENCHMARK_OS_DRAGONFLY
633 unsigned long long hz
= 0;
634 #if defined BENCHMARK_OS_OPENBSD
635 if (GetSysctl(FreqStr
, &hz
)) return hz
* 1000000;
637 if (GetSysctl(FreqStr
, &hz
)) return hz
;
639 fprintf(stderr
, "Unable to determine clock rate from sysctl: %s: %s\n",
640 FreqStr
, strerror(errno
));
642 #elif defined BENCHMARK_OS_WINDOWS
643 // In NT, read MHz from the registry. If we fail to do so or we're in win9x
644 // then make a crude estimate.
645 DWORD data
, data_size
= sizeof(data
);
646 if (IsWindowsXPOrGreater() &&
648 SHGetValueA(HKEY_LOCAL_MACHINE
,
649 "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
650 "~MHz", nullptr, &data
, &data_size
)))
651 return static_cast<double>((int64_t)data
*
652 (int64_t)(1000 * 1000)); // was mhz
653 #elif defined(BENCHMARK_OS_SOLARIS)
654 kstat_ctl_t
* kc
= kstat_open();
656 std::cerr
<< "failed to open /dev/kstat\n";
659 kstat_t
* ksp
= kstat_lookup(kc
, (char*)"cpu_info", -1, (char*)"cpu_info0");
661 std::cerr
<< "failed to lookup in /dev/kstat\n";
664 if (kstat_read(kc
, ksp
, NULL
) < 0) {
665 std::cerr
<< "failed to read from /dev/kstat\n";
669 (kstat_named_t
*)kstat_data_lookup(ksp
, (char*)"current_clock_Hz");
671 std::cerr
<< "failed to lookup data in /dev/kstat\n";
674 if (knp
->data_type
!= KSTAT_DATA_UINT64
) {
675 std::cerr
<< "current_clock_Hz is of unexpected data type: "
676 << knp
->data_type
<< "\n";
679 double clock_hz
= knp
->value
.ui64
;
682 #elif defined(BENCHMARK_OS_QNX)
683 return static_cast<double>((int64_t)(SYSPAGE_ENTRY(cpuinfo
)->speed
) *
684 (int64_t)(1000 * 1000));
686 // If we've fallen through, attempt to roughly estimate the CPU clock rate.
687 const int estimate_time_ms
= 1000;
688 const auto start_ticks
= cycleclock::Now();
689 SleepForMilliseconds(estimate_time_ms
);
690 return static_cast<double>(cycleclock::Now() - start_ticks
);
693 std::vector
<double> GetLoadAvg() {
694 #if (defined BENCHMARK_OS_FREEBSD || defined(BENCHMARK_OS_LINUX) || \
695 defined BENCHMARK_OS_MACOSX || defined BENCHMARK_OS_NETBSD || \
696 defined BENCHMARK_OS_OPENBSD || defined BENCHMARK_OS_DRAGONFLY) && \
697 !defined(__ANDROID__)
698 constexpr int kMaxSamples
= 3;
699 std::vector
<double> res(kMaxSamples
, 0.0);
700 const int nelem
= getloadavg(res
.data(), kMaxSamples
);
714 const CPUInfo
& CPUInfo::Get() {
715 static const CPUInfo
* info
= new CPUInfo();
720 : num_cpus(GetNumCPUs()),
721 scaling(CpuScaling(num_cpus
)),
722 cycles_per_second(GetCPUCyclesPerSecond(scaling
)),
723 caches(GetCacheSizes()),
724 load_avg(GetLoadAvg()) {}
726 const SystemInfo
& SystemInfo::Get() {
727 static const SystemInfo
* info
= new SystemInfo();
731 SystemInfo::SystemInfo() : name(GetSystemName()) {}
732 } // end namespace benchmark