CMS 3D CMS Logo

SimpleMemoryCheck.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Services
4 // Class : Memory
5 //
6 // Implementation:
7 //
8 // Original Author: Jim Kowalkowski
9 //
10 // Change Log
11 //
12 // 1 - Apr 25, 2008 M. Fischler
13 // Collect event summary information and output to XML file and logger
14 // at the end of the job. Involves split-up of updateAndPrint method.
15 //
16 // 2 - May 7, 2008 M. Fischler
17 // Collect module summary information and output to XML file and logger
18 // at the end of the job.
19 //
20 // 3 - Jan 14, 2009 Natalia Garcia Nebot
21 // Added: - Average rate of growth in RSS and peak value attained.
22 // - Average rate of growth in VSize over time, Peak VSize
23 //
24 //
26 
31 
43 
44 #include <cstring>
45 #include <iostream>
46 #include <memory>
47 #ifdef __linux__
48 #include <malloc.h>
49 #endif
50 #include <sstream>
51 //#include <stdio.h>
52 #include <string>
53 //#include <string.h>
54 
55 #include <cstdio>
56 #include <atomic>
57 
58 namespace edm {
59  namespace service {
60  struct smapsInfo {
61  smapsInfo() : private_(), pss_() {}
62  smapsInfo(double private_sz, double pss_sz) : private_(private_sz), pss_(pss_sz) {}
63 
64  bool operator==(const smapsInfo& p) const { return private_ == p.private_ && pss_ == p.pss_; }
65 
66  bool operator>(const smapsInfo& p) const { return private_ > p.private_ || pss_ > p.pss_; }
67 
68  double private_; // in MB
69  double pss_; // in MB
70  };
71 
73  public:
76 
77  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
78 
82 
83  void postBeginJob();
84 
85  void postEvent(StreamContext const&);
86 
89 
90  void preModule(StreamContext const&, ModuleCallingContext const&);
91  void postModule(StreamContext const&, ModuleCallingContext const&);
92 
93  void postEndJob();
94 
95  void startSamplingThread();
96  void stopSamplingThread();
97 
98  private:
99  ProcInfo fetch();
101  double pageSize() const { return pg_size_; }
102  double averageGrowthRate(double current, double past, int count);
103  void update();
104  void updateMax();
105  void andPrint(const std::string& type, const std::string& mdlabel, const std::string& mdname) const;
106  void updateAndPrint(const std::string& type, const std::string& mdlabel, const std::string& mdname);
107  void openFiles();
108 
109  char const* smapsLineBuffer() const { return get_underlying_safe(smapsLineBuffer_); }
111 
117 
119 
121  double pg_size_;
123  //options
129  std::atomic<int> count_;
130  unsigned int sampleEveryNSeconds_;
131  std::optional<std::thread> samplingThread_;
132  std::atomic<bool> stopThread_ = false;
133  std::atomic<edm::EventID> mostRecentlyStartedEvent_;
134 
135  //smaps
139 
140  //Rates of growth
143 
144  // Event summary statistics changeLog 1
146  int count;
147  double vsize;
148  double deltaVsize;
149  double rss;
150  double deltaRss;
152  double privateSize;
153  double pss;
156  : count(0),
157  vsize(0),
158  deltaVsize(0),
159  rss(0),
160  deltaRss(0),
162  privateSize(0),
163  pss(0),
164  event() {}
165  void set(double deltaV, double deltaR, edm::EventID const& e, SimpleMemoryCheck* t) {
166  count = t->count_;
167  vsize = t->current_->vsize;
168  deltaVsize = deltaV;
169  rss = t->current_->rss;
170  deltaRss = deltaR;
171  monitorPssAndPrivate = t->monitorPssAndPrivate_;
172  if (monitorPssAndPrivate) {
173  privateSize = t->currentSmaps_.private_;
174  pss = t->currentSmaps_.pss_;
175  }
176  event = e;
177  }
178  }; // SignificantEvent
179  friend struct SignificantEvent;
180  friend std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se);
181 
182  /*
183  Significative events for deltaVsize:
184  - eventM_: Event which makes the biggest value for deltaVsize
185  - eventL1_: Event which makes the second biggest value for deltaVsize
186  - eventL2_: Event which makes the third biggest value for deltaVsize
187  - eventR1_: Event which makes the second biggest value for deltaVsize
188  - eventR2_: Event which makes the third biggest value for deltaVsize
189  M>L1>L2 and M>R1>R2
190  Unknown relation between Ls and Rs events ???????
191  Significative events for vsize:
192  - eventT1_: Event whith the biggest value for vsize
193  - eventT2_: Event whith the second biggest value for vsize
194  - eventT3_: Event whith the third biggest value for vsize
195  T1>T2>T3
196  */
205 
206  /*
207  Significative event for deltaRss:
208  - eventRssT1_: Event whith the biggest value for rss
209  - eventRssT2_: Event whith the second biggest value for rss
210  - eventRssT3_: Event whith the third biggest value for rss
211  T1>T2>T3
212  Significative events for deltaRss:
213  - eventDeltaRssT1_: Event whith the biggest value for deltaRss
214  - eventDeltaRssT2_: Event whith the second biggest value for deltaRss
215  - eventDeltaRssT3_: Event whith the third biggest value for deltaRss
216  T1>T2>T3
217  */
224 
225  void updateEventStats(edm::EventID const& e);
227  void eventStatOutput(std::string title, SignificantEvent const& e, std::map<std::string, std::string>& m) const;
228  std::string mallOutput(std::string title, size_t const& n) const;
229 
230  // Module summary statistices
239  : postEarlyCount(0),
240  totalDeltaVsize(0),
241  maxDeltaVsize(0),
242  eventMaxDeltaV(),
243  totalEarlyVsize(0),
244  maxEarlyVsize(0) {}
245  void set(double deltaV, bool early);
246  }; // SignificantModule
247  friend struct SignificantModule;
248  friend std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& se);
250  typedef std::map<std::string, SignificantModule> SignificantModulesMap;
253  void updateModuleMemoryStats(SignificantModule& m, double dv, edm::EventID const&);
254 
255  //Used to guarantee we only do one measurement at a time
256  std::atomic<bool> measurementUnderway_;
257  std::atomic<bool> moduleMeasurementUnderway_;
258  std::atomic<unsigned int> moduleStreamID_;
259  std::atomic<unsigned int> moduleID_;
260 
261  }; // SimpleMemoryCheck
262 
263  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se);
264 
265  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& se);
266 
267  } // namespace service
268 } // namespace edm
269 
270 #ifdef __linux__
271 #define LINUX 1
272 #endif
273 
274 #include <fcntl.h>
275 #include <unistd.h>
276 
277 namespace edm {
278  namespace service {
279 
280  static std::string d2str(double d) {
281  std::ostringstream t;
282  t << d;
283  return t.str();
284  }
285 
286  static std::string i2str(int i) {
287  std::ostringstream t;
288  t << i;
289  return t.str();
290  }
291 
293 
295  smapsInfo ret;
296  ret.private_ = 0;
297  ret.pss_ = 0;
298 #ifdef LINUX
299  fseek(smapsFile_, 0, SEEK_SET);
300  ssize_t read;
301 
302  /*
303  The format of the report is
304  Private_Clean: 0 kB
305  Private_Dirty: 72 kB
306  Swap: 0 kB
307  Pss: 72 kB
308  */
309 
310  while ((read = getline(&smapsLineBuffer(), &smapsLineBufferLen_, smapsFile_)) != -1) {
311  if (read > 14) {
312  //Private
313  if (0 == strncmp("Private_", smapsLineBuffer_, 8)) {
314  unsigned int value = atoi(smapsLineBuffer_ + 14);
315  //Convert from kB to MB
316  ret.private_ += static_cast<double>(value) / 1024.;
317  } else if (0 == strncmp("Pss:", smapsLineBuffer_, 4)) {
318  unsigned int value = atoi(smapsLineBuffer_ + 4);
319  //Convert from kB to MB
320  ret.pss_ += static_cast<double>(value) / 1024.;
321  }
322  }
323  }
324 #endif
325  return ret;
326  }
327 
328  double SimpleMemoryCheck::averageGrowthRate(double current, double past, int count) {
329  return (current - past) / (double)count;
330  }
331 
333  : a_(),
334  b_(),
335  current_(&a_),
336  previous_(&b_),
337  pg_size_(sysconf(_SC_PAGESIZE)) // getpagesize()
338  ,
339  num_to_skip_(iPS.getUntrackedParameter<int>("ignoreTotal")),
340  showMallocInfo_(iPS.getUntrackedParameter<bool>("showMallocInfo")),
341  oncePerEventMode_(iPS.getUntrackedParameter<bool>("oncePerEventMode")),
342  printEachTime_(oncePerEventMode_ or iPS.getUntrackedParameter<bool>("printEachSample")),
343  jobReportOutputOnly_(iPS.getUntrackedParameter<bool>("jobReportOutputOnly")),
344  monitorPssAndPrivate_(iPS.getUntrackedParameter<bool>("monitorPssAndPrivate")),
345  count_(),
346  sampleEveryNSeconds_(iPS.getUntrackedParameter<unsigned int>("sampleEveryNSeconds")),
347  smapsFile_(nullptr),
348  smapsLineBuffer_(nullptr),
349  smapsLineBufferLen_(0),
350  growthRateVsize_(),
351  growthRateRss_(),
352  moduleSummaryRequested_(iPS.getUntrackedParameter<bool>("moduleMemorySummary")),
353  measurementUnderway_(false) {
354  // changelog 2
355  // pg_size = (double)getpagesize();
356  std::ostringstream ost;
357 
358  openFiles();
359 
360  if (sampleEveryNSeconds_ > 0) {
361  if (oncePerEventMode_) {
363  << "'sampleEventNSeconds' and 'oncePerEventMode' cannot be used together";
364  }
367  << "'sampleEventNSeconds' and 'moduleSummaryRequested' cannot be used together";
368  }
372  iReg.watchPreEvent([this](auto const& iContext) { mostRecentlyStartedEvent_.store(iContext.eventID()); });
373  return;
374  }
375 
376  if (!oncePerEventMode_) { // default, prints on increases
386  } else {
389  }
390  if (moduleSummaryRequested_) { // changelog 2
392  if (oncePerEventMode_) {
394  }
395  }
396 
397  // The following are not currenty used/implemented below for either
398  // of the print modes (but are left here for reference)
399  // iReg.watchPostBeginJob(this,
400  // &SimpleMemoryCheck::postBeginJob);
401  // iReg.watchPreProcessEvent(this,
402  // &SimpleMemoryCheck::preEventProcessing);
403  // iReg.watchPreModule(this,
404  // &SimpleMemoryCheck::preModule);
405  }
406 
408 #ifdef LINUX
409  if (nullptr != smapsFile_) {
410  fclose(smapsFile_);
411  }
412 #endif
413  if (smapsLineBuffer_) {
414  //getline will create the memory using malloc
416  }
417  }
418 
421  desc.addUntracked<int>("ignoreTotal", 1)
422  ->setComment("Number of events/samples to finish before starting measuring and reporting.");
423  desc.addUntracked<unsigned int>("sampleEveryNSeconds", 0)
424  ->setComment(
425  "Use a special thread to sample memory at the set rate. A value of 0 means no sampling. This option "
426  "cannot be used with 'oncePerEventMode' or 'moduleMemorySummary'.");
427  desc.addUntracked<bool>("printEachSample", false)
428  ->setComment("If sampling on, print each sample taken else will print only when sample is the largest seen.");
429  desc.addUntracked<bool>("showMallocInfo", false);
430  desc.addUntracked<bool>("oncePerEventMode", false)
431  ->setComment(
432  "Only check memory at the end of each event. Not as useful in multi-threaded job as other running events "
433  "contribute.");
434  desc.addUntracked<bool>("jobReportOutputOnly", false);
435  desc.addUntracked<bool>("monitorPssAndPrivate", false);
436  desc.addUntracked<bool>("moduleMemorySummary", false)
437  ->setComment(
438  "Track significant memory events for each module. This does not work well in multi-threaded jobs.");
439  descriptions.add("SimpleMemoryCheck", desc);
440  }
441 
443 #ifdef LINUX
444  if (monitorPssAndPrivate_) {
445  std::ostringstream smapsNameOst;
446  smapsNameOst << "/proc/" << getpid() << "/smaps";
447  if ((smapsFile_ = fopen(smapsNameOst.str().c_str(), "r")) == nullptr) {
448  throw Exception(errors::Configuration) << "Failed to open smaps file " << smapsNameOst.str() << std::endl;
449  }
450  }
451 #endif
452  }
453 
455  growthRateVsize_ = current_->vsize;
456  growthRateRss_ = current_->rss;
457  }
458 
460  bool expected = false;
461  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
462  std::shared_ptr<void> guard(
463  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
464  updateAndPrint("pre-ctor", md.moduleLabel(), md.moduleName());
465  }
466  }
467 
469  bool expected = false;
470  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
471  std::shared_ptr<void> guard(
472  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
473  updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
474  }
475  }
476 
478  bool expected = false;
479  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
480  std::shared_ptr<void> guard(
481  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
482  updateAndPrint("module", "source", "source");
483  }
484  }
485 
487  bool expected = false;
488  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
489  std::shared_ptr<void> guard(
490  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
491  updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
492  }
493  }
494 
496  bool expected = false;
497  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
498  std::shared_ptr<void> guard(
499  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
500  updateAndPrint("beginJob", md.moduleLabel(), md.moduleName());
501  }
502  }
503 
505  samplingThread_ = std::thread{[this]() {
506  while (not stopThread_) {
507  std::this_thread::sleep_for(std::chrono::duration<unsigned int>(sampleEveryNSeconds_));
508  ++count_;
509  update();
510  if (monitorPssAndPrivate_) {
512  }
513  auto e = mostRecentlyStartedEvent_.load();
514  andPrint("sampling", "", "");
516  updateMax();
517  }
518  }};
519  }
521  stopThread_ = true;
522  samplingThread_->join();
523  }
524 
526  if (not jobReportOutputOnly_) {
527  LogAbsolute("MemoryReport") // changelog 1
528  << "MemoryReport> Peak virtual size " << eventT1_.vsize << " Mbytes"
529  << "\n"
530  << " Key events increasing vsize: \n"
531  << eventL2_ << "\n"
532  << eventL1_ << "\n"
533  << eventM_ << "\n"
534  << eventR1_ << "\n"
535  << eventR2_ << "\n"
536  << eventT3_ << "\n"
537  << eventT2_ << "\n"
538  << eventT1_ << "\nMemoryReport> Peak rss size " << eventRssT1_.rss
539  << " Mbytes"
540  "\n Key events increasing rss:\n"
541  << eventRssT3_ << "\n"
542  << eventRssT2_ << "\n"
543  << eventRssT1_ << "\n"
544  << eventDeltaRssT3_ << "\n"
545  << eventDeltaRssT2_ << "\n"
546  << eventDeltaRssT1_;
547  ;
548  }
549  if (moduleSummaryRequested_ and not jobReportOutputOnly_) { // changelog 1
550  LogAbsolute mmr("ModuleMemoryReport"); // at end of if block, mmr
551  // is destructed, causing
552  // message to be logged
553  mmr << "ModuleMemoryReport> Each line has module label and: \n";
554  mmr << " (after early ignored events) \n";
555  mmr << " count of times module executed; average increase in vsize \n";
556  mmr << " maximum increase in vsize; event on which maximum occurred \n";
557  mmr << " (during early ignored events) \n";
558  mmr << " total and maximum vsize increases \n \n";
559  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
560  SignificantModule const& m = im->second;
561  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
562  continue;
563  mmr << im->first << ": ";
564  mmr << "n = " << m.postEarlyCount;
565  if (m.postEarlyCount > 0) {
566  mmr << " avg = " << m.totalDeltaVsize / m.postEarlyCount;
567  }
568  mmr << " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
569  if (m.totalEarlyVsize > 0) {
570  mmr << " early total: " << m.totalEarlyVsize;
571  mmr << " max: " << m.maxEarlyVsize;
572  }
573  mmr << "\n";
574  }
575  } // end of if; mmr goes out of scope; log message is queued
576 
577  Service<JobReport> reportSvc;
578  // changelog 1
579 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
580 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
581  // std::map<std::string, double> reportData;
582  std::map<std::string, std::string> reportData;
583 
584  if (eventL2_.vsize > 0)
585  eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
586  if (eventL1_.vsize > 0)
587  eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
588  if (eventM_.vsize > 0)
589  eventStatOutput("LargestVsizeIncreaseEvent", eventM_, reportData);
590  if (eventR1_.vsize > 0)
591  eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
592  if (eventR2_.vsize > 0)
593  eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
594  if (eventT3_.vsize > 0)
595  eventStatOutput("ThirdLargestVsizeEventT3", eventT3_, reportData);
596  if (eventT2_.vsize > 0)
597  eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
598  if (eventT1_.vsize > 0)
599  eventStatOutput("LargestVsizeEventT1", eventT1_, reportData);
600 
601  if (eventRssT3_.rss > 0)
602  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
603  if (eventRssT2_.rss > 0)
604  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
605  if (eventRssT1_.rss > 0)
606  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
607  if (eventDeltaRssT3_.deltaRss > 0)
608  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
609  if (eventDeltaRssT2_.deltaRss > 0)
610  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
611  if (eventDeltaRssT1_.deltaRss > 0)
612  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
613 
614 #ifdef __linux__
615 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
616  struct mallinfo2 minfo = mallinfo2();
617 #else
618  struct mallinfo minfo = mallinfo();
619 #endif
620  reportData.insert(std::make_pair("HEAP_ARENA_SIZE_BYTES", std::to_string(minfo.arena)));
621  reportData.insert(std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", std::to_string(minfo.ordblks)));
622  reportData.insert(std::make_pair("HEAP_TOP_FREE_BYTES", std::to_string(minfo.keepcost)));
623  reportData.insert(std::make_pair("HEAP_MAPPED_SIZE_BYTES", std::to_string(minfo.hblkhd)));
624  reportData.insert(std::make_pair("HEAP_MAPPED_N_CHUNKS", std::to_string(minfo.hblks)));
625  reportData.insert(std::make_pair("HEAP_USED_BYTES", std::to_string(minfo.uordblks)));
626  reportData.insert(std::make_pair("HEAP_UNUSED_BYTES", std::to_string(minfo.fordblks)));
627 #endif
628 
629  // Report Growth rates for VSize and Rss
630  reportData.insert(std::make_pair("AverageGrowthRateVsize",
632  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
633  reportData.insert(
634  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
635  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
636 
637  if (moduleSummaryRequested_) { // changelog 2
638  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
639  SignificantModule const& m = im->second;
640  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
641  continue;
642  std::string label = im->first + ":";
643  reportData.insert(std::make_pair(label + "PostEarlyCount", i2str(m.postEarlyCount)));
644  if (m.postEarlyCount > 0) {
645  reportData.insert(std::make_pair(label + "AverageDeltaVsize", d2str(m.totalDeltaVsize / m.postEarlyCount)));
646  }
647  reportData.insert(std::make_pair(label + "MaxDeltaVsize", d2str(m.maxDeltaVsize)));
648  if (m.totalEarlyVsize > 0) {
649  reportData.insert(std::make_pair(label + "TotalEarlyVsize", d2str(m.totalEarlyVsize)));
650  reportData.insert(std::make_pair(label + "MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
651  }
652  }
653  }
654 
655  std::map<std::string, std::string> reportMemoryProperties;
656 
657  if (FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
658  char buf[128];
659  char space[] = " ";
660  size_t value;
661  while (fgets(buf, sizeof(buf), fmeminfo)) {
662  char* saveptr;
663  char* token = nullptr;
664  token = strtok_r(buf, space, &saveptr);
665  if (token != nullptr) {
666  value = atol(strtok_r(nullptr, space, &saveptr));
668  reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token) - 1), i2str(value)));
669  }
670  }
671 
672  fclose(fmeminfo);
673  }
674 
675  // reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
676  reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
677  reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
678 #endif
679 
680 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
681  std::vector<std::string> reportData;
682 
683  if (eventL2_.vsize > 0)
684  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
685  if (eventL1_.vsize > 0)
686  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
687  if (eventM_.vsize > 0)
688  reportData.push_back(eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
689  if (eventR1_.vsize > 0)
690  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
691  if (eventR2_.vsize > 0)
692  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
693  if (eventT3_.vsize > 0)
694  reportData.push_back(eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
695  if (eventT2_.vsize > 0)
696  reportData.push_back(eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
697  if (eventT1_.vsize > 0)
698  reportData.push_back(eventStatOutput("LargestVsizeEventT1", eventT1_));
699 
700  if (eventRssT3_.rss > 0)
701  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
702  if (eventRssT2_.rss > 0)
703  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
704  if (eventRssT1_.rss > 0)
705  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
706  if (eventDeltaRssT3_.deltaRss > 0)
707  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
708  if (eventDeltaRssT2_.deltaRss > 0)
709  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
710  if (eventDeltaRssT1_.deltaRss > 0)
711  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
712 
713 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
714  struct mallinfo2 minfo = mallinfo2();
715 #else
716  struct mallinfo minfo = mallinfo();
717 #endif
718  reportData.push_back(mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
719  reportData.push_back(mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
720  reportData.push_back(mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
721  reportData.push_back(mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
722  reportData.push_back(mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
723  reportData.push_back(mallOutput("HEAP_USED_BYTES", minfo.uordblks));
724  reportData.push_back(mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
725 
726  // Report Growth rates for VSize and Rss
727  reportData.insert(std::make_pair("AverageGrowthRateVsize",
729  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
730  reportData.insert(
731  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
732  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
733 
734  reportSvc->reportMemoryInfo(reportData);
735  // This is a form of reportMemoryInfo taking s vector, not a map
736 #endif
737  } // postEndJob
738 
740  ++count_;
741  bool expected = false;
742  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
743  std::shared_ptr<void> guard(
744  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
745  update();
746  if (monitorPssAndPrivate_) {
748  }
749  updateEventStats(iContext.eventID());
750  if (oncePerEventMode_) {
751  // should probably use be Run:Event or count_ for the label and name
752  updateMax();
753  andPrint("event", "", "");
754  }
755  }
756  }
757 
758  void SimpleMemoryCheck::preModule(StreamContext const& iStreamContext, ModuleCallingContext const& iModuleContext) {
759  bool expectedMeasurementUnderway = false;
760  if (measurementUnderway_.compare_exchange_strong(expectedMeasurementUnderway, true, std::memory_order_acq_rel)) {
761  std::shared_ptr<void> guard(
762  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
763  bool expectedModuleMeasurementUnderway = false;
764  if (moduleMeasurementUnderway_.compare_exchange_strong(expectedModuleMeasurementUnderway, true)) {
765  update();
766  // changelog 2
767  moduleEntryVsize_ = current_->vsize;
768  moduleStreamID_.store(iStreamContext.streamID().value(), std::memory_order_release);
769  moduleID_.store(iModuleContext.moduleDescription()->id(), std::memory_order_release);
770  }
771  }
772  }
773 
774  void SimpleMemoryCheck::postModule(StreamContext const& iStreamContext,
775  ModuleCallingContext const& iModuleContext) {
776  if (!oncePerEventMode_) {
777  bool expected = false;
778  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
779  std::shared_ptr<void> guard(
780  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
781  auto const md = iModuleContext.moduleDescription();
782  updateAndPrint("module", md->moduleLabel(), md->moduleName());
783  }
784  }
785 
787  //is this the module instance we are measuring?
788  if (moduleMeasurementUnderway_.load(std::memory_order_acquire) and
789  (iStreamContext.streamID().value() == moduleStreamID_.load(std::memory_order_acquire)) and
790  (iModuleContext.moduleDescription()->id() == moduleID_.load(std::memory_order_acquire))) {
791  //Need to release our module measurement lock
792  std::shared_ptr<void> guardModuleMeasurementUnderway(
793  nullptr, [this](void const*) { moduleMeasurementUnderway_.store(false, std::memory_order_release); });
794  bool expected = false;
795  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
796  std::shared_ptr<void> guardMeasurementUnderway(
797  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
798  if (oncePerEventMode_) {
799  update();
800  }
801  // changelog 2
802  double dv = current_->vsize - moduleEntryVsize_;
803  std::string label = iModuleContext.moduleDescription()->moduleLabel();
804  updateModuleMemoryStats(modules_[label], dv, iStreamContext.eventID());
805  }
806  }
807  }
808  }
809 
812  *current_ = fetch();
813  }
814 
816  auto v = *current_;
817  if ((v > max_) || oncePerEventMode_) {
818  if (max_.vsize < v.vsize) {
819  max_.vsize = v.vsize;
820  }
821  if (max_.rss < v.rss) {
822  max_.rss = v.rss;
823  }
824  }
825  }
826 
828  if (count_ < num_to_skip_)
829  return;
830  if (count_ == num_to_skip_) {
831  eventT1_.set(0, 0, e, this);
832  eventM_.set(0, 0, e, this);
833  eventRssT1_.set(0, 0, e, this);
834  eventDeltaRssT1_.set(0, 0, e, this);
835  return;
836  }
837  double vsize = current_->vsize;
838  double deltaVsize = vsize - eventT1_.vsize;
839 
840  // Update significative events for Vsize
841  if (vsize > eventT1_.vsize) {
842  double deltaRss = current_->rss - eventT1_.rss;
843  eventT3_ = eventT2_;
844  eventT2_ = eventT1_;
845  eventT1_.set(deltaVsize, deltaRss, e, this);
846  } else if (vsize > eventT2_.vsize) {
847  double deltaRss = current_->rss - eventT1_.rss;
848  eventT3_ = eventT2_;
849  eventT2_.set(deltaVsize, deltaRss, e, this);
850  } else if (vsize > eventT3_.vsize) {
851  double deltaRss = current_->rss - eventT1_.rss;
852  eventT3_.set(deltaVsize, deltaRss, e, this);
853  }
854 
855  if (deltaVsize > eventM_.deltaVsize) {
856  double deltaRss = current_->rss - eventM_.rss;
858  eventL2_ = eventL1_;
859  } else {
860  eventL2_ = eventR1_;
861  }
862  eventL1_ = eventM_;
863  eventM_.set(deltaVsize, deltaRss, e, this);
866  } else if (deltaVsize > eventR1_.deltaVsize) {
867  double deltaRss = current_->rss - eventM_.rss;
868  eventR2_ = eventR1_;
869  eventR1_.set(deltaVsize, deltaRss, e, this);
870  } else if (deltaVsize > eventR2_.deltaVsize) {
871  double deltaRss = current_->rss - eventR1_.rss;
872  eventR2_.set(deltaVsize, deltaRss, e, this);
873  }
874 
875  // Update significative events for Rss
876  double rss = current_->rss;
877  double deltaRss = rss - eventRssT1_.rss;
878 
879  if (rss > eventRssT1_.rss) {
882  eventRssT1_.set(deltaVsize, deltaRss, e, this);
883  } else if (rss > eventRssT2_.rss) {
885  eventRssT2_.set(deltaVsize, deltaRss, e, this);
886  } else if (rss > eventRssT3_.rss) {
887  eventRssT3_.set(deltaVsize, deltaRss, e, this);
888  }
889  if (deltaRss > eventDeltaRssT1_.deltaRss) {
892  eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
893  } else if (deltaRss > eventDeltaRssT2_.deltaRss) {
895  eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
896  } else if (deltaRss > eventDeltaRssT3_.deltaRss) {
897  eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
898  }
899  } // updateEventStats
900 
902  std::string const& mdlabel,
903  std::string const& mdname) const {
904  if (not jobReportOutputOnly_ && ((*current_ > max_) || printEachTime_)) {
905  if (count_ >= num_to_skip_) {
906  double deltaVSIZE = current_->vsize - max_.vsize;
907  double deltaRSS = current_->rss - max_.rss;
908  if (!showMallocInfo_) { // default
909  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
910  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
911  << deltaRSS;
912  } else {
913 #ifdef __linux__
914 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
915  struct mallinfo2 minfo = mallinfo2();
916 #else
917  struct mallinfo minfo = mallinfo();
918 #endif
919 #endif
920  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
921  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
922  << deltaRSS
923 #ifdef __linux__
924  << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena << " N-UNUSED-CHUNKS "
925  << minfo.ordblks << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
926  << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd << " N-CHUNKS " << minfo.hblks
927  << " ]"
928  << " HEAP-USED-BYTES " << minfo.uordblks << " HEAP-UNUSED-BYTES "
929  << minfo.fordblks
930 #endif
931  ;
932  }
933  }
934  }
935  }
936 
938  std::string const& mdlabel,
939  std::string const& mdname) {
940  update();
941  andPrint(type, mdlabel, mdname);
942  updateMax();
943  }
944 
945 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
947  SignificantEvent const& e,
948  std::map<std::string, std::string>& m) const {
949  {
950  std::ostringstream os;
951  os << title << "-a-COUNT";
952  m.insert(std::make_pair(os.str(), i2str(e.count)));
953  }
954  {
955  std::ostringstream os;
956  os << title << "-b-RUN";
957  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run()))));
958  }
959  {
960  std::ostringstream os;
961  os << title << "-c-EVENT";
962  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event()))));
963  }
964  {
965  std::ostringstream os;
966  os << title << "-d-VSIZE";
967  m.insert(std::make_pair(os.str(), d2str(e.vsize)));
968  }
969  {
970  std::ostringstream os;
971  os << title << "-e-DELTV";
972  m.insert(std::make_pair(os.str(), d2str(e.deltaVsize)));
973  }
974  {
975  std::ostringstream os;
976  os << title << "-f-RSS";
977  m.insert(std::make_pair(os.str(), d2str(e.rss)));
978  }
979  if (monitorPssAndPrivate_) {
980  {
981  std::ostringstream os;
982  os << title << "-g-PRIVATE";
983  m.insert(std::make_pair(os.str(), d2str(e.privateSize)));
984  }
985  {
986  std::ostringstream os;
987  os << title << "-h-PSS";
988  m.insert(std::make_pair(os.str(), d2str(e.pss)));
989  }
990  }
991  } // eventStatOutput
992 #endif
993 
994 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
995  std::string SimpleMemoryCheck::eventStatOutput(std::string title, SignificantEvent const& e) const {
996  std::ostringstream os;
997  os << " <" << title << ">\n";
998  os << " " << e.count << ": " << e.event;
999  os << " vsize " << e.vsize - e.deltaVsize << " + " << e.deltaVsize << " = " << e.vsize;
1000  os << " rss: " << e.rss << "\n";
1001  os << " </" << title << ">\n";
1002  return os.str();
1003  } // eventStatOutput
1004 
1006  std::ostringstream os;
1007  os << " <" << title << ">\n";
1008  os << " " << n << "\n";
1009  os << " </" << title << ">\n";
1010  return os.str();
1011  }
1012 #endif
1013  // changelog 2
1015  double dv,
1016  edm::EventID const& currentEventID) {
1017  if (count_ < num_to_skip_) {
1018  m.totalEarlyVsize += dv;
1019  if (dv > m.maxEarlyVsize)
1020  m.maxEarlyVsize = dv;
1021  } else {
1022  ++m.postEarlyCount;
1023  m.totalDeltaVsize += dv;
1024  if (dv > m.maxDeltaVsize) {
1025  m.maxDeltaVsize = dv;
1026  m.eventMaxDeltaV = currentEventID;
1027  }
1028  }
1029  } //updateModuleMemoryStats
1030 
1031  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se) {
1032  os << "[" << se.count << "] " << se.event << " vsize = " << se.vsize << " deltaVsize = " << se.deltaVsize
1033  << " rss = " << se.rss << " delta = " << se.deltaRss;
1034 
1035  if (se.monitorPssAndPrivate) {
1036  os << " private = " << se.privateSize << " pss = " << se.pss;
1037  }
1038  return os;
1039  }
1040 
1041  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& sm) {
1042  if (sm.postEarlyCount > 0) {
1043  os << "\nPost Early Events: TotalDeltaVsize: " << sm.totalDeltaVsize
1044  << " (avg: " << sm.totalDeltaVsize / sm.postEarlyCount << "; max: " << sm.maxDeltaVsize << " during "
1045  << sm.eventMaxDeltaV << ")";
1046  }
1047  if (sm.totalEarlyVsize > 0) {
1048  os << "\n Early Events: TotalDeltaVsize: " << sm.totalEarlyVsize << " (max: " << sm.maxEarlyVsize << ")";
1049  }
1050 
1051  return os;
1052  }
1053 
1054  } // end namespace service
1055 } // end namespace edm
1056 
1057 #if defined(__linux__)
1060 #endif
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
static std::string i2str(int i)
void watchPreEvent(PreEvent::slot_type const &iSlot)
void preSourceConstruction(const ModuleDescription &)
std::pair< ALIstring, ALIstring > pss
Definition: Fit.h:25
std::atomic< edm::EventID > mostRecentlyStartedEvent_
friend std::ostream & operator<<(std::ostream &os, SimpleMemoryCheck::SignificantEvent const &se)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
edm::propagate_const< ProcInfo * > current_
std::atomic< bool > measurementUnderway_
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void updateEventStats(edm::EventID const &e)
ret
prodAgent to be discontinued
void watchPostEvent(PostEvent::slot_type const &iSlot)
std::atomic< bool > moduleMeasurementUnderway_
std::string eventStatOutput(std::string title, SignificantEvent const &e) const
void watchPreSourceConstruction(PreSourceConstruction::slot_type const &iSlot)
void watchPostSourceConstruction(PostSourceConstruction::slot_type const &iSlot)
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
void watchPostSourceEvent(PostSourceEvent::slot_type const &iSlot)
std::string const & moduleName() const
constexpr std::shared_ptr< T > & get_underlying_safe(propagate_const< std::shared_ptr< T >> &iP)
ModuleDescription const * moduleDescription() const noexcept
void swap(Association< C > &lhs, Association< C > &rhs)
Definition: Association.h:112
static std::string to_string(const XMLCh *ch)
std::atomic< unsigned int > moduleStreamID_
void free(void *ptr) noexcept
char const * label
unsigned int id() const
edm::propagate_const< FILE * > smapsFile_
std::map< std::string, SignificantModule > SignificantModulesMap
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
StreamID const & streamID() const
Definition: StreamContext.h:55
bool operator==(const smapsInfo &p) const
Definition: value.py:1
std::ostream & operator<<(std::ostream &os, SimpleMemoryCheck::SignificantEvent const &se)
void set(double deltaV, double deltaR, edm::EventID const &e, SimpleMemoryCheck *t)
edm::propagate_const< ProcInfo * > previous_
d
Definition: ztail.py:151
smapsInfo(double private_sz, double pss_sz)
#define DEFINE_FWK_SERVICE(type)
Definition: ServiceMaker.h:97
void updateAndPrint(const std::string &type, const std::string &mdlabel, const std::string &mdname)
void andPrint(const std::string &type, const std::string &mdlabel, const std::string &mdname) const
void preModule(StreamContext const &, ModuleCallingContext const &)
char const * smapsLineBuffer() const
std::optional< std::thread > samplingThread_
static std::string d2str(double d)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void updateModuleMemoryStats(SignificantModule &m, double dv, edm::EventID const &)
void watchPreEndJob(PreEndJob::slot_type const &iSlot)
void postEvent(StreamContext const &)
HLT enums.
edm::propagate_const< char * > smapsLineBuffer_
EventID const & eventID() const
Definition: StreamContext.h:60
void watchPostModuleBeginJob(PostModuleBeginJob::slot_type const &iSlot)
void postSourceConstruction(const ModuleDescription &)
Log< level::System, true > LogAbsolute
void postModuleBeginJob(const ModuleDescription &)
unsigned int value() const
Definition: StreamID.h:43
std::string mallOutput(std::string title, size_t const &n) const
double averageGrowthRate(double current, double past, int count)
Log< level::Warning, false > LogWarning
SimpleMemoryCheck(const ParameterSet &, ActivityRegistry &)
bool operator>(const smapsInfo &p) const
void postModule(StreamContext const &, ModuleCallingContext const &)
std::string const & moduleLabel() const
void postModuleConstruction(const ModuleDescription &)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: event.py:1
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal
std::atomic< unsigned int > moduleID_