File indexing completed on 2022-06-11 03:13:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "FWCore/MessageLogger/interface/JobReport.h"
0012 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
0013 #include "FWCore/ServiceRegistry/interface/Service.h"
0014 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0015 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0016 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0017 #include "FWCore/Utilities/interface/CPUServiceBase.h"
0018
0019 #include <iostream>
0020 #include <sys/time.h>
0021 #include <sys/resource.h>
0022 #include <cstdio>
0023 #include <string>
0024 #include <fstream>
0025 #include <sstream>
0026 #include <set>
0027
0028 #ifdef __linux__
0029 #include <sched.h>
0030 #include <cerrno>
0031 #endif
0032
0033 namespace edm {
0034
0035 namespace service {
0036 class CPU : public CPUServiceBase {
0037 public:
0038 CPU(ParameterSet const &, ActivityRegistry &);
0039 ~CPU() override;
0040
0041 static void fillDescriptions(ConfigurationDescriptions &descriptions);
0042
0043 bool cpuInfo(std::string &models, double &avgSpeed) override;
0044
0045 private:
0046 const bool reportCPUProperties_;
0047
0048 bool cpuInfoImpl(std::string &models, double &avgSpeed, Service<JobReport> *reportSvc);
0049 bool parseCPUInfo(std::vector<std::pair<std::string, std::string>> &info);
0050 std::string getModels(const std::vector<std::pair<std::string, std::string>> &info);
0051 double getAverageSpeed(const std::vector<std::pair<std::string, std::string>> &info);
0052 void postEndJob();
0053 };
0054
0055 inline bool isProcessWideService(CPU const *) { return true; }
0056 }
0057 }
0058
0059 namespace edm {
0060 namespace service {
0061 namespace {
0062
0063 std::string i2str(int i) {
0064 std::ostringstream t;
0065 t << i;
0066 return t.str();
0067 }
0068
0069 std::string d2str(double d) {
0070 std::ostringstream t;
0071 t << d;
0072 return t.str();
0073 }
0074
0075 double str2d(std::string s) { return atof(s.c_str()); }
0076
0077 void trim(std::string &s, const std::string &drop = " \t") {
0078 std::string::size_type p = s.find_last_not_of(drop);
0079 if (p != std::string::npos) {
0080 s = s.erase(p + 1);
0081 }
0082 s = s.erase(0, s.find_first_not_of(drop));
0083 }
0084
0085 std::string eraseExtraSpaces(std::string s) {
0086 bool founded = false;
0087 std::string aux;
0088 for (std::string::const_iterator iter = s.begin(); iter != s.end(); iter++) {
0089 if (founded) {
0090 if (*iter == ' ')
0091 founded = true;
0092 else {
0093 aux += " ";
0094 aux += *iter;
0095 founded = false;
0096 }
0097 } else {
0098 if (*iter == ' ')
0099 founded = true;
0100 else
0101 aux += *iter;
0102 }
0103 }
0104 return aux;
0105 }
0106
0107
0108
0109 bool getCpuSetSize(unsigned &set_size) {
0110 #ifdef __linux__
0111 cpu_set_t *cpusetp;
0112 unsigned current_size = 128;
0113 unsigned cpu_count = 0;
0114 while (current_size * 2 > current_size) {
0115 cpusetp = CPU_ALLOC(current_size);
0116 CPU_ZERO_S(CPU_ALLOC_SIZE(current_size), cpusetp);
0117
0118 if (sched_getaffinity(0, CPU_ALLOC_SIZE(current_size), cpusetp)) {
0119 CPU_FREE(cpusetp);
0120 if (errno == EINVAL) {
0121 current_size *= 2;
0122 continue;
0123 }
0124 return false;
0125 }
0126 cpu_count = CPU_COUNT_S(CPU_ALLOC_SIZE(current_size), cpusetp);
0127 CPU_FREE(cpusetp);
0128 break;
0129 }
0130 set_size = cpu_count;
0131 return true;
0132 #else
0133 return false;
0134 #endif
0135 }
0136 }
0137
0138 CPU::CPU(const ParameterSet &iPS, ActivityRegistry &iRegistry)
0139 : reportCPUProperties_(iPS.getUntrackedParameter<bool>("reportCPUProperties")) {
0140 iRegistry.watchPostEndJob(this, &CPU::postEndJob);
0141 }
0142
0143 CPU::~CPU() {}
0144
0145 void CPU::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0146 edm::ParameterSetDescription desc;
0147 desc.addUntracked<bool>("reportCPUProperties", false);
0148 descriptions.add("CPU", desc);
0149 }
0150
0151 void CPU::postEndJob() {
0152 Service<JobReport> reportSvc;
0153
0154 std::vector<std::pair<std::string, std::string>> info;
0155 if (!parseCPUInfo(info)) {
0156 return;
0157 }
0158
0159 std::string models = getModels(info);
0160 double avgSpeed = getAverageSpeed(info);
0161 unsigned totalNumberCPUs = 0;
0162 std::map<std::string, std::string> currentCoreProperties;
0163 std::string currentCore;
0164
0165 for (const auto &entry : info) {
0166 if (entry.first == "processor") {
0167 if (reportCPUProperties_) {
0168 if (currentCore.empty()) {
0169 currentCore = entry.second;
0170 } else {
0171 reportSvc->reportPerformanceForModule("SystemCPU", "CPU-" + currentCore, currentCoreProperties);
0172 currentCoreProperties.clear();
0173 currentCore = entry.second;
0174 }
0175 }
0176 totalNumberCPUs++;
0177 } else if (reportCPUProperties_) {
0178 currentCoreProperties.insert(entry);
0179 }
0180 }
0181 if (!currentCore.empty() && reportCPUProperties_) {
0182 reportSvc->reportPerformanceForModule("SystemCPU", "CPU-" + currentCore, currentCoreProperties);
0183 }
0184
0185 std::map<std::string, std::string> reportCPUProperties{
0186 {"totalCPUs", i2str(totalNumberCPUs)}, {"averageCoreSpeed", d2str(avgSpeed)}, {"CPUModels", models}};
0187 unsigned set_size = -1;
0188 if (getCpuSetSize(set_size)) {
0189 reportCPUProperties.insert(std::make_pair("cpusetCount", i2str(set_size)));
0190 }
0191 reportSvc->reportPerformanceSummary("SystemCPU", reportCPUProperties);
0192 }
0193
0194 bool CPU::cpuInfo(std::string &models, double &avgSpeed) {
0195 std::vector<std::pair<std::string, std::string>> info;
0196 if (!parseCPUInfo(info)) {
0197 return false;
0198 }
0199
0200 models = getModels(info);
0201 avgSpeed = getAverageSpeed(info);
0202 return true;
0203 }
0204
0205 bool CPU::parseCPUInfo(std::vector<std::pair<std::string, std::string>> &info) {
0206 info.clear();
0207 std::ifstream fcpuinfo("/proc/cpuinfo");
0208 if (!fcpuinfo.is_open()) {
0209 return false;
0210 }
0211 while (!fcpuinfo.eof()) {
0212 std::string buf;
0213 std::getline(fcpuinfo, buf);
0214
0215 std::istringstream iss(buf);
0216 std::string token;
0217 std::string property;
0218 std::string value;
0219
0220 int time = 1;
0221
0222 while (std::getline(iss, token, ':')) {
0223 switch (time) {
0224 case 1:
0225 property = token;
0226 break;
0227 case 2:
0228 value = token;
0229 break;
0230 default:
0231 value += token;
0232 break;
0233 }
0234 time++;
0235 }
0236 trim(property);
0237 trim(value);
0238 if (property.empty()) {
0239 continue;
0240 }
0241
0242 if (property == "model name") {
0243 value = eraseExtraSpaces(value);
0244 }
0245 info.emplace_back(property, value);
0246 }
0247 return true;
0248 }
0249
0250 std::string CPU::getModels(const std::vector<std::pair<std::string, std::string>> &info) {
0251 std::set<std::string> models;
0252 for (const auto &entry : info) {
0253 if (entry.first == "model name") {
0254 models.insert(entry.second);
0255 }
0256 }
0257 std::stringstream ss;
0258 int model = 0;
0259 for (const auto &modelname : models) {
0260 if (model++ != 0) {
0261 ss << ", ";
0262 }
0263 ss << modelname;
0264 }
0265 return ss.str();
0266 }
0267
0268 double CPU::getAverageSpeed(const std::vector<std::pair<std::string, std::string>> &info) {
0269 double averageCoreSpeed = 0.0;
0270 unsigned coreCount = 0;
0271 for (const auto &entry : info) {
0272 if (entry.first == "cpu MHz") {
0273 averageCoreSpeed += str2d(entry.second);
0274 coreCount++;
0275 }
0276 }
0277 if (!coreCount) {
0278 return 0;
0279 }
0280 return averageCoreSpeed / static_cast<double>(coreCount);
0281 }
0282 }
0283 }
0284
0285 #include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
0286
0287 using edm::service::CPU;
0288 typedef edm::serviceregistry::AllArgsMaker<edm::CPUServiceBase, CPU> CPUMaker;
0289 DEFINE_FWK_SERVICE_MAKER(CPU, CPUMaker);