ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
CPUInfo.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "CPUInfo.h"
9 
10 #include <cstring>
11 #include <fstream>
12 #include <memory>
13 #include <set>
14 #include <sstream>
15 #include <string>
16 #include <thread>
17 #include <vector>
18 
19 #ifdef __linux__
20 #include <sys/sysinfo.h>
21 #elif __APPLE__
22 #include <sys/sysctl.h>
23 #include <sys/types.h>
24 #elif _WIN32
25 #include <Windows.h>
26 #include <intrin.h>
27 #endif
28 
29 #include <Helper.h>
30 #include <Logging.h>
31 
32 namespace cloudViewer {
33 namespace utility {
34 
36 static int PhysicalConcurrency() {
37  try {
38 #ifdef __linux__
39  // Ref: boost::thread::physical_concurrency().
40  std::ifstream proc_cpuinfo("/proc/cpuinfo");
41  const std::string physical_id("physical id");
42  const std::string core_id("core id");
43 
44  // [physical ID, core id]
45  using CoreEntry = std::pair<int, int>;
46  std::set<CoreEntry> cores;
47  CoreEntry current_core_entry;
48 
49  std::string line;
50  while (std::getline(proc_cpuinfo, line)) {
51  if (line.empty()) {
52  continue;
53  }
54  std::vector<std::string> key_val =
55  utility::SplitString(line, ":", /*trim_empty_str=*/false);
56  if (key_val.size() != 2) {
57  return std::thread::hardware_concurrency();
58  }
59  std::string key = utility::StripString(key_val[0]);
60  std::string value = utility::StripString(key_val[1]);
61  if (key == physical_id) {
62  current_core_entry.first = std::stoi(value);
63  continue;
64  }
65  if (key == core_id) {
66  current_core_entry.second = std::stoi(value);
67  cores.insert(current_core_entry);
68  continue;
69  }
70  }
71  // Fall back to hardware_concurrency() in case
72  // /proc/cpuinfo is formatted differently than we expect.
73  return cores.size() != 0 ? cores.size()
74  : std::thread::hardware_concurrency();
75 #elif __APPLE__
76  // Ref: boost::thread::physical_concurrency().
77  int count;
78  size_t size = sizeof(count);
79  return sysctlbyname("hw.physicalcpu", &count, &size, NULL, 0) ? 0
80  : count;
81 #elif _WIN32
82  // Ref: https://stackoverflow.com/a/44247223/1255535.
83  DWORD length = 0;
84  const BOOL result_first = GetLogicalProcessorInformationEx(
85  RelationProcessorCore, nullptr, &length);
86  assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
87 
88  std::unique_ptr<uint8_t[]> buffer(new uint8_t[length]);
89  const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info =
90  reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
91  buffer.get());
92  const BOOL result_second = GetLogicalProcessorInformationEx(
93  RelationProcessorCore, info, &length);
94  assert(result_second != FALSE);
95 
96  int nb_physical_cores = 0;
97  int offset = 0;
98  do {
99  const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX current_info =
100  reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(
101  buffer.get() + offset);
102  offset += current_info->Size;
103  ++nb_physical_cores;
104  } while (offset < static_cast<int>(length));
105  return nb_physical_cores;
106 #else
107  return std::thread::hardware_concurrency();
108 #endif
109  } catch (...) {
110  return std::thread::hardware_concurrency();
111  }
112 }
113 
115 static std::string GetCPUModelName() {
116 #ifdef __linux__
117  std::ifstream proc_cpuinfo("/proc/cpuinfo");
118  std::string line;
119  while (std::getline(proc_cpuinfo, line)) {
120  if (line.find("model name") == 0) {
121  size_t colon_pos = line.find(':');
122  if (colon_pos != std::string::npos) {
123  std::string model_name = line.substr(colon_pos + 1);
124  return utility::StripString(model_name);
125  }
126  }
127  }
128  return "";
129 #elif __APPLE__
130  char brand_string[256];
131  size_t size = sizeof(brand_string);
132  if (sysctlbyname("machdep.cpu.brand_string", brand_string, &size, NULL,
133  0) == 0) {
134  return std::string(brand_string);
135  }
136  return "";
137 #elif _WIN32
138  // Use CPUID instruction to get CPU brand string
139  int cpuInfo[4] = {-1};
140  char brand_string[0x40] = {0};
141 
142  // Get extended CPUID info
143  __cpuid(cpuInfo, 0x80000000);
144  unsigned int nExIds = cpuInfo[0];
145 
146  if (nExIds >= 0x80000004) {
147  // Get brand string in 3 parts
148  for (unsigned int i = 0x80000002; i <= 0x80000004; ++i) {
149  __cpuid(cpuInfo, i);
150  memcpy(brand_string + (i - 0x80000002) * 16, cpuInfo,
151  sizeof(cpuInfo));
152  }
153  std::string result(brand_string);
154  // Trim whitespace
155  size_t first = result.find_first_not_of(" \t\n\r");
156  size_t last = result.find_last_not_of(" \t\n\r");
157  if (first != std::string::npos && last != std::string::npos) {
158  return result.substr(first, last - first + 1);
159  }
160  return result;
161  }
162  return "";
163 #else
164  return "";
165 #endif
166 }
167 
168 CPUInfo::CPUInfo() : impl_(new CPUInfo::Impl()) {
169  impl_->num_cores_ = PhysicalConcurrency();
170  impl_->num_threads_ = std::thread::hardware_concurrency();
171  impl_->model_name_ = GetCPUModelName();
172 }
173 
175  static CPUInfo instance;
176  return instance;
177 }
178 
179 int CPUInfo::NumCores() const { return impl_->num_cores_; }
180 
181 int CPUInfo::NumThreads() const { return impl_->num_threads_; }
182 
183 const std::string& CPUInfo::ModelName() const { return impl_->model_name_; }
184 
185 void CPUInfo::Print() const {
186  if (!impl_->model_name_.empty()) {
187  utility::LogInfo("CPUInfo: {} ({} cores, {} threads).",
188  impl_->model_name_, NumCores(), NumThreads());
189  } else {
190  utility::LogInfo("CPUInfo: {} cores, {} threads.", NumCores(),
191  NumThreads());
192  }
193 }
194 
195 } // namespace utility
196 } // namespace cloudViewer
int size
int count
int offset
#define NULL
core::Tensor result
Definition: VtkUtils.cpp:76
CPU information.
Definition: CPUInfo.h:19
#define LogInfo(...)
Definition: Logging.h:81
__host__ __device__ float length(float2 v)
Definition: cutil_math.h:1162
Helper functions for the ml ops.
#define FALSE
Definition: lsd.c:115
ccGuiPythonInstance * GetInstance() noexcept
Definition: Runtime.cpp:72
void SplitString(std::vector< std::string > &tokens, const std::string &str, const std::string &delimiters=" ", bool trim_empty_str=true)
Definition: Helper.cpp:197
std::string & StripString(std::string &str, const std::string &chars="\t\n\v\f\r ")
Definition: Helper.cpp:238
static std::string GetCPUModelName()
Returns the CPU model name/brand string.
Definition: CPUInfo.cpp:115
static int PhysicalConcurrency()
Returns the number of physical CPU cores.
Definition: CPUInfo.cpp:36
Generic file read and write utility for python interface.