File indexing completed on 2022-05-04 02:52:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
0026
0027 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0028 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
0029 #include "DataFormats/Provenance/interface/EventID.h"
0030 #include "FWCore/Services/plugins/ProcInfoFetcher.h"
0031
0032 #include "DataFormats/Provenance/interface/ModuleDescription.h"
0033 #include "FWCore/Framework/interface/Event.h"
0034 #include "FWCore/MessageLogger/interface/JobReport.h"
0035 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0036 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0037 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0038 #include "FWCore/ServiceRegistry/interface/Service.h"
0039 #include "FWCore/ServiceRegistry/interface/StreamContext.h"
0040 #include "FWCore/ServiceRegistry/interface/ModuleCallingContext.h"
0041 #include "FWCore/Utilities/interface/Exception.h"
0042 #include "FWCore/Utilities/interface/get_underlying_safe.h"
0043
0044 #include <cstring>
0045 #include <iostream>
0046 #include <memory>
0047 #ifdef __linux__
0048 #include <malloc.h>
0049 #endif
0050 #include <sstream>
0051
0052 #include <string>
0053
0054
0055 #include <cstdio>
0056 #include <atomic>
0057
0058 namespace edm {
0059 class EventID;
0060 class Timestamp;
0061
0062 namespace service {
0063 struct smapsInfo {
0064 smapsInfo() : private_(), pss_() {}
0065 smapsInfo(double private_sz, double pss_sz) : private_(private_sz), pss_(pss_sz) {}
0066
0067 bool operator==(const smapsInfo& p) const { return private_ == p.private_ && pss_ == p.pss_; }
0068
0069 bool operator>(const smapsInfo& p) const { return private_ > p.private_ || pss_ > p.pss_; }
0070
0071 double private_;
0072 double pss_;
0073 };
0074
0075 class SimpleMemoryCheck {
0076 public:
0077 SimpleMemoryCheck(const ParameterSet&, ActivityRegistry&);
0078 ~SimpleMemoryCheck();
0079
0080 static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0081
0082 void preSourceConstruction(const ModuleDescription&);
0083 void postSourceConstruction(const ModuleDescription&);
0084 void postSourceEvent(StreamID);
0085
0086 void postBeginJob();
0087
0088 void postEvent(StreamContext const&);
0089
0090 void postModuleBeginJob(const ModuleDescription&);
0091 void postModuleConstruction(const ModuleDescription&);
0092
0093 void preModule(StreamContext const&, ModuleCallingContext const&);
0094 void postModule(StreamContext const&, ModuleCallingContext const&);
0095
0096 void postEndJob();
0097
0098 private:
0099 ProcInfo fetch();
0100 smapsInfo fetchSmaps();
0101 double pageSize() const { return pg_size_; }
0102 double averageGrowthRate(double current, double past, int count);
0103 void update();
0104 void updateMax();
0105 void andPrint(const std::string& type, const std::string& mdlabel, const std::string& mdname) const;
0106 void updateAndPrint(const std::string& type, const std::string& mdlabel, const std::string& mdname);
0107 void openFiles();
0108
0109 char const* smapsLineBuffer() const { return get_underlying_safe(smapsLineBuffer_); }
0110 char*& smapsLineBuffer() { return get_underlying_safe(smapsLineBuffer_); }
0111
0112 ProcInfo a_;
0113 ProcInfo b_;
0114 ProcInfo max_;
0115 edm::propagate_const<ProcInfo*> current_;
0116 edm::propagate_const<ProcInfo*> previous_;
0117
0118 smapsInfo currentSmaps_;
0119
0120 ProcInfoFetcher piFetcher_;
0121 double pg_size_;
0122 int num_to_skip_;
0123
0124 bool showMallocInfo_;
0125 bool oncePerEventMode_;
0126 bool jobReportOutputOnly_;
0127 bool monitorPssAndPrivate_;
0128 std::atomic<int> count_;
0129
0130
0131 edm::propagate_const<FILE*> smapsFile_;
0132 edm::propagate_const<char*> smapsLineBuffer_;
0133 size_t smapsLineBufferLen_;
0134
0135
0136 double growthRateVsize_;
0137 double growthRateRss_;
0138
0139
0140 struct SignificantEvent {
0141 int count;
0142 double vsize;
0143 double deltaVsize;
0144 double rss;
0145 double deltaRss;
0146 bool monitorPssAndPrivate;
0147 double privateSize;
0148 double pss;
0149 edm::EventID event;
0150 SignificantEvent()
0151 : count(0),
0152 vsize(0),
0153 deltaVsize(0),
0154 rss(0),
0155 deltaRss(0),
0156 monitorPssAndPrivate(false),
0157 privateSize(0),
0158 pss(0),
0159 event() {}
0160 void set(double deltaV, double deltaR, edm::EventID const& e, SimpleMemoryCheck* t) {
0161 count = t->count_;
0162 vsize = t->current_->vsize;
0163 deltaVsize = deltaV;
0164 rss = t->current_->rss;
0165 deltaRss = deltaR;
0166 monitorPssAndPrivate = t->monitorPssAndPrivate_;
0167 if (monitorPssAndPrivate) {
0168 privateSize = t->currentSmaps_.private_;
0169 pss = t->currentSmaps_.pss_;
0170 }
0171 event = e;
0172 }
0173 };
0174 friend struct SignificantEvent;
0175 friend std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se);
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 SignificantEvent eventM_;
0193 SignificantEvent eventL1_;
0194 SignificantEvent eventL2_;
0195 SignificantEvent eventR1_;
0196 SignificantEvent eventR2_;
0197 SignificantEvent eventT1_;
0198 SignificantEvent eventT2_;
0199 SignificantEvent eventT3_;
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 SignificantEvent eventRssT1_;
0214 SignificantEvent eventRssT2_;
0215 SignificantEvent eventRssT3_;
0216 SignificantEvent eventDeltaRssT1_;
0217 SignificantEvent eventDeltaRssT2_;
0218 SignificantEvent eventDeltaRssT3_;
0219
0220 void updateEventStats(edm::EventID const& e);
0221 std::string eventStatOutput(std::string title, SignificantEvent const& e) const;
0222 void eventStatOutput(std::string title, SignificantEvent const& e, std::map<std::string, std::string>& m) const;
0223 std::string mallOutput(std::string title, size_t const& n) const;
0224
0225
0226 struct SignificantModule {
0227 int postEarlyCount;
0228 double totalDeltaVsize;
0229 double maxDeltaVsize;
0230 edm::EventID eventMaxDeltaV;
0231 double totalEarlyVsize;
0232 double maxEarlyVsize;
0233 SignificantModule()
0234 : postEarlyCount(0),
0235 totalDeltaVsize(0),
0236 maxDeltaVsize(0),
0237 eventMaxDeltaV(),
0238 totalEarlyVsize(0),
0239 maxEarlyVsize(0) {}
0240 void set(double deltaV, bool early);
0241 };
0242 friend struct SignificantModule;
0243 friend std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& se);
0244 bool moduleSummaryRequested_;
0245 typedef std::map<std::string, SignificantModule> SignificantModulesMap;
0246 SignificantModulesMap modules_;
0247 double moduleEntryVsize_;
0248 void updateModuleMemoryStats(SignificantModule& m, double dv, edm::EventID const&);
0249
0250
0251 std::atomic<bool> measurementUnderway_;
0252 std::atomic<bool> moduleMeasurementUnderway_;
0253 std::atomic<unsigned int> moduleStreamID_;
0254 std::atomic<unsigned int> moduleID_;
0255
0256 };
0257
0258 std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se);
0259
0260 std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& se);
0261
0262 }
0263 }
0264
0265 #ifdef __linux__
0266 #define LINUX 1
0267 #endif
0268
0269 #include <fcntl.h>
0270 #include <unistd.h>
0271
0272 namespace edm {
0273 namespace service {
0274
0275 static std::string d2str(double d) {
0276 std::ostringstream t;
0277 t << d;
0278 return t.str();
0279 }
0280
0281 static std::string i2str(int i) {
0282 std::ostringstream t;
0283 t << i;
0284 return t.str();
0285 }
0286
0287 ProcInfo SimpleMemoryCheck::fetch() { return piFetcher_.fetch(); }
0288
0289 smapsInfo SimpleMemoryCheck::fetchSmaps() {
0290 smapsInfo ret;
0291 ret.private_ = 0;
0292 ret.pss_ = 0;
0293 #ifdef LINUX
0294 fseek(smapsFile_, 0, SEEK_SET);
0295 ssize_t read;
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 while ((read = getline(&smapsLineBuffer(), &smapsLineBufferLen_, smapsFile_)) != -1) {
0306 if (read > 14) {
0307
0308 if (0 == strncmp("Private_", smapsLineBuffer_, 8)) {
0309 unsigned int value = atoi(smapsLineBuffer_ + 14);
0310
0311 ret.private_ += static_cast<double>(value) / 1024.;
0312 } else if (0 == strncmp("Pss:", smapsLineBuffer_, 4)) {
0313 unsigned int value = atoi(smapsLineBuffer_ + 4);
0314
0315 ret.pss_ += static_cast<double>(value) / 1024.;
0316 }
0317 }
0318 }
0319 #endif
0320 return ret;
0321 }
0322
0323 double SimpleMemoryCheck::averageGrowthRate(double current, double past, int count) {
0324 return (current - past) / (double)count;
0325 }
0326
0327 SimpleMemoryCheck::SimpleMemoryCheck(ParameterSet const& iPS, ActivityRegistry& iReg)
0328 : a_(),
0329 b_(),
0330 current_(&a_),
0331 previous_(&b_),
0332 pg_size_(sysconf(_SC_PAGESIZE))
0333 ,
0334 num_to_skip_(iPS.getUntrackedParameter<int>("ignoreTotal")),
0335 showMallocInfo_(iPS.getUntrackedParameter<bool>("showMallocInfo")),
0336 oncePerEventMode_(iPS.getUntrackedParameter<bool>("oncePerEventMode")),
0337 jobReportOutputOnly_(iPS.getUntrackedParameter<bool>("jobReportOutputOnly")),
0338 monitorPssAndPrivate_(iPS.getUntrackedParameter<bool>("monitorPssAndPrivate")),
0339 count_(),
0340 smapsFile_(nullptr),
0341 smapsLineBuffer_(nullptr),
0342 smapsLineBufferLen_(0),
0343 growthRateVsize_(),
0344 growthRateRss_(),
0345 moduleSummaryRequested_(iPS.getUntrackedParameter<bool>("moduleMemorySummary")),
0346 measurementUnderway_(false) {
0347
0348
0349 std::ostringstream ost;
0350
0351 openFiles();
0352
0353 if (!oncePerEventMode_) {
0354 iReg.watchPreSourceConstruction(this, &SimpleMemoryCheck::preSourceConstruction);
0355 iReg.watchPostSourceConstruction(this, &SimpleMemoryCheck::postSourceConstruction);
0356 iReg.watchPostSourceEvent(this, &SimpleMemoryCheck::postSourceEvent);
0357 iReg.watchPostModuleConstruction(this, &SimpleMemoryCheck::postModuleConstruction);
0358 iReg.watchPostModuleBeginJob(this, &SimpleMemoryCheck::postModuleBeginJob);
0359 iReg.watchPostEvent(this, &SimpleMemoryCheck::postEvent);
0360 iReg.watchPostModuleEvent(this, &SimpleMemoryCheck::postModule);
0361 iReg.watchPostBeginJob(this, &SimpleMemoryCheck::postBeginJob);
0362 iReg.watchPostEndJob(this, &SimpleMemoryCheck::postEndJob);
0363 } else {
0364 iReg.watchPostEvent(this, &SimpleMemoryCheck::postEvent);
0365 iReg.watchPostEndJob(this, &SimpleMemoryCheck::postEndJob);
0366 }
0367 if (moduleSummaryRequested_) {
0368 iReg.watchPreModuleEvent(this, &SimpleMemoryCheck::preModule);
0369 if (oncePerEventMode_) {
0370 iReg.watchPostModuleEvent(this, &SimpleMemoryCheck::postModule);
0371 }
0372 }
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 }
0383
0384 SimpleMemoryCheck::~SimpleMemoryCheck() {
0385 #ifdef LINUX
0386 if (nullptr != smapsFile_) {
0387 fclose(smapsFile_);
0388 }
0389 #endif
0390 if (smapsLineBuffer_) {
0391
0392 free(smapsLineBuffer_);
0393 }
0394 }
0395
0396 void SimpleMemoryCheck::fillDescriptions(ConfigurationDescriptions& descriptions) {
0397 ParameterSetDescription desc;
0398 desc.addUntracked<int>("ignoreTotal", 1);
0399 desc.addUntracked<bool>("showMallocInfo", false);
0400 desc.addUntracked<bool>("oncePerEventMode", false);
0401 desc.addUntracked<bool>("jobReportOutputOnly", false);
0402 desc.addUntracked<bool>("monitorPssAndPrivate", false);
0403 desc.addUntracked<bool>("moduleMemorySummary", false);
0404 desc.addUntracked<bool>("dump", false);
0405 descriptions.add("SimpleMemoryCheck", desc);
0406 }
0407
0408 void SimpleMemoryCheck::openFiles() {
0409 #ifdef LINUX
0410 if (monitorPssAndPrivate_) {
0411 std::ostringstream smapsNameOst;
0412 smapsNameOst << "/proc/" << getpid() << "/smaps";
0413 if ((smapsFile_ = fopen(smapsNameOst.str().c_str(), "r")) == nullptr) {
0414 throw Exception(errors::Configuration) << "Failed to open smaps file " << smapsNameOst.str() << std::endl;
0415 }
0416 }
0417 #endif
0418 }
0419
0420 void SimpleMemoryCheck::postBeginJob() {
0421 growthRateVsize_ = current_->vsize;
0422 growthRateRss_ = current_->rss;
0423 }
0424
0425 void SimpleMemoryCheck::preSourceConstruction(ModuleDescription const& md) {
0426 bool expected = false;
0427 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0428 std::shared_ptr<void> guard(
0429 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0430 updateAndPrint("pre-ctor", md.moduleLabel(), md.moduleName());
0431 }
0432 }
0433
0434 void SimpleMemoryCheck::postSourceConstruction(ModuleDescription const& md) {
0435 bool expected = false;
0436 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0437 std::shared_ptr<void> guard(
0438 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0439 updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
0440 }
0441 }
0442
0443 void SimpleMemoryCheck::postSourceEvent(StreamID sid) {
0444 bool expected = false;
0445 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0446 std::shared_ptr<void> guard(
0447 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0448 updateAndPrint("module", "source", "source");
0449 }
0450 }
0451
0452 void SimpleMemoryCheck::postModuleConstruction(ModuleDescription const& md) {
0453 bool expected = false;
0454 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0455 std::shared_ptr<void> guard(
0456 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0457 updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
0458 }
0459 }
0460
0461 void SimpleMemoryCheck::postModuleBeginJob(ModuleDescription const& md) {
0462 bool expected = false;
0463 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0464 std::shared_ptr<void> guard(
0465 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0466 updateAndPrint("beginJob", md.moduleLabel(), md.moduleName());
0467 }
0468 }
0469
0470 void SimpleMemoryCheck::postEndJob() {
0471 if (not jobReportOutputOnly_) {
0472 LogAbsolute("MemoryReport")
0473 << "MemoryReport> Peak virtual size " << eventT1_.vsize << " Mbytes"
0474 << "\n"
0475 << " Key events increasing vsize: \n"
0476 << eventL2_ << "\n"
0477 << eventL1_ << "\n"
0478 << eventM_ << "\n"
0479 << eventR1_ << "\n"
0480 << eventR2_ << "\n"
0481 << eventT3_ << "\n"
0482 << eventT2_ << "\n"
0483 << eventT1_;
0484 }
0485 if (moduleSummaryRequested_ and not jobReportOutputOnly_) {
0486 LogAbsolute mmr("ModuleMemoryReport");
0487
0488
0489 mmr << "ModuleMemoryReport> Each line has module label and: \n";
0490 mmr << " (after early ignored events) \n";
0491 mmr << " count of times module executed; average increase in vsize \n";
0492 mmr << " maximum increase in vsize; event on which maximum occurred \n";
0493 mmr << " (during early ignored events) \n";
0494 mmr << " total and maximum vsize increases \n \n";
0495 for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
0496 SignificantModule const& m = im->second;
0497 if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
0498 continue;
0499 mmr << im->first << ": ";
0500 mmr << "n = " << m.postEarlyCount;
0501 if (m.postEarlyCount > 0) {
0502 mmr << " avg = " << m.totalDeltaVsize / m.postEarlyCount;
0503 }
0504 mmr << " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
0505 if (m.totalEarlyVsize > 0) {
0506 mmr << " early total: " << m.totalEarlyVsize;
0507 mmr << " max: " << m.maxEarlyVsize;
0508 }
0509 mmr << "\n";
0510 }
0511 }
0512
0513 Service<JobReport> reportSvc;
0514
0515 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
0516 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
0517
0518 std::map<std::string, std::string> reportData;
0519
0520 if (eventL2_.vsize > 0)
0521 eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
0522 if (eventL1_.vsize > 0)
0523 eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
0524 if (eventM_.vsize > 0)
0525 eventStatOutput("LargestVsizeIncreaseEvent", eventM_, reportData);
0526 if (eventR1_.vsize > 0)
0527 eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
0528 if (eventR2_.vsize > 0)
0529 eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
0530 if (eventT3_.vsize > 0)
0531 eventStatOutput("ThirdLargestVsizeEventT3", eventT3_, reportData);
0532 if (eventT2_.vsize > 0)
0533 eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
0534 if (eventT1_.vsize > 0)
0535 eventStatOutput("LargestVsizeEventT1", eventT1_, reportData);
0536
0537 if (eventRssT3_.rss > 0)
0538 eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
0539 if (eventRssT2_.rss > 0)
0540 eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
0541 if (eventRssT1_.rss > 0)
0542 eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
0543 if (eventDeltaRssT3_.deltaRss > 0)
0544 eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
0545 if (eventDeltaRssT2_.deltaRss > 0)
0546 eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
0547 if (eventDeltaRssT1_.deltaRss > 0)
0548 eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
0549
0550 #ifdef __linux__
0551 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
0552 struct mallinfo2 minfo = mallinfo2();
0553 #else
0554 struct mallinfo minfo = mallinfo();
0555 #endif
0556 reportData.insert(std::make_pair("HEAP_ARENA_SIZE_BYTES", std::to_string(minfo.arena)));
0557 reportData.insert(std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", std::to_string(minfo.ordblks)));
0558 reportData.insert(std::make_pair("HEAP_TOP_FREE_BYTES", std::to_string(minfo.keepcost)));
0559 reportData.insert(std::make_pair("HEAP_MAPPED_SIZE_BYTES", std::to_string(minfo.hblkhd)));
0560 reportData.insert(std::make_pair("HEAP_MAPPED_N_CHUNKS", std::to_string(minfo.hblks)));
0561 reportData.insert(std::make_pair("HEAP_USED_BYTES", std::to_string(minfo.uordblks)));
0562 reportData.insert(std::make_pair("HEAP_UNUSED_BYTES", std::to_string(minfo.fordblks)));
0563 #endif
0564
0565
0566 reportData.insert(std::make_pair("AverageGrowthRateVsize",
0567 d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
0568 reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
0569 reportData.insert(
0570 std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
0571 reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
0572
0573 if (moduleSummaryRequested_) {
0574 for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
0575 SignificantModule const& m = im->second;
0576 if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
0577 continue;
0578 std::string label = im->first + ":";
0579 reportData.insert(std::make_pair(label + "PostEarlyCount", i2str(m.postEarlyCount)));
0580 if (m.postEarlyCount > 0) {
0581 reportData.insert(std::make_pair(label + "AverageDeltaVsize", d2str(m.totalDeltaVsize / m.postEarlyCount)));
0582 }
0583 reportData.insert(std::make_pair(label + "MaxDeltaVsize", d2str(m.maxDeltaVsize)));
0584 if (m.totalEarlyVsize > 0) {
0585 reportData.insert(std::make_pair(label + "TotalEarlyVsize", d2str(m.totalEarlyVsize)));
0586 reportData.insert(std::make_pair(label + "MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
0587 }
0588 }
0589 }
0590
0591 std::map<std::string, std::string> reportMemoryProperties;
0592
0593 if (FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
0594 char buf[128];
0595 char space[] = " ";
0596 size_t value;
0597 while (fgets(buf, sizeof(buf), fmeminfo)) {
0598 char* saveptr;
0599 char* token = nullptr;
0600 token = strtok_r(buf, space, &saveptr);
0601 if (token != nullptr) {
0602 value = atol(strtok_r(nullptr, space, &saveptr));
0603 std::string category = token;
0604 reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token) - 1), i2str(value)));
0605 }
0606 }
0607
0608 fclose(fmeminfo);
0609 }
0610
0611
0612 reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
0613 reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
0614 #endif
0615
0616 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
0617 std::vector<std::string> reportData;
0618
0619 if (eventL2_.vsize > 0)
0620 reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
0621 if (eventL1_.vsize > 0)
0622 reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
0623 if (eventM_.vsize > 0)
0624 reportData.push_back(eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
0625 if (eventR1_.vsize > 0)
0626 reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
0627 if (eventR2_.vsize > 0)
0628 reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
0629 if (eventT3_.vsize > 0)
0630 reportData.push_back(eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
0631 if (eventT2_.vsize > 0)
0632 reportData.push_back(eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
0633 if (eventT1_.vsize > 0)
0634 reportData.push_back(eventStatOutput("LargestVsizeEventT1", eventT1_));
0635
0636 if (eventRssT3_.rss > 0)
0637 eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
0638 if (eventRssT2_.rss > 0)
0639 eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
0640 if (eventRssT1_.rss > 0)
0641 eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
0642 if (eventDeltaRssT3_.deltaRss > 0)
0643 eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
0644 if (eventDeltaRssT2_.deltaRss > 0)
0645 eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
0646 if (eventDeltaRssT1_.deltaRss > 0)
0647 eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
0648
0649 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
0650 struct mallinfo2 minfo = mallinfo2();
0651 #else
0652 struct mallinfo minfo = mallinfo();
0653 #endif
0654 reportData.push_back(mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
0655 reportData.push_back(mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
0656 reportData.push_back(mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
0657 reportData.push_back(mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
0658 reportData.push_back(mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
0659 reportData.push_back(mallOutput("HEAP_USED_BYTES", minfo.uordblks));
0660 reportData.push_back(mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
0661
0662
0663 reportData.insert(std::make_pair("AverageGrowthRateVsize",
0664 d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
0665 reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
0666 reportData.insert(
0667 std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
0668 reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
0669
0670 reportSvc->reportMemoryInfo(reportData);
0671
0672 #endif
0673 }
0674
0675 void SimpleMemoryCheck::postEvent(StreamContext const& iContext) {
0676 ++count_;
0677 bool expected = false;
0678 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0679 std::shared_ptr<void> guard(
0680 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0681 update();
0682 if (monitorPssAndPrivate_) {
0683 currentSmaps_ = fetchSmaps();
0684 }
0685 updateEventStats(iContext.eventID());
0686 if (oncePerEventMode_) {
0687
0688 updateMax();
0689 andPrint("event", "", "");
0690 }
0691 }
0692 }
0693
0694 void SimpleMemoryCheck::preModule(StreamContext const& iStreamContext, ModuleCallingContext const& iModuleContext) {
0695 bool expectedMeasurementUnderway = false;
0696 if (measurementUnderway_.compare_exchange_strong(expectedMeasurementUnderway, true, std::memory_order_acq_rel)) {
0697 std::shared_ptr<void> guard(
0698 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0699 bool expectedModuleMeasurementUnderway = false;
0700 if (moduleMeasurementUnderway_.compare_exchange_strong(expectedModuleMeasurementUnderway, true)) {
0701 update();
0702
0703 moduleEntryVsize_ = current_->vsize;
0704 moduleStreamID_.store(iStreamContext.streamID().value(), std::memory_order_release);
0705 moduleID_.store(iModuleContext.moduleDescription()->id(), std::memory_order_release);
0706 }
0707 }
0708 }
0709
0710 void SimpleMemoryCheck::postModule(StreamContext const& iStreamContext,
0711 ModuleCallingContext const& iModuleContext) {
0712 if (!oncePerEventMode_) {
0713 bool expected = false;
0714 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0715 std::shared_ptr<void> guard(
0716 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0717 auto const md = iModuleContext.moduleDescription();
0718 updateAndPrint("module", md->moduleLabel(), md->moduleName());
0719 }
0720 }
0721
0722 if (moduleSummaryRequested_) {
0723
0724 if (moduleMeasurementUnderway_.load(std::memory_order_acquire) and
0725 (iStreamContext.streamID().value() == moduleStreamID_.load(std::memory_order_acquire)) and
0726 (iModuleContext.moduleDescription()->id() == moduleID_.load(std::memory_order_acquire))) {
0727
0728 std::shared_ptr<void> guardModuleMeasurementUnderway(
0729 nullptr, [this](void const*) { moduleMeasurementUnderway_.store(false, std::memory_order_release); });
0730 bool expected = false;
0731 if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
0732 std::shared_ptr<void> guardMeasurementUnderway(
0733 nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
0734 if (oncePerEventMode_) {
0735 update();
0736 }
0737
0738 double dv = current_->vsize - moduleEntryVsize_;
0739 std::string label = iModuleContext.moduleDescription()->moduleLabel();
0740 updateModuleMemoryStats(modules_[label], dv, iStreamContext.eventID());
0741 }
0742 }
0743 }
0744 }
0745
0746 void SimpleMemoryCheck::update() {
0747 std::swap(current_, previous_);
0748 *current_ = fetch();
0749 }
0750
0751 void SimpleMemoryCheck::updateMax() {
0752 if ((*current_ > max_) || oncePerEventMode_) {
0753 if (count_ >= num_to_skip_) {
0754 }
0755 max_ = *current_;
0756 }
0757 }
0758
0759 void SimpleMemoryCheck::updateEventStats(EventID const& e) {
0760 if (count_ < num_to_skip_)
0761 return;
0762 if (count_ == num_to_skip_) {
0763 eventT1_.set(0, 0, e, this);
0764 eventM_.set(0, 0, e, this);
0765 eventRssT1_.set(0, 0, e, this);
0766 eventDeltaRssT1_.set(0, 0, e, this);
0767 return;
0768 }
0769 double vsize = current_->vsize;
0770 double deltaVsize = vsize - eventT1_.vsize;
0771
0772
0773 if (vsize > eventT1_.vsize) {
0774 double deltaRss = current_->rss - eventT1_.rss;
0775 eventT3_ = eventT2_;
0776 eventT2_ = eventT1_;
0777 eventT1_.set(deltaVsize, deltaRss, e, this);
0778 } else if (vsize > eventT2_.vsize) {
0779 double deltaRss = current_->rss - eventT1_.rss;
0780 eventT3_ = eventT2_;
0781 eventT2_.set(deltaVsize, deltaRss, e, this);
0782 } else if (vsize > eventT3_.vsize) {
0783 double deltaRss = current_->rss - eventT1_.rss;
0784 eventT3_.set(deltaVsize, deltaRss, e, this);
0785 }
0786
0787 if (deltaVsize > eventM_.deltaVsize) {
0788 double deltaRss = current_->rss - eventM_.rss;
0789 if (eventL1_.deltaVsize >= eventR1_.deltaVsize) {
0790 eventL2_ = eventL1_;
0791 } else {
0792 eventL2_ = eventR1_;
0793 }
0794 eventL1_ = eventM_;
0795 eventM_.set(deltaVsize, deltaRss, e, this);
0796 eventR1_ = SignificantEvent();
0797 eventR2_ = SignificantEvent();
0798 } else if (deltaVsize > eventR1_.deltaVsize) {
0799 double deltaRss = current_->rss - eventM_.rss;
0800 eventR2_ = eventR1_;
0801 eventR1_.set(deltaVsize, deltaRss, e, this);
0802 } else if (deltaVsize > eventR2_.deltaVsize) {
0803 double deltaRss = current_->rss - eventR1_.rss;
0804 eventR2_.set(deltaVsize, deltaRss, e, this);
0805 }
0806
0807
0808 double rss = current_->rss;
0809 double deltaRss = rss - eventRssT1_.rss;
0810
0811 if (rss > eventRssT1_.rss) {
0812 eventRssT3_ = eventRssT2_;
0813 eventRssT2_ = eventRssT1_;
0814 eventRssT1_.set(deltaVsize, deltaRss, e, this);
0815 } else if (rss > eventRssT2_.rss) {
0816 eventRssT3_ = eventRssT2_;
0817 eventRssT2_.set(deltaVsize, deltaRss, e, this);
0818 } else if (rss > eventRssT3_.rss) {
0819 eventRssT3_.set(deltaVsize, deltaRss, e, this);
0820 }
0821 if (deltaRss > eventDeltaRssT1_.deltaRss) {
0822 eventDeltaRssT3_ = eventDeltaRssT2_;
0823 eventDeltaRssT2_ = eventDeltaRssT1_;
0824 eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
0825 } else if (deltaRss > eventDeltaRssT2_.deltaRss) {
0826 eventDeltaRssT3_ = eventDeltaRssT2_;
0827 eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
0828 } else if (deltaRss > eventDeltaRssT3_.deltaRss) {
0829 eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
0830 }
0831 }
0832
0833 void SimpleMemoryCheck::andPrint(std::string const& type,
0834 std::string const& mdlabel,
0835 std::string const& mdname) const {
0836 if (not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
0837 if (count_ >= num_to_skip_) {
0838 double deltaVSIZE = current_->vsize - max_.vsize;
0839 double deltaRSS = current_->rss - max_.rss;
0840 if (!showMallocInfo_) {
0841 LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
0842 << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
0843 << deltaRSS;
0844 } else {
0845 #ifdef __linux__
0846 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
0847 struct mallinfo2 minfo = mallinfo2();
0848 #else
0849 struct mallinfo minfo = mallinfo();
0850 #endif
0851 #endif
0852 LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
0853 << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
0854 << deltaRSS
0855 #ifdef __linux__
0856 << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena << " N-UNUSED-CHUNKS "
0857 << minfo.ordblks << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
0858 << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd << " N-CHUNKS " << minfo.hblks
0859 << " ]"
0860 << " HEAP-USED-BYTES " << minfo.uordblks << " HEAP-UNUSED-BYTES "
0861 << minfo.fordblks
0862 #endif
0863 ;
0864 }
0865 }
0866 }
0867 }
0868
0869 void SimpleMemoryCheck::updateAndPrint(std::string const& type,
0870 std::string const& mdlabel,
0871 std::string const& mdname) {
0872 update();
0873 andPrint(type, mdlabel, mdname);
0874 updateMax();
0875 }
0876
0877 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
0878 void SimpleMemoryCheck::eventStatOutput(std::string title,
0879 SignificantEvent const& e,
0880 std::map<std::string, std::string>& m) const {
0881 {
0882 std::ostringstream os;
0883 os << title << "-a-COUNT";
0884 m.insert(std::make_pair(os.str(), i2str(e.count)));
0885 }
0886 {
0887 std::ostringstream os;
0888 os << title << "-b-RUN";
0889 m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run()))));
0890 }
0891 {
0892 std::ostringstream os;
0893 os << title << "-c-EVENT";
0894 m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event()))));
0895 }
0896 {
0897 std::ostringstream os;
0898 os << title << "-d-VSIZE";
0899 m.insert(std::make_pair(os.str(), d2str(e.vsize)));
0900 }
0901 {
0902 std::ostringstream os;
0903 os << title << "-e-DELTV";
0904 m.insert(std::make_pair(os.str(), d2str(e.deltaVsize)));
0905 }
0906 {
0907 std::ostringstream os;
0908 os << title << "-f-RSS";
0909 m.insert(std::make_pair(os.str(), d2str(e.rss)));
0910 }
0911 if (monitorPssAndPrivate_) {
0912 {
0913 std::ostringstream os;
0914 os << title << "-g-PRIVATE";
0915 m.insert(std::make_pair(os.str(), d2str(e.privateSize)));
0916 }
0917 {
0918 std::ostringstream os;
0919 os << title << "-h-PSS";
0920 m.insert(std::make_pair(os.str(), d2str(e.pss)));
0921 }
0922 }
0923 }
0924 #endif
0925
0926 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
0927 std::string SimpleMemoryCheck::eventStatOutput(std::string title, SignificantEvent const& e) const {
0928 std::ostringstream os;
0929 os << " <" << title << ">\n";
0930 os << " " << e.count << ": " << e.event;
0931 os << " vsize " << e.vsize - e.deltaVsize << " + " << e.deltaVsize << " = " << e.vsize;
0932 os << " rss: " << e.rss << "\n";
0933 os << " </" << title << ">\n";
0934 return os.str();
0935 }
0936
0937 std::string SimpleMemoryCheck::mallOutput(std::string title, size_t const& n) const {
0938 std::ostringstream os;
0939 os << " <" << title << ">\n";
0940 os << " " << n << "\n";
0941 os << " </" << title << ">\n";
0942 return os.str();
0943 }
0944 #endif
0945
0946 void SimpleMemoryCheck::updateModuleMemoryStats(SignificantModule& m,
0947 double dv,
0948 edm::EventID const& currentEventID) {
0949 if (count_ < num_to_skip_) {
0950 m.totalEarlyVsize += dv;
0951 if (dv > m.maxEarlyVsize)
0952 m.maxEarlyVsize = dv;
0953 } else {
0954 ++m.postEarlyCount;
0955 m.totalDeltaVsize += dv;
0956 if (dv > m.maxDeltaVsize) {
0957 m.maxDeltaVsize = dv;
0958 m.eventMaxDeltaV = currentEventID;
0959 }
0960 }
0961 }
0962
0963 std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se) {
0964 os << "[" << se.count << "] " << se.event << " vsize = " << se.vsize << " deltaVsize = " << se.deltaVsize
0965 << " rss = " << se.rss << " delta = " << se.deltaRss;
0966
0967 if (se.monitorPssAndPrivate) {
0968 os << " private = " << se.privateSize << " pss = " << se.pss;
0969 }
0970 return os;
0971 }
0972
0973 std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& sm) {
0974 if (sm.postEarlyCount > 0) {
0975 os << "\nPost Early Events: TotalDeltaVsize: " << sm.totalDeltaVsize
0976 << " (avg: " << sm.totalDeltaVsize / sm.postEarlyCount << "; max: " << sm.maxDeltaVsize << " during "
0977 << sm.eventMaxDeltaV << ")";
0978 }
0979 if (sm.totalEarlyVsize > 0) {
0980 os << "\n Early Events: TotalDeltaVsize: " << sm.totalEarlyVsize << " (max: " << sm.maxEarlyVsize << ")";
0981 }
0982
0983 return os;
0984 }
0985
0986 }
0987 }
0988
0989 #if defined(__linux__)
0990 using edm::service::SimpleMemoryCheck;
0991 DEFINE_FWK_SERVICE(SimpleMemoryCheck);
0992 #endif