benchmark/src/sysinfo.cc
Go to the documentation of this file.
1 // Copyright 2015 Google Inc. All rights reserved.
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14 
15 #include "internal_macros.h"
16 
17 #ifdef BENCHMARK_OS_WINDOWS
18 #include <shlwapi.h>
19 #undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
20 #include <versionhelpers.h>
21 #include <windows.h>
22 #include <codecvt>
23 #else
24 #include <fcntl.h>
25 #ifndef BENCHMARK_OS_FUCHSIA
26 #include <sys/resource.h>
27 #endif
28 #include <sys/time.h>
29 #include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
30 #include <unistd.h>
31 #if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX || \
32  defined BENCHMARK_OS_NETBSD || defined BENCHMARK_OS_OPENBSD || \
33  defined BENCHMARK_OS_DRAGONFLY
34 #define BENCHMARK_HAS_SYSCTL
35 #include <sys/sysctl.h>
36 #endif
37 #endif
38 #if defined(BENCHMARK_OS_SOLARIS)
39 #include <kstat.h>
40 #endif
41 #if defined(BENCHMARK_OS_QNX)
42 #include <sys/syspage.h>
43 #endif
44 
45 #include <algorithm>
46 #include <array>
47 #include <bitset>
48 #include <cerrno>
49 #include <climits>
50 #include <cstdint>
51 #include <cstdio>
52 #include <cstdlib>
53 #include <cstring>
54 #include <fstream>
55 #include <iostream>
56 #include <iterator>
57 #include <limits>
58 #include <memory>
59 #include <sstream>
60 #include <locale>
61 #include <utility>
62 
63 #include "check.h"
64 #include "cycleclock.h"
65 #include "internal_macros.h"
66 #include "log.h"
67 #include "sleep.h"
68 #include "string_util.h"
69 
70 namespace benchmark {
71 namespace {
72 
73 void PrintImp(std::ostream& out) { out << std::endl; }
74 
75 template <class First, class... Rest>
76 void PrintImp(std::ostream& out, First&& f, Rest&&... rest) {
77  out << std::forward<First>(f);
78  PrintImp(out, std::forward<Rest>(rest)...);
79 }
80 
81 template <class... Args>
82 BENCHMARK_NORETURN void PrintErrorAndDie(Args&&... args) {
83  PrintImp(std::cerr, std::forward<Args>(args)...);
84  std::exit(EXIT_FAILURE);
85 }
86 
87 #ifdef BENCHMARK_HAS_SYSCTL
88 
91 struct ValueUnion {
92  union DataT {
93  uint32_t uint32_value;
94  uint64_t uint64_value;
95  // For correct aliasing of union members from bytes.
96  char bytes[8];
97  };
98  using DataPtr = std::unique_ptr<DataT, decltype(&std::free)>;
99 
100  // The size of the data union member + its trailing array size.
101  size_t Size;
102  DataPtr Buff;
103 
104  public:
105  ValueUnion() : Size(0), Buff(nullptr, &std::free) {}
106 
107  explicit ValueUnion(size_t BuffSize)
108  : Size(sizeof(DataT) + BuffSize),
109  Buff(::new (std::malloc(Size)) DataT(), &std::free) {}
110 
111  ValueUnion(ValueUnion&& other) = default;
112 
113  explicit operator bool() const { return bool(Buff); }
114 
115  char* data() const { return Buff->bytes; }
116 
117  std::string GetAsString() const { return std::string(data()); }
118 
119  int64_t GetAsInteger() const {
120  if (Size == sizeof(Buff->uint32_value))
121  return static_cast<int32_t>(Buff->uint32_value);
122  else if (Size == sizeof(Buff->uint64_value))
123  return static_cast<int64_t>(Buff->uint64_value);
125  }
126 
127  uint64_t GetAsUnsigned() const {
128  if (Size == sizeof(Buff->uint32_value))
129  return Buff->uint32_value;
130  else if (Size == sizeof(Buff->uint64_value))
131  return Buff->uint64_value;
133  }
134 
135  template <class T, int N>
136  std::array<T, N> GetAsArray() {
137  const int ArrSize = sizeof(T) * N;
138  BM_CHECK_LE(ArrSize, Size);
139  std::array<T, N> Arr;
140  std::memcpy(Arr.data(), data(), ArrSize);
141  return Arr;
142  }
143 };
144 
145 ValueUnion GetSysctlImp(std::string const& Name) {
146 #if defined BENCHMARK_OS_OPENBSD
147  int mib[2];
148 
149  mib[0] = CTL_HW;
150  if ((Name == "hw.ncpu") || (Name == "hw.cpuspeed")){
151  ValueUnion buff(sizeof(int));
152 
153  if (Name == "hw.ncpu") {
154  mib[1] = HW_NCPU;
155  } else {
156  mib[1] = HW_CPUSPEED;
157  }
158 
159  if (sysctl(mib, 2, buff.data(), &buff.Size, nullptr, 0) == -1) {
160  return ValueUnion();
161  }
162  return buff;
163  }
164  return ValueUnion();
165 #else
166  size_t CurBuffSize = 0;
167  if (sysctlbyname(Name.c_str(), nullptr, &CurBuffSize, nullptr, 0) == -1)
168  return ValueUnion();
169 
170  ValueUnion buff(CurBuffSize);
171  if (sysctlbyname(Name.c_str(), buff.data(), &buff.Size, nullptr, 0) == 0)
172  return buff;
173  return ValueUnion();
174 #endif
175 }
176 
178 bool GetSysctl(std::string const& Name, std::string* Out) {
179  Out->clear();
180  auto Buff = GetSysctlImp(Name);
181  if (!Buff) return false;
182  Out->assign(Buff.data());
183  return true;
184 }
185 
186 template <class Tp,
188 bool GetSysctl(std::string const& Name, Tp* Out) {
189  *Out = 0;
190  auto Buff = GetSysctlImp(Name);
191  if (!Buff) return false;
192  *Out = static_cast<Tp>(Buff.GetAsUnsigned());
193  return true;
194 }
195 
196 template <class Tp, size_t N>
197 bool GetSysctl(std::string const& Name, std::array<Tp, N>* Out) {
198  auto Buff = GetSysctlImp(Name);
199  if (!Buff) return false;
200  *Out = Buff.GetAsArray<Tp, N>();
201  return true;
202 }
203 #endif
204 
205 template <class ArgT>
206 bool ReadFromFile(std::string const& fname, ArgT* arg) {
207  *arg = ArgT();
208  std::ifstream f(fname.c_str());
209  if (!f.is_open()) return false;
210  f >> *arg;
211  return f.good();
212 }
213 
214 CPUInfo::Scaling CpuScaling(int num_cpus) {
215  // We don't have a valid CPU count, so don't even bother.
216  if (num_cpus <= 0) return CPUInfo::Scaling::UNKNOWN;
217 #if defined(BENCHMARK_OS_QNX)
218  return CPUInfo::Scaling::UNKNOWN;
219 #elif !defined(BENCHMARK_OS_WINDOWS)
220  // On Linux, the CPUfreq subsystem exposes CPU information as files on the
221  // local file system. If reading the exported files fails, then we may not be
222  // running on Linux, so we silently ignore all the read errors.
223  std::string res;
224  for (int cpu = 0; cpu < num_cpus; ++cpu) {
225  std::string governor_file =
226  StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor");
227  if (ReadFromFile(governor_file, &res) && res != "performance") return CPUInfo::Scaling::ENABLED;
228  }
229  return CPUInfo::Scaling::DISABLED;
230 #else
231  return CPUInfo::Scaling::UNKNOWN;
232 #endif
233 }
234 
235 int CountSetBitsInCPUMap(std::string Val) {
236  auto CountBits = [](std::string Part) {
237  using CPUMask = std::bitset<sizeof(std::uintptr_t) * CHAR_BIT>;
238  Part = "0x" + Part;
239  CPUMask Mask(benchmark::stoul(Part, nullptr, 16));
240  return static_cast<int>(Mask.count());
241  };
242  size_t Pos;
243  int total = 0;
244  while ((Pos = Val.find(',')) != std::string::npos) {
245  total += CountBits(Val.substr(0, Pos));
246  Val = Val.substr(Pos + 1);
247  }
248  if (!Val.empty()) {
249  total += CountBits(Val);
250  }
251  return total;
252 }
253 
255 std::vector<CPUInfo::CacheInfo> GetCacheSizesFromKVFS() {
256  std::vector<CPUInfo::CacheInfo> res;
257  std::string dir = "/sys/devices/system/cpu/cpu0/cache/";
258  int Idx = 0;
259  while (true) {
260  CPUInfo::CacheInfo info;
261  std::string FPath = StrCat(dir, "index", Idx++, "/");
262  std::ifstream f(StrCat(FPath, "size").c_str());
263  if (!f.is_open()) break;
265  f >> info.size;
266  if (f.fail())
267  PrintErrorAndDie("Failed while reading file '", FPath, "size'");
268  if (f.good()) {
269  f >> suffix;
270  if (f.bad())
271  PrintErrorAndDie(
272  "Invalid cache size format: failed to read size suffix");
273  else if (f && suffix != "K")
274  PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix);
275  else if (suffix == "K")
276  info.size *= 1024;
277  }
278  if (!ReadFromFile(StrCat(FPath, "type"), &info.type))
279  PrintErrorAndDie("Failed to read from file ", FPath, "type");
280  if (!ReadFromFile(StrCat(FPath, "level"), &info.level))
281  PrintErrorAndDie("Failed to read from file ", FPath, "level");
282  std::string map_str;
283  if (!ReadFromFile(StrCat(FPath, "shared_cpu_map"), &map_str))
284  PrintErrorAndDie("Failed to read from file ", FPath, "shared_cpu_map");
285  info.num_sharing = CountSetBitsInCPUMap(map_str);
286  res.push_back(info);
287  }
288 
289  return res;
290 }
291 
292 #ifdef BENCHMARK_OS_MACOSX
293 std::vector<CPUInfo::CacheInfo> GetCacheSizesMacOSX() {
294  std::vector<CPUInfo::CacheInfo> res;
295  std::array<uint64_t, 4> CacheCounts{{0, 0, 0, 0}};
296  GetSysctl("hw.cacheconfig", &CacheCounts);
297 
298  struct {
301  int level;
302  uint64_t num_sharing;
303  } Cases[] = {{"hw.l1dcachesize", "Data", 1, CacheCounts[1]},
304  {"hw.l1icachesize", "Instruction", 1, CacheCounts[1]},
305  {"hw.l2cachesize", "Unified", 2, CacheCounts[2]},
306  {"hw.l3cachesize", "Unified", 3, CacheCounts[3]}};
307  for (auto& C : Cases) {
308  int val;
309  if (!GetSysctl(C.name, &val)) continue;
310  CPUInfo::CacheInfo info;
311  info.type = C.type;
312  info.level = C.level;
313  info.size = val;
314  info.num_sharing = static_cast<int>(C.num_sharing);
315  res.push_back(std::move(info));
316  }
317  return res;
318 }
319 #elif defined(BENCHMARK_OS_WINDOWS)
320 std::vector<CPUInfo::CacheInfo> GetCacheSizesWindows() {
321  std::vector<CPUInfo::CacheInfo> res;
322  DWORD buffer_size = 0;
323  using PInfo = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
324  using CInfo = CACHE_DESCRIPTOR;
325 
326  using UPtr = std::unique_ptr<PInfo, decltype(&std::free)>;
327  GetLogicalProcessorInformation(nullptr, &buffer_size);
328  UPtr buff((PInfo*)malloc(buffer_size), &std::free);
329  if (!GetLogicalProcessorInformation(buff.get(), &buffer_size))
330  PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ",
331  GetLastError());
332 
333  PInfo* it = buff.get();
334  PInfo* end = buff.get() + (buffer_size / sizeof(PInfo));
335 
336  for (; it != end; ++it) {
337  if (it->Relationship != RelationCache) continue;
338  using BitSet = std::bitset<sizeof(ULONG_PTR) * CHAR_BIT>;
339  BitSet B(it->ProcessorMask);
340  // To prevent duplicates, only consider caches where CPU 0 is specified
341  if (!B.test(0)) continue;
342  CInfo* Cache = &it->Cache;
343  CPUInfo::CacheInfo C;
344  C.num_sharing = static_cast<int>(B.count());
345  C.level = Cache->Level;
346  C.size = Cache->Size;
347  switch (Cache->Type) {
348  case CacheUnified:
349  C.type = "Unified";
350  break;
351  case CacheInstruction:
352  C.type = "Instruction";
353  break;
354  case CacheData:
355  C.type = "Data";
356  break;
357  case CacheTrace:
358  C.type = "Trace";
359  break;
360  default:
361  C.type = "Unknown";
362  break;
363  }
364  res.push_back(C);
365  }
366  return res;
367 }
368 #elif BENCHMARK_OS_QNX
369 std::vector<CPUInfo::CacheInfo> GetCacheSizesQNX() {
370  std::vector<CPUInfo::CacheInfo> res;
371  struct cacheattr_entry *cache = SYSPAGE_ENTRY(cacheattr);
372  uint32_t const elsize = SYSPAGE_ELEMENT_SIZE(cacheattr);
373  int num = SYSPAGE_ENTRY_SIZE(cacheattr) / elsize ;
374  for(int i = 0; i < num; ++i ) {
375  CPUInfo::CacheInfo info;
376  switch (cache->flags){
377  case CACHE_FLAG_INSTR :
378  info.type = "Instruction";
379  info.level = 1;
380  break;
381  case CACHE_FLAG_DATA :
382  info.type = "Data";
383  info.level = 1;
384  break;
385  case CACHE_FLAG_UNIFIED :
386  info.type = "Unified";
387  info.level = 2;
388  break;
389  case CACHE_FLAG_SHARED :
390  info.type = "Shared";
391  info.level = 3;
392  break;
393  default :
394  continue;
395  break;
396  }
397  info.size = cache->line_size * cache->num_lines;
398  info.num_sharing = 0;
399  res.push_back(std::move(info));
400  cache = SYSPAGE_ARRAY_ADJ_OFFSET(cacheattr, cache, elsize);
401  }
402  return res;
403 }
404 #endif
405 
406 std::vector<CPUInfo::CacheInfo> GetCacheSizes() {
407 #ifdef BENCHMARK_OS_MACOSX
408  return GetCacheSizesMacOSX();
409 #elif defined(BENCHMARK_OS_WINDOWS)
410  return GetCacheSizesWindows();
411 #elif defined(BENCHMARK_OS_QNX)
412  return GetCacheSizesQNX();
413 #else
414  return GetCacheSizesFromKVFS();
415 #endif
416 }
417 
418 std::string GetSystemName() {
419 #if defined(BENCHMARK_OS_WINDOWS)
421  const unsigned COUNT = MAX_COMPUTERNAME_LENGTH+1;
422  TCHAR hostname[COUNT] = {'\0'};
423  DWORD DWCOUNT = COUNT;
424  if (!GetComputerName(hostname, &DWCOUNT))
425  return std::string("");
426 #ifndef UNICODE
427  str = std::string(hostname, DWCOUNT);
428 #else
429  //Using wstring_convert, Is deprecated in C++17
430  using convert_type = std::codecvt_utf8<wchar_t>;
431  std::wstring_convert<convert_type, wchar_t> converter;
432  std::wstring wStr(hostname, DWCOUNT);
433  str = converter.to_bytes(wStr);
434 #endif
435  return str;
436 #else // defined(BENCHMARK_OS_WINDOWS)
437 #ifndef HOST_NAME_MAX
438 #ifdef BENCHMARK_HAS_SYSCTL // BSD/Mac Doesnt have HOST_NAME_MAX defined
439 #define HOST_NAME_MAX 64
440 #elif defined(BENCHMARK_OS_NACL)
441 #define HOST_NAME_MAX 64
442 #elif defined(BENCHMARK_OS_QNX)
443 #define HOST_NAME_MAX 154
444 #elif defined(BENCHMARK_OS_RTEMS)
445 #define HOST_NAME_MAX 256
446 #else
447 #pragma message("HOST_NAME_MAX not defined. using 64")
448 #define HOST_NAME_MAX 64
449 #endif
450 #endif // def HOST_NAME_MAX
451  char hostname[HOST_NAME_MAX];
452  int retVal = gethostname(hostname, HOST_NAME_MAX);
453  if (retVal != 0) return std::string("");
454  return std::string(hostname);
455 #endif // Catch-all POSIX block.
456 }
457 
458 int GetNumCPUs() {
459 #ifdef BENCHMARK_HAS_SYSCTL
460  int NumCPU = -1;
461  if (GetSysctl("hw.ncpu", &NumCPU)) return NumCPU;
462  fprintf(stderr, "Err: %s\n", strerror(errno));
463  std::exit(EXIT_FAILURE);
464 #elif defined(BENCHMARK_OS_WINDOWS)
465  SYSTEM_INFO sysinfo;
466  // Use memset as opposed to = {} to avoid GCC missing initializer false
467  // positives.
468  std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO));
469  GetSystemInfo(&sysinfo);
470  return sysinfo.dwNumberOfProcessors; // number of logical
471  // processors in the current
472  // group
473 #elif defined(BENCHMARK_OS_SOLARIS)
474  // Returns -1 in case of a failure.
475  int NumCPU = sysconf(_SC_NPROCESSORS_ONLN);
476  if (NumCPU < 0) {
477  fprintf(stderr,
478  "sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n",
479  strerror(errno));
480  }
481  return NumCPU;
482 #elif defined(BENCHMARK_OS_QNX)
483  return static_cast<int>(_syspage_ptr->num_cpu);
484 #else
485  int NumCPUs = 0;
486  int MaxID = -1;
487  std::ifstream f("/proc/cpuinfo");
488  if (!f.is_open()) {
489  std::cerr << "failed to open /proc/cpuinfo\n";
490  return -1;
491  }
492  const std::string Key = "processor";
493  std::string ln;
494  while (std::getline(f, ln)) {
495  if (ln.empty()) continue;
496  size_t SplitIdx = ln.find(':');
498 #if defined(__s390__)
499  // s390 has another format in /proc/cpuinfo
500  // it needs to be parsed differently
501  if (SplitIdx != std::string::npos) value = ln.substr(Key.size()+1,SplitIdx-Key.size()-1);
502 #else
503  if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
504 #endif
505  if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) {
506  NumCPUs++;
507  if (!value.empty()) {
508  int CurID = benchmark::stoi(value);
509  MaxID = std::max(CurID, MaxID);
510  }
511  }
512  }
513  if (f.bad()) {
514  std::cerr << "Failure reading /proc/cpuinfo\n";
515  return -1;
516  }
517  if (!f.eof()) {
518  std::cerr << "Failed to read to end of /proc/cpuinfo\n";
519  return -1;
520  }
521  f.close();
522 
523  if ((MaxID + 1) != NumCPUs) {
524  fprintf(stderr,
525  "CPU ID assignments in /proc/cpuinfo seem messed up."
526  " This is usually caused by a bad BIOS.\n");
527  }
528  return NumCPUs;
529 #endif
531 }
532 
533 double GetCPUCyclesPerSecond(CPUInfo::Scaling scaling) {
534  // Currently, scaling is only used on linux path here,
535  // suppress diagnostics about it being unused on other paths.
536  (void)scaling;
537 
538 #if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
539  long freq;
540 
541  // If the kernel is exporting the tsc frequency use that. There are issues
542  // where cpuinfo_max_freq cannot be relied on because the BIOS may be
543  // exporintg an invalid p-state (on x86) or p-states may be used to put the
544  // processor in a new mode (turbo mode). Essentially, those frequencies
545  // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as
546  // well.
547  if (ReadFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)
548  // If CPU scaling is disabled, use the *current* frequency.
549  // Note that we specifically don't want to read cpuinfo_cur_freq,
550  // because it is only readable by root.
551  || (scaling == CPUInfo::Scaling::DISABLED &&
552  ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq",
553  &freq))
554  // Otherwise, if CPU scaling may be in effect, we want to use
555  // the *maximum* frequency, not whatever CPU speed some random processor
556  // happens to be using now.
557  || ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
558  &freq)) {
559  // The value is in kHz (as the file name suggests). For example, on a
560  // 2GHz warpstation, the file contains the value "2000000".
561  return freq * 1000.0;
562  }
563 
564  const double error_value = -1;
565  double bogo_clock = error_value;
566 
567  std::ifstream f("/proc/cpuinfo");
568  if (!f.is_open()) {
569  std::cerr << "failed to open /proc/cpuinfo\n";
570  return error_value;
571  }
572 
573  auto startsWithKey = [](std::string const& Value, std::string const& Key) {
574  if (Key.size() > Value.size()) return false;
575  auto Cmp = [&](char X, char Y) {
576  return std::tolower(X) == std::tolower(Y);
577  };
578  return std::equal(Key.begin(), Key.end(), Value.begin(), Cmp);
579  };
580 
581  std::string ln;
582  while (std::getline(f, ln)) {
583  if (ln.empty()) continue;
584  size_t SplitIdx = ln.find(':');
586  if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
587  // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only
588  // accept positive values. Some environments (virtual machines) report zero,
589  // which would cause infinite looping in WallTime_Init.
590  if (startsWithKey(ln, "cpu MHz")) {
591  if (!value.empty()) {
592  double cycles_per_second = benchmark::stod(value) * 1000000.0;
593  if (cycles_per_second > 0) return cycles_per_second;
594  }
595  } else if (startsWithKey(ln, "bogomips")) {
596  if (!value.empty()) {
597  bogo_clock = benchmark::stod(value) * 1000000.0;
598  if (bogo_clock < 0.0) bogo_clock = error_value;
599  }
600  }
601  }
602  if (f.bad()) {
603  std::cerr << "Failure reading /proc/cpuinfo\n";
604  return error_value;
605  }
606  if (!f.eof()) {
607  std::cerr << "Failed to read to end of /proc/cpuinfo\n";
608  return error_value;
609  }
610  f.close();
611  // If we found the bogomips clock, but nothing better, we'll use it (but
612  // we're not happy about it); otherwise, fallback to the rough estimation
613  // below.
614  if (bogo_clock >= 0.0) return bogo_clock;
615 
616 #elif defined BENCHMARK_HAS_SYSCTL
617  constexpr auto* FreqStr =
618 #if defined(BENCHMARK_OS_FREEBSD) || defined(BENCHMARK_OS_NETBSD)
619  "machdep.tsc_freq";
620 #elif defined BENCHMARK_OS_OPENBSD
621  "hw.cpuspeed";
622 #elif defined BENCHMARK_OS_DRAGONFLY
623  "hw.tsc_frequency";
624 #else
625  "hw.cpufrequency";
626 #endif
627  unsigned long long hz = 0;
628 #if defined BENCHMARK_OS_OPENBSD
629  if (GetSysctl(FreqStr, &hz)) return hz * 1000000;
630 #else
631  if (GetSysctl(FreqStr, &hz)) return hz;
632 #endif
633  fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n",
634  FreqStr, strerror(errno));
635 
636 #elif defined BENCHMARK_OS_WINDOWS
637  // In NT, read MHz from the registry. If we fail to do so or we're in win9x
638  // then make a crude estimate.
639  DWORD data, data_size = sizeof(data);
640  if (IsWindowsXPOrGreater() &&
641  SUCCEEDED(
642  SHGetValueA(HKEY_LOCAL_MACHINE,
643  "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
644  "~MHz", nullptr, &data, &data_size)))
645  return static_cast<double>((int64_t)data *
646  (int64_t)(1000 * 1000)); // was mhz
647 #elif defined (BENCHMARK_OS_SOLARIS)
648  kstat_ctl_t *kc = kstat_open();
649  if (!kc) {
650  std::cerr << "failed to open /dev/kstat\n";
651  return -1;
652  }
653  kstat_t *ksp = kstat_lookup(kc, (char*)"cpu_info", -1, (char*)"cpu_info0");
654  if (!ksp) {
655  std::cerr << "failed to lookup in /dev/kstat\n";
656  return -1;
657  }
658  if (kstat_read(kc, ksp, NULL) < 0) {
659  std::cerr << "failed to read from /dev/kstat\n";
660  return -1;
661  }
662  kstat_named_t *knp =
663  (kstat_named_t*)kstat_data_lookup(ksp, (char*)"current_clock_Hz");
664  if (!knp) {
665  std::cerr << "failed to lookup data in /dev/kstat\n";
666  return -1;
667  }
668  if (knp->data_type != KSTAT_DATA_UINT64) {
669  std::cerr << "current_clock_Hz is of unexpected data type: "
670  << knp->data_type << "\n";
671  return -1;
672  }
673  double clock_hz = knp->value.ui64;
674  kstat_close(kc);
675  return clock_hz;
676 #elif defined (BENCHMARK_OS_QNX)
677  return static_cast<double>((int64_t)(SYSPAGE_ENTRY(cpuinfo)->speed) *
678  (int64_t)(1000 * 1000));
679 #endif
680  // If we've fallen through, attempt to roughly estimate the CPU clock rate.
681  const int estimate_time_ms = 1000;
682  const auto start_ticks = cycleclock::Now();
683  SleepForMilliseconds(estimate_time_ms);
684  return static_cast<double>(cycleclock::Now() - start_ticks);
685 }
686 
687 std::vector<double> GetLoadAvg() {
688 #if (defined BENCHMARK_OS_FREEBSD || defined(BENCHMARK_OS_LINUX) || \
689  defined BENCHMARK_OS_MACOSX || defined BENCHMARK_OS_NETBSD || \
690  defined BENCHMARK_OS_OPENBSD || defined BENCHMARK_OS_DRAGONFLY) && \
691  !defined(__ANDROID__)
692  constexpr int kMaxSamples = 3;
693  std::vector<double> res(kMaxSamples, 0.0);
694  const int nelem = getloadavg(res.data(), kMaxSamples);
695  if (nelem < 1) {
696  res.clear();
697  } else {
698  res.resize(nelem);
699  }
700  return res;
701 #else
702  return {};
703 #endif
704 }
705 
706 } // end namespace
707 
709  static const CPUInfo* info = new CPUInfo();
710  return *info;
711 }
712 
714  : num_cpus(GetNumCPUs()),
715  scaling(CpuScaling(num_cpus)),
716  cycles_per_second(GetCPUCyclesPerSecond(scaling)),
717  caches(GetCacheSizes()),
718  load_avg(GetLoadAvg()) {}
719 
721  static const SystemInfo* info = new SystemInfo();
722  return *info;
723 }
724 
725 SystemInfo::SystemInfo() : name(GetSystemName()) {}
726 } // end namespace benchmark
BM_CHECK_LE
#define BM_CHECK_LE(a, b)
Definition: benchmark/src/check.h:71
xds_interop_client.str
str
Definition: xds_interop_client.py:487
log.h
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
benchmark::CPUInfo::Scaling
Scaling
Definition: benchmark/include/benchmark/benchmark.h:1361
regen-readme.it
it
Definition: regen-readme.py:15
check.h
X
#define X(c)
bool
bool
Definition: setup_once.h:312
benchmark
Definition: bm_alarm.cc:55
memset
return memset(p, 0, total)
benchmark::SystemInfo::Get
static const SystemInfo & Get()
Definition: benchmark/src/sysinfo.cc:720
asyncio_get_stats.default
default
Definition: asyncio_get_stats.py:38
C
#define C(x)
Definition: abseil-cpp/absl/hash/internal/city_test.cc:49
BENCHMARK_UNREACHABLE
#define BENCHMARK_UNREACHABLE()
Definition: benchmark/include/benchmark/benchmark.h:265
total
size_t total
Definition: cord_analysis.cc:59
BENCHMARK_NORETURN
#define BENCHMARK_NORETURN
Definition: benchmark/src/internal_macros.h:40
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
Pos
ush Pos
Definition: bloaty/third_party/zlib/deflate.h:92
make_cmakelists.converter
converter
Definition: make_cmakelists.py:317
COUNT
#define COUNT(T, name, index)
Definition: abseil-cpp/absl/flags/flag_benchmark.cc:135
setup.name
name
Definition: setup.py:542
env.new
def new
Definition: env.py:51
T
#define T(upbtypeconst, upbtype, ctype, default_value)
benchmark::SystemInfo::SystemInfo
SystemInfo()
Definition: benchmark/src/sysinfo.cc:725
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
autogen_x86imm.f
f
Definition: autogen_x86imm.py:9
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
hpack_encoder_fixtures::Args
Args({0, 16384})
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
absl::base_internal::num_cpus
static ABSL_CONST_INIT int num_cpus
Definition: abseil-cpp/absl/base/internal/sysinfo.cc:343
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
HOST_NAME_MAX
#define HOST_NAME_MAX
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
BENCHMARK_MAYBE_UNUSED
#define BENCHMARK_MAYBE_UNUSED
Definition: benchmark/src/internal_macros.h:97
benchmark::SystemInfo
Definition: benchmark/include/benchmark/benchmark.h:1381
arg
Definition: cmdline.cc:40
testing::internal::wstring
::std::wstring wstring
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:887
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
sleep.h
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
benchmark::CPUInfo::Get
static const CPUInfo & Get()
Definition: benchmark/src/sysinfo.cc:708
value
const char * value
Definition: hpack_parser_table.cc:165
internal_macros.h
benchmark::SleepForMilliseconds
void SleepForMilliseconds(int milliseconds)
Definition: third_party/benchmark/src/sleep.cc:59
cycleclock.h
string_util.h
N
#define N
Definition: sync_test.cc:37
suffix
unsigned char suffix[65536]
Definition: bloaty/third_party/zlib/examples/gun.c:164
bytes
uint8 bytes[10]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:153
testing::Key
internal::KeyMatcher< M > Key(M inner_matcher)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:9141
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
xds_manager.num
num
Definition: xds_manager.py:56
arg
struct arg arg
benchmark::cycleclock::Now
BENCHMARK_ALWAYS_INLINE int64_t Now()
Definition: benchmark/src/cycleclock.h:61
benchmark::CPUInfo::CPUInfo
CPUInfo()
Definition: benchmark/src/sysinfo.cc:713
benchmark::CPUInfo
Definition: benchmark/include/benchmark/benchmark.h:1353
benchmark::NumCPUs
int NumCPUs(void)
Definition: bloaty/third_party/protobuf/third_party/benchmark/src/sysinfo.cc:321
client.level
level
Definition: examples/python/async_streaming/client.py:118
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
Value
struct Value Value
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:676
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
benchmark::StrCat
std::string StrCat(Args &&... args)
Definition: third_party/benchmark/src/string_util.h:34
versiongenerate.buffer_size
int buffer_size
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/xcode/Scripts/versiongenerate.py:65
absl::base_internal::GetNumCPUs
static int GetNumCPUs()
Definition: abseil-cpp/absl/base/internal/sysinfo.cc:127
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:24