CMS 3D CMS Logo

CPU.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Services
4 // Class : CPU
5 //
6 // Implementation:
7 //
8 // Original Author: Natalia Garcia
9 // CPU.cc: v 1.0 2009/01/08 11:31:07
10 
18 
19 #include "cpu_features/cpu_features_macros.h"
20 
21 #if defined(CPU_FEATURES_ARCH_X86)
22 #include "cpu_features/cpuinfo_x86.h"
23 #elif defined(CPU_FEATURES_ARCH_ARM)
24 #include "cpu_features/cpuinfo_arm.h"
25 #elif defined(CPU_FEATURES_ARCH_AARCH64)
26 #include "cpu_features/cpuinfo_aarch64.h"
27 #elif defined(CPU_FEATURES_ARCH_PPC)
28 #include "cpu_features/cpuinfo_ppc.h"
29 #endif
30 
31 #include <iostream>
32 #include <sys/time.h>
33 #include <sys/resource.h>
34 #include <cstdio>
35 #include <string>
36 #include <fstream>
37 #include <sstream>
38 #include <set>
39 #include <fmt/format.h>
40 
41 #ifdef __linux__
42 #include <sched.h>
43 #include <cerrno>
44 #endif
45 
46 namespace edm {
47 
48  namespace service {
49  class CPU : public CPUServiceBase {
50  public:
51  CPU(ParameterSet const &, ActivityRegistry &);
52  ~CPU() override;
53 
54  static void fillDescriptions(ConfigurationDescriptions &descriptions);
55 
56  bool cpuInfo(std::string &models, double &avgSpeed) override;
57 
58  private:
60 
61  bool cpuInfoImpl(std::string &models, double &avgSpeed, Service<JobReport> *reportSvc);
62  bool parseCPUInfo(std::vector<std::pair<std::string, std::string>> &info);
63  std::string getModels(const std::vector<std::pair<std::string, std::string>> &info);
65  double getAverageSpeed(const std::vector<std::pair<std::string, std::string>> &info);
66  void postEndJob();
67  };
68 
69  inline bool isProcessWideService(CPU const *) { return true; }
70  } // namespace service
71 } // namespace edm
72 
73 namespace edm {
74  namespace service {
75  namespace {
76 
77  std::string i2str(int i) {
78  std::ostringstream t;
79  t << i;
80  return t.str();
81  }
82 
83  std::string d2str(double d) {
84  std::ostringstream t;
85  t << d;
86  return t.str();
87  }
88 
89  double str2d(std::string s) { return atof(s.c_str()); }
90 
91  void trim(std::string &s, const std::string &drop = " \t") {
92  std::string::size_type p = s.find_last_not_of(drop);
93  if (p != std::string::npos) {
94  s = s.erase(p + 1);
95  }
96  s = s.erase(0, s.find_first_not_of(drop));
97  }
98 
99  std::string eraseExtraSpaces(std::string s) {
100  bool founded = false;
102  for (std::string::const_iterator iter = s.begin(); iter != s.end(); iter++) {
103  if (founded) {
104  if (*iter == ' ')
105  founded = true;
106  else {
107  aux += " ";
108  aux += *iter;
109  founded = false;
110  }
111  } else {
112  if (*iter == ' ')
113  founded = true;
114  else
115  aux += *iter;
116  }
117  }
118  return aux;
119  }
120 
121  // Determine the CPU set size; if this can be successfully determined, then this
122  // returns true.
123  bool getCpuSetSize(unsigned &set_size) {
124 #ifdef __linux__
125  cpu_set_t *cpusetp;
126  unsigned current_size = 128;
127  unsigned cpu_count = 0;
128  while (current_size * 2 > current_size) {
129  cpusetp = CPU_ALLOC(current_size);
130  CPU_ZERO_S(CPU_ALLOC_SIZE(current_size), cpusetp);
131 
132  if (sched_getaffinity(0, CPU_ALLOC_SIZE(current_size), cpusetp)) {
133  CPU_FREE(cpusetp);
134  if (errno == EINVAL) {
135  current_size *= 2;
136  continue;
137  }
138  return false;
139  }
140  cpu_count = CPU_COUNT_S(CPU_ALLOC_SIZE(current_size), cpusetp);
141  CPU_FREE(cpusetp);
142  break;
143  }
144  set_size = cpu_count;
145  return true;
146 #else
147  return false;
148 #endif
149  }
150  } // namespace
151 
152  CPU::CPU(const ParameterSet &iPS, ActivityRegistry &iRegistry)
153  : reportCPUProperties_(iPS.getUntrackedParameter<bool>("reportCPUProperties")) {
154  iRegistry.watchPostEndJob(this, &CPU::postEndJob);
155  }
156 
158 
161  desc.addUntracked<bool>("reportCPUProperties", false);
162  descriptions.add("CPU", desc);
163  }
164 
166  Service<JobReport> reportSvc;
167 
168  std::vector<std::pair<std::string, std::string>> info;
169  if (!parseCPUInfo(info)) {
170  return;
171  }
172 
174  double avgSpeed = getAverageSpeed(info);
175  unsigned totalNumberCPUs = 0;
176  std::map<std::string, std::string> currentCoreProperties;
177  std::string currentCore;
178 
179  for (const auto &entry : info) {
180  if (entry.first == "processor") {
181  if (reportCPUProperties_) {
182  if (currentCore.empty()) { // first core
183  currentCore = entry.second;
184  } else {
185  reportSvc->reportPerformanceForModule("SystemCPU", "CPU-" + currentCore, currentCoreProperties);
186  currentCoreProperties.clear();
187  currentCore = entry.second;
188  }
189  }
190  totalNumberCPUs++;
191  } else if (reportCPUProperties_) {
192  currentCoreProperties.insert(entry);
193  }
194  }
195  if (!currentCore.empty() && reportCPUProperties_) {
196  reportSvc->reportPerformanceForModule("SystemCPU", "CPU-" + currentCore, currentCoreProperties);
197  }
198 
199  std::map<std::string, std::string> reportCPUProperties{
200  {"totalCPUs", i2str(totalNumberCPUs)}, {"averageCoreSpeed", d2str(avgSpeed)}, {"CPUModels", models}};
201  unsigned set_size = -1;
202  if (getCpuSetSize(set_size)) {
203  reportCPUProperties.insert(std::make_pair("cpusetCount", i2str(set_size)));
204  }
205  reportSvc->reportPerformanceSummary("SystemCPU", reportCPUProperties);
206  }
207 
208  bool CPU::cpuInfo(std::string &models, double &avgSpeed) {
209  std::vector<std::pair<std::string, std::string>> info;
210  if (!parseCPUInfo(info)) {
211  return false;
212  }
213 
214  models = getModels(info);
215  avgSpeed = getAverageSpeed(info);
216  return true;
217  }
218 
219  bool CPU::parseCPUInfo(std::vector<std::pair<std::string, std::string>> &info) {
220  info.clear();
221  std::ifstream fcpuinfo("/proc/cpuinfo");
222  if (!fcpuinfo.is_open()) {
223  return false;
224  }
225  while (!fcpuinfo.eof()) {
227  std::getline(fcpuinfo, buf);
228 
229  std::istringstream iss(buf);
231  std::string property;
233 
234  int time = 1;
235 
236  while (std::getline(iss, token, ':')) {
237  switch (time) {
238  case 1:
239  property = token;
240  break;
241  case 2:
242  value = token;
243  break;
244  default:
245  value += token;
246  break;
247  }
248  time++;
249  }
250  trim(property);
251  trim(value);
252  if (property.empty()) {
253  continue;
254  }
255 
256  if (property == "model name") {
257  value = eraseExtraSpaces(value);
258  }
259  info.emplace_back(property, value);
260  }
261  return true;
262  }
263 
265  using namespace cpu_features;
266 
268 #if defined(CPU_FEATURES_ARCH_X86)
269  const auto info{GetX86Info()};
270  model = info.brand_string;
271 #elif defined(CPU_FEATURES_ARCH_ARM)
272  const auto info{GetArmInfo()};
273  model = fmt::format("ARM {} {} {}", info.implementer, info.architecture, info.variant);
274 #elif defined(CPU_FEATURES_ARCH_AARCH64)
275  const auto info{GetAarch64Info()};
276  model = fmt::format("aarch64 {} {}", info.implementer, info.variant);
277 #elif defined(CPU_FEATURES_ARCH_PPC)
278  const auto strings{GetPPCPlatformStrings()};
279  model = strings.machine;
280 #endif
281  return model;
282  }
283 
284  std::string CPU::getModels(const std::vector<std::pair<std::string, std::string>> &info) {
285  std::set<std::string> models;
286  for (const auto &entry : info) {
287  if (entry.first == "model name") {
288  models.insert(entry.second);
289  }
290  }
291  std::stringstream ss;
292  int model = 0;
293  for (const auto &modelname : models) {
294  if (model++ != 0) {
295  ss << ", ";
296  }
297  ss << modelname;
298  }
299  // If "model name" isn't present in /proc/cpuinfo, see what we can get
300  // from cpu_features
301  if (0 == model) {
302  return getModelFromCPUFeatures();
303  }
304  return ss.str();
305  }
306 
307  double CPU::getAverageSpeed(const std::vector<std::pair<std::string, std::string>> &info) {
308  double averageCoreSpeed = 0.0;
309  unsigned coreCount = 0;
310  for (const auto &entry : info) {
311  if (entry.first == "cpu MHz") {
312  averageCoreSpeed += str2d(entry.second);
313  coreCount++;
314  }
315  }
316  if (!coreCount) {
317  return 0;
318  }
319  return averageCoreSpeed / static_cast<double>(coreCount);
320  }
321  } // namespace service
322 } // namespace edm
323 
325 
326 using edm::service::CPU;
static std::string i2str(int i)
static const TGPicture * info(bool iBackgroundIsBlack)
double getAverageSpeed(const std::vector< std::pair< std::string, std::string >> &info)
Definition: CPU.cc:307
#define DEFINE_FWK_SERVICE_MAKER(concrete, maker)
Definition: ServiceMaker.h:102
void postEndJob()
Definition: CPU.cc:165
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
bool isProcessWideService(TFileService const *)
Definition: TFileService.h:98
static void trim(std::string &s)
Definition: models.py:1
uint16_t size_type
edm::serviceregistry::AllArgsMaker< edm::CPUServiceBase, CPU > CPUMaker
Definition: CPU.cc:327
bool cpuInfo(std::string &models, double &avgSpeed) override
CPU information - the models present and average speed.
Definition: CPU.cc:208
bool parseCPUInfo(std::vector< std::pair< std::string, std::string >> &info)
Definition: CPU.cc:219
~CPU() override
Definition: CPU.cc:157
Definition: value.py:1
d
Definition: ztail.py:151
const int drop
CPU(ParameterSet const &, ActivityRegistry &)
Definition: CPU.cc:152
static std::string d2str(double d)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
bool cpuInfoImpl(std::string &models, double &avgSpeed, Service< JobReport > *reportSvc)
std::string getModelFromCPUFeatures()
Definition: CPU.cc:264
static void fillDescriptions(ConfigurationDescriptions &descriptions)
Definition: CPU.cc:159
HLT enums.
const bool reportCPUProperties_
Definition: CPU.cc:59
std::string getModels(const std::vector< std::pair< std::string, std::string >> &info)
Definition: CPU.cc:284