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 
44 
45 #include <cstring>
46 #include <iostream>
47 #include <memory>
48 #ifdef __linux__
49 #include <malloc.h>
50 #endif
51 #include <sstream>
52 //#include <stdio.h>
53 #include <string>
54 //#include <string.h>
55 #include <boost/lexical_cast.hpp>
56 
57 #include <cstdio>
58 #include <atomic>
59 
60 namespace edm {
61  class EventID;
62  class Timestamp;
63 
64  namespace service {
65  struct smapsInfo {
66  smapsInfo() : private_(), pss_() {}
67  smapsInfo(double private_sz, double pss_sz) : private_(private_sz), pss_(pss_sz) {}
68 
69  bool operator==(const smapsInfo& p) const { return private_ == p.private_ && pss_ == p.pss_; }
70 
71  bool operator>(const smapsInfo& p) const { return private_ > p.private_ || pss_ > p.pss_; }
72 
73  double private_; // in MB
74  double pss_; // in MB
75  };
76 
78  public:
81 
82  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
83 
84  void preSourceConstruction(const ModuleDescription&);
85  void postSourceConstruction(const ModuleDescription&);
86  void postSourceEvent(StreamID);
87 
88  void postBeginJob();
89 
90  void postEvent(StreamContext const&);
91 
92  void postModuleBeginJob(const ModuleDescription&);
93  void postModuleConstruction(const ModuleDescription&);
94 
95  void preModule(StreamContext const&, ModuleCallingContext const&);
96  void postModule(StreamContext const&, ModuleCallingContext const&);
97 
98  void postEndJob();
99 
100  private:
101  ProcInfo fetch();
102  smapsInfo fetchSmaps();
103  double pageSize() const { return pg_size_; }
104  double averageGrowthRate(double current, double past, int count);
105  void update();
106  void updateMax();
107  void andPrint(const std::string& type, const std::string& mdlabel, const std::string& mdname) const;
108  void updateAndPrint(const std::string& type, const std::string& mdlabel, const std::string& mdname);
109  void openFiles();
110 
111  char const* smapsLineBuffer() const { return get_underlying_safe(smapsLineBuffer_); }
112  char*& smapsLineBuffer() { return get_underlying_safe(smapsLineBuffer_); }
113 
119 
121 
123  double pg_size_;
125  //options
130  std::atomic<int> count_;
131 
132  //smaps
136 
137  //Rates of growth
140 
141  // Event summary statistics changeLog 1
143  int count;
144  double vsize;
145  double deltaVsize;
146  double rss;
147  double deltaRss;
149  double privateSize;
150  double pss;
153  : count(0),
154  vsize(0),
155  deltaVsize(0),
156  rss(0),
157  deltaRss(0),
158  monitorPssAndPrivate(false),
159  privateSize(0),
160  pss(0),
161  event() {}
162  void set(double deltaV, double deltaR, edm::EventID const& e, SimpleMemoryCheck* t) {
163  count = t->count_;
164  vsize = t->current_->vsize;
165  deltaVsize = deltaV;
166  rss = t->current_->rss;
167  deltaRss = deltaR;
168  monitorPssAndPrivate = t->monitorPssAndPrivate_;
169  if (monitorPssAndPrivate) {
170  privateSize = t->currentSmaps_.private_;
171  pss = t->currentSmaps_.pss_;
172  }
173  event = e;
174  }
175  }; // SignificantEvent
176  friend struct SignificantEvent;
177  friend std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se);
178 
179  /*
180  Significative events for deltaVsize:
181  - eventM_: Event which makes the biggest value for deltaVsize
182  - eventL1_: Event which makes the second biggest value for deltaVsize
183  - eventL2_: Event which makes the third biggest value for deltaVsize
184  - eventR1_: Event which makes the second biggest value for deltaVsize
185  - eventR2_: Event which makes the third biggest value for deltaVsize
186  M>L1>L2 and M>R1>R2
187  Unknown relation between Ls and Rs events ???????
188  Significative events for vsize:
189  - eventT1_: Event whith the biggest value for vsize
190  - eventT2_: Event whith the second biggest value for vsize
191  - eventT3_: Event whith the third biggest value for vsize
192  T1>T2>T3
193  */
202 
203  /*
204  Significative event for deltaRss:
205  - eventRssT1_: Event whith the biggest value for rss
206  - eventRssT2_: Event whith the second biggest value for rss
207  - eventRssT3_: Event whith the third biggest value for rss
208  T1>T2>T3
209  Significative events for deltaRss:
210  - eventDeltaRssT1_: Event whith the biggest value for deltaRss
211  - eventDeltaRssT2_: Event whith the second biggest value for deltaRss
212  - eventDeltaRssT3_: Event whith the third biggest value for deltaRss
213  T1>T2>T3
214  */
221 
222  void updateEventStats(edm::EventID const& e);
223  std::string eventStatOutput(std::string title, SignificantEvent const& e) const;
224  void eventStatOutput(std::string title, SignificantEvent const& e, std::map<std::string, std::string>& m) const;
225  std::string mallOutput(std::string title, size_t const& n) const;
226 
227  // Module summary statistices
236  : postEarlyCount(0),
237  totalDeltaVsize(0),
238  maxDeltaVsize(0),
239  eventMaxDeltaV(),
240  totalEarlyVsize(0),
241  maxEarlyVsize(0) {}
242  void set(double deltaV, bool early);
243  }; // SignificantModule
244  friend struct SignificantModule;
245  friend std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& se);
247  typedef std::map<std::string, SignificantModule> SignificantModulesMap;
248  SignificantModulesMap modules_;
250  void updateModuleMemoryStats(SignificantModule& m, double dv, edm::EventID const&);
251 
252  //Used to guarantee we only do one measurement at a time
253  std::atomic<bool> measurementUnderway_;
254  std::atomic<bool> moduleMeasurementUnderway_;
255  std::atomic<unsigned int> moduleStreamID_;
256  std::atomic<unsigned int> moduleID_;
257 
258  }; // SimpleMemoryCheck
259 
260  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se);
261 
262  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& se);
263 
264  } // namespace service
265 } // namespace edm
266 
267 #ifdef __linux__
268 #define LINUX 1
269 #endif
270 
271 #include <fcntl.h>
272 #include <unistd.h>
273 
274 namespace edm {
275  namespace service {
276 
277  static std::string d2str(double d) {
278  std::ostringstream t;
279  t << d;
280  return t.str();
281  }
282 
283  static std::string i2str(int i) {
284  std::ostringstream t;
285  t << i;
286  return t.str();
287  }
288 
289  ProcInfo SimpleMemoryCheck::fetch() { return piFetcher_.fetch(); }
290 
292  smapsInfo ret;
293  ret.private_ = 0;
294  ret.pss_ = 0;
295 #ifdef LINUX
296  fseek(smapsFile_, 0, SEEK_SET);
297  ssize_t read;
298 
299  /*
300  The format of the report is
301  Private_Clean: 0 kB
302  Private_Dirty: 72 kB
303  Swap: 0 kB
304  Pss: 72 kB
305  */
306 
307  while ((read = getline(&smapsLineBuffer(), &smapsLineBufferLen_, smapsFile_)) != -1) {
308  if (read > 14) {
309  //Private
310  if (0 == strncmp("Private_", smapsLineBuffer_, 8)) {
311  unsigned int value = atoi(smapsLineBuffer_ + 14);
312  //Convert from kB to MB
313  ret.private_ += static_cast<double>(value) / 1024.;
314  } else if (0 == strncmp("Pss:", smapsLineBuffer_, 4)) {
315  unsigned int value = atoi(smapsLineBuffer_ + 4);
316  //Convert from kB to MB
317  ret.pss_ += static_cast<double>(value) / 1024.;
318  }
319  }
320  }
321 #endif
322  return ret;
323  }
324 
325  double SimpleMemoryCheck::averageGrowthRate(double current, double past, int count) {
326  return (current - past) / (double)count;
327  }
328 
330  : a_(),
331  b_(),
332  current_(&a_),
333  previous_(&b_),
334  pg_size_(sysconf(_SC_PAGESIZE)) // getpagesize()
335  ,
336  num_to_skip_(iPS.getUntrackedParameter<int>("ignoreTotal")),
337  showMallocInfo_(iPS.getUntrackedParameter<bool>("showMallocInfo")),
338  oncePerEventMode_(iPS.getUntrackedParameter<bool>("oncePerEventMode")),
339  jobReportOutputOnly_(iPS.getUntrackedParameter<bool>("jobReportOutputOnly")),
340  monitorPssAndPrivate_(iPS.getUntrackedParameter<bool>("monitorPssAndPrivate")),
341  count_(),
342  smapsFile_(nullptr),
343  smapsLineBuffer_(nullptr),
344  smapsLineBufferLen_(0),
345  growthRateVsize_(),
346  growthRateRss_(),
347  moduleSummaryRequested_(iPS.getUntrackedParameter<bool>("moduleMemorySummary")),
348  measurementUnderway_(false) {
349  // changelog 2
350  // pg_size = (double)getpagesize();
351  std::ostringstream ost;
352 
353  openFiles();
354 
355  if (!oncePerEventMode_) { // default, prints on increases
365  } else {
368  }
369  if (moduleSummaryRequested_) { // changelog 2
371  if (oncePerEventMode_) {
373  }
374  }
375 
376  // The following are not currenty used/implemented below for either
377  // of the print modes (but are left here for reference)
378  // iReg.watchPostBeginJob(this,
379  // &SimpleMemoryCheck::postBeginJob);
380  // iReg.watchPreProcessEvent(this,
381  // &SimpleMemoryCheck::preEventProcessing);
382  // iReg.watchPreModule(this,
383  // &SimpleMemoryCheck::preModule);
384 
385 #ifndef __SANITIZE_ADDRESS__
386  typedef MallocOpts::opt_type opt_type;
388 
389  opt_type p_mmap_max = iPS.getUntrackedParameter<int>("M_MMAP_MAX"),
390  p_trim_thr = iPS.getUntrackedParameter<int>("M_TRIM_THRESHOLD"),
391  p_top_pad = iPS.getUntrackedParameter<int>("M_TOP_PAD"),
392  p_mmap_thr = iPS.getUntrackedParameter<int>("M_MMAP_THRESHOLD");
393 
394  if (p_mmap_max >= 0)
395  mopts.set_mmap_max(p_mmap_max);
396  if (p_trim_thr >= 0)
397  mopts.set_trim_thr(p_trim_thr);
398  if (p_top_pad >= 0)
399  mopts.set_top_pad(p_top_pad);
400  if (p_mmap_thr >= 0)
401  mopts.set_mmap_thr(p_mmap_thr);
402 
403  mopts.adjustMallocParams();
404 
405  if (mopts.hasErrors()) {
406  LogWarning("MemoryCheck") << "ERROR: Problem with setting malloc options\n" << mopts.error_message();
407  }
408 
409  if (iPS.getUntrackedParameter<bool>("dump") == true) {
410  MallocOpts mo = mopts.get();
411  LogWarning("MemoryCheck") << "Malloc options: " << mo << "\n";
412  }
413 #endif
414  }
415 
417 #ifdef LINUX
418  if (nullptr != smapsFile_) {
419  fclose(smapsFile_);
420  }
421 #endif
422  if (smapsLineBuffer_) {
423  //getline will create the memory using malloc
424  free(smapsLineBuffer_);
425  }
426  }
427 
430  desc.addUntracked<int>("ignoreTotal", 1);
431  desc.addUntracked<bool>("showMallocInfo", false);
432  desc.addUntracked<bool>("oncePerEventMode", false);
433  desc.addUntracked<bool>("jobReportOutputOnly", false);
434  desc.addUntracked<bool>("monitorPssAndPrivate", false);
435  desc.addUntracked<bool>("moduleMemorySummary", false);
436  desc.addUntracked<int>("M_MMAP_MAX", -1);
437  desc.addUntracked<int>("M_TRIM_THRESHOLD", -1);
438  desc.addUntracked<int>("M_TOP_PAD", -1);
439  desc.addUntracked<int>("M_MMAP_THRESHOLD", -1);
440  desc.addUntracked<bool>("dump", false);
441  descriptions.add("SimpleMemoryCheck", desc);
442  }
443 
445 #ifdef LINUX
446  if (monitorPssAndPrivate_) {
447  std::ostringstream smapsNameOst;
448  smapsNameOst << "/proc/" << getpid() << "/smaps";
449  if ((smapsFile_ = fopen(smapsNameOst.str().c_str(), "r")) == nullptr) {
450  throw Exception(errors::Configuration) << "Failed to open smaps file " << smapsNameOst.str() << std::endl;
451  }
452  }
453 #endif
454  }
455 
457  growthRateVsize_ = current_->vsize;
458  growthRateRss_ = current_->rss;
459  }
460 
462  bool expected = false;
463  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
464  std::shared_ptr<void> guard(
465  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
466  updateAndPrint("pre-ctor", md.moduleLabel(), md.moduleName());
467  }
468  }
469 
471  bool expected = false;
472  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
473  std::shared_ptr<void> guard(
474  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
475  updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
476  }
477  }
478 
480  bool expected = false;
481  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
482  std::shared_ptr<void> guard(
483  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
484  updateAndPrint("module", "source", "source");
485  }
486  }
487 
489  bool expected = false;
490  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
491  std::shared_ptr<void> guard(
492  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
493  updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
494  }
495  }
496 
498  bool expected = false;
499  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
500  std::shared_ptr<void> guard(
501  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
502  updateAndPrint("beginJob", md.moduleLabel(), md.moduleName());
503  }
504  }
505 
507  if (not jobReportOutputOnly_) {
508  LogAbsolute("MemoryReport") // changelog 1
509  << "MemoryReport> Peak virtual size " << eventT1_.vsize << " Mbytes"
510  << "\n"
511  << " Key events increasing vsize: \n"
512  << eventL2_ << "\n"
513  << eventL1_ << "\n"
514  << eventM_ << "\n"
515  << eventR1_ << "\n"
516  << eventR2_ << "\n"
517  << eventT3_ << "\n"
518  << eventT2_ << "\n"
519  << eventT1_;
520  }
521  if (moduleSummaryRequested_ and not jobReportOutputOnly_) { // changelog 1
522  LogAbsolute mmr("ModuleMemoryReport"); // at end of if block, mmr
523  // is destructed, causing
524  // message to be logged
525  mmr << "ModuleMemoryReport> Each line has module label and: \n";
526  mmr << " (after early ignored events) \n";
527  mmr << " count of times module executed; average increase in vsize \n";
528  mmr << " maximum increase in vsize; event on which maximum occurred \n";
529  mmr << " (during early ignored events) \n";
530  mmr << " total and maximum vsize increases \n \n";
531  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
532  SignificantModule const& m = im->second;
533  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
534  continue;
535  mmr << im->first << ": ";
536  mmr << "n = " << m.postEarlyCount;
537  if (m.postEarlyCount > 0) {
538  mmr << " avg = " << m.totalDeltaVsize / m.postEarlyCount;
539  }
540  mmr << " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
541  if (m.totalEarlyVsize > 0) {
542  mmr << " early total: " << m.totalEarlyVsize;
543  mmr << " max: " << m.maxEarlyVsize;
544  }
545  mmr << "\n";
546  }
547  } // end of if; mmr goes out of scope; log message is queued
548 
549  Service<JobReport> reportSvc;
550  // changelog 1
551 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
552 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
553  // std::map<std::string, double> reportData;
554  std::map<std::string, std::string> reportData;
555 
556  if (eventL2_.vsize > 0)
557  eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
558  if (eventL1_.vsize > 0)
559  eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
560  if (eventM_.vsize > 0)
561  eventStatOutput("LargestVsizeIncreaseEvent", eventM_, reportData);
562  if (eventR1_.vsize > 0)
563  eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
564  if (eventR2_.vsize > 0)
565  eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
566  if (eventT3_.vsize > 0)
567  eventStatOutput("ThirdLargestVsizeEventT3", eventT3_, reportData);
568  if (eventT2_.vsize > 0)
569  eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
570  if (eventT1_.vsize > 0)
571  eventStatOutput("LargestVsizeEventT1", eventT1_, reportData);
572 
573  if (eventRssT3_.rss > 0)
574  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
575  if (eventRssT2_.rss > 0)
576  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
577  if (eventRssT1_.rss > 0)
578  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
579  if (eventDeltaRssT3_.deltaRss > 0)
580  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
581  if (eventDeltaRssT2_.deltaRss > 0)
582  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
583  if (eventDeltaRssT1_.deltaRss > 0)
584  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
585 
586 #ifdef __linux__
587  struct mallinfo minfo = mallinfo();
588  reportData.insert(std::make_pair("HEAP_ARENA_SIZE_BYTES", i2str(minfo.arena)));
589  reportData.insert(std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", i2str(minfo.ordblks)));
590  reportData.insert(std::make_pair("HEAP_TOP_FREE_BYTES", i2str(minfo.keepcost)));
591  reportData.insert(std::make_pair("HEAP_MAPPED_SIZE_BYTES", i2str(minfo.hblkhd)));
592  reportData.insert(std::make_pair("HEAP_MAPPED_N_CHUNKS", i2str(minfo.hblks)));
593  reportData.insert(std::make_pair("HEAP_USED_BYTES", i2str(minfo.uordblks)));
594  reportData.insert(std::make_pair("HEAP_UNUSED_BYTES", i2str(minfo.fordblks)));
595 #endif
596 
597  // Report Growth rates for VSize and Rss
598  reportData.insert(std::make_pair("AverageGrowthRateVsize",
600  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
601  reportData.insert(
602  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
603  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
604 
605  if (moduleSummaryRequested_) { // changelog 2
606  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
607  SignificantModule const& m = im->second;
608  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
609  continue;
610  std::string label = im->first + ":";
611  reportData.insert(std::make_pair(label + "PostEarlyCount", i2str(m.postEarlyCount)));
612  if (m.postEarlyCount > 0) {
613  reportData.insert(std::make_pair(label + "AverageDeltaVsize", d2str(m.totalDeltaVsize / m.postEarlyCount)));
614  }
615  reportData.insert(std::make_pair(label + "MaxDeltaVsize", d2str(m.maxDeltaVsize)));
616  if (m.totalEarlyVsize > 0) {
617  reportData.insert(std::make_pair(label + "TotalEarlyVsize", d2str(m.totalEarlyVsize)));
618  reportData.insert(std::make_pair(label + "MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
619  }
620  }
621  }
622 
623  std::map<std::string, std::string> reportMemoryProperties;
624 
625  if (FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
626  char buf[128];
627  char space[] = " ";
628  size_t value;
629  while (fgets(buf, sizeof(buf), fmeminfo)) {
630  char* saveptr;
631  char* token = nullptr;
632  token = strtok_r(buf, space, &saveptr);
633  if (token != nullptr) {
634  value = atol(strtok_r(nullptr, space, &saveptr));
635  std::string category = token;
636  reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token) - 1), i2str(value)));
637  }
638  }
639 
640  fclose(fmeminfo);
641  }
642 
643  // reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
644  reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
645  reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
646 #endif
647 
648 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
649  std::vector<std::string> reportData;
650 
651  if (eventL2_.vsize > 0)
652  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
653  if (eventL1_.vsize > 0)
654  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
655  if (eventM_.vsize > 0)
656  reportData.push_back(eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
657  if (eventR1_.vsize > 0)
658  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
659  if (eventR2_.vsize > 0)
660  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
661  if (eventT3_.vsize > 0)
662  reportData.push_back(eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
663  if (eventT2_.vsize > 0)
664  reportData.push_back(eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
665  if (eventT1_.vsize > 0)
666  reportData.push_back(eventStatOutput("LargestVsizeEventT1", eventT1_));
667 
668  if (eventRssT3_.rss > 0)
669  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
670  if (eventRssT2_.rss > 0)
671  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
672  if (eventRssT1_.rss > 0)
673  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
674  if (eventDeltaRssT3_.deltaRss > 0)
675  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
676  if (eventDeltaRssT2_.deltaRss > 0)
677  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
678  if (eventDeltaRssT1_.deltaRss > 0)
679  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
680 
681  struct mallinfo minfo = mallinfo();
682  reportData.push_back(mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
683  reportData.push_back(mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
684  reportData.push_back(mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
685  reportData.push_back(mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
686  reportData.push_back(mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
687  reportData.push_back(mallOutput("HEAP_USED_BYTES", minfo.uordblks));
688  reportData.push_back(mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
689 
690  // Report Growth rates for VSize and Rss
691  reportData.insert(std::make_pair("AverageGrowthRateVsize",
693  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
694  reportData.insert(
695  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
696  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
697 
698  reportSvc->reportMemoryInfo(reportData);
699  // This is a form of reportMemoryInfo taking s vector, not a map
700 #endif
701  } // postEndJob
702 
704  ++count_;
705  bool expected = false;
706  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
707  std::shared_ptr<void> guard(
708  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
709  update();
710  if (monitorPssAndPrivate_) {
712  }
713  updateEventStats(iContext.eventID());
714  if (oncePerEventMode_) {
715  // should probably use be Run:Event or count_ for the label and name
716  updateMax();
717  andPrint("event", "", "");
718  }
719  }
720  }
721 
722  void SimpleMemoryCheck::preModule(StreamContext const& iStreamContext, ModuleCallingContext const& iModuleContext) {
723  bool expected = false;
724  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
725  std::shared_ptr<void> guard(
726  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
727  bool expected = false;
728  if (moduleMeasurementUnderway_.compare_exchange_strong(expected, true)) {
729  update();
730  // changelog 2
731  moduleEntryVsize_ = current_->vsize;
732  moduleStreamID_.store(iStreamContext.streamID().value(), std::memory_order_release);
733  moduleID_.store(iModuleContext.moduleDescription()->id(), std::memory_order_release);
734  }
735  }
736  }
737 
738  void SimpleMemoryCheck::postModule(StreamContext const& iStreamContext,
739  ModuleCallingContext const& iModuleContext) {
740  if (!oncePerEventMode_) {
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  auto const md = iModuleContext.moduleDescription();
746  updateAndPrint("module", md->moduleLabel(), md->moduleName());
747  }
748  }
749 
751  //is this the module instance we are measuring?
752  if (moduleMeasurementUnderway_.load(std::memory_order_acquire) and
753  (iStreamContext.streamID().value() == moduleStreamID_.load(std::memory_order_acquire)) and
754  (iModuleContext.moduleDescription()->id() == moduleID_.load(std::memory_order_acquire))) {
755  //Need to release our module measurement lock
756  std::shared_ptr<void> guard(
757  nullptr, [this](void const*) { moduleMeasurementUnderway_.store(false, std::memory_order_release); });
758  bool expected = false;
759  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
760  std::shared_ptr<void> guard(
761  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
762  if (oncePerEventMode_) {
763  update();
764  }
765  // changelog 2
766  double dv = current_->vsize - moduleEntryVsize_;
767  std::string label = iModuleContext.moduleDescription()->moduleLabel();
768  updateModuleMemoryStats(modules_[label], dv, iStreamContext.eventID());
769  }
770  }
771  }
772  }
773 
776  *current_ = fetch();
777  }
778 
780  if ((*current_ > max_) || oncePerEventMode_) {
781  if (count_ >= num_to_skip_) {
782  }
783  max_ = *current_;
784  }
785  }
786 
788  if (count_ < num_to_skip_)
789  return;
790  if (count_ == num_to_skip_) {
791  eventT1_.set(0, 0, e, this);
792  eventM_.set(0, 0, e, this);
793  eventRssT1_.set(0, 0, e, this);
794  eventDeltaRssT1_.set(0, 0, e, this);
795  return;
796  }
797  double vsize = current_->vsize;
798  double deltaVsize = vsize - eventT1_.vsize;
799 
800  // Update significative events for Vsize
801  if (vsize > eventT1_.vsize) {
802  double deltaRss = current_->rss - eventT1_.rss;
803  eventT3_ = eventT2_;
804  eventT2_ = eventT1_;
805  eventT1_.set(deltaVsize, deltaRss, e, this);
806  } else if (vsize > eventT2_.vsize) {
807  double deltaRss = current_->rss - eventT1_.rss;
808  eventT3_ = eventT2_;
809  eventT2_.set(deltaVsize, deltaRss, e, this);
810  } else if (vsize > eventT3_.vsize) {
811  double deltaRss = current_->rss - eventT1_.rss;
812  eventT3_.set(deltaVsize, deltaRss, e, this);
813  }
814 
815  if (deltaVsize > eventM_.deltaVsize) {
816  double deltaRss = current_->rss - eventM_.rss;
818  eventL2_ = eventL1_;
819  } else {
820  eventL2_ = eventR1_;
821  }
822  eventL1_ = eventM_;
823  eventM_.set(deltaVsize, deltaRss, e, this);
826  } else if (deltaVsize > eventR1_.deltaVsize) {
827  double deltaRss = current_->rss - eventM_.rss;
828  eventR2_ = eventR1_;
829  eventR1_.set(deltaVsize, deltaRss, e, this);
830  } else if (deltaVsize > eventR2_.deltaVsize) {
831  double deltaRss = current_->rss - eventR1_.rss;
832  eventR2_.set(deltaVsize, deltaRss, e, this);
833  }
834 
835  // Update significative events for Rss
836  double rss = current_->rss;
837  double deltaRss = rss - eventRssT1_.rss;
838 
839  if (rss > eventRssT1_.rss) {
842  eventRssT1_.set(deltaVsize, deltaRss, e, this);
843  } else if (rss > eventRssT2_.rss) {
845  eventRssT2_.set(deltaVsize, deltaRss, e, this);
846  } else if (rss > eventRssT3_.rss) {
847  eventRssT3_.set(deltaVsize, deltaRss, e, this);
848  }
849  if (deltaRss > eventDeltaRssT1_.deltaRss) {
852  eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
853  } else if (deltaRss > eventDeltaRssT2_.deltaRss) {
855  eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
856  } else if (deltaRss > eventDeltaRssT3_.deltaRss) {
857  eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
858  }
859  } // updateEventStats
860 
862  std::string const& mdlabel,
863  std::string const& mdname) const {
864  if (not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
865  if (count_ >= num_to_skip_) {
866  double deltaVSIZE = current_->vsize - max_.vsize;
867  double deltaRSS = current_->rss - max_.rss;
868  if (!showMallocInfo_) { // default
869  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
870  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
871  << deltaRSS;
872  } else {
873 #ifdef __linux__
874  struct mallinfo minfo = mallinfo();
875 #endif
876  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
877  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
878  << deltaRSS
879 #ifdef __linux__
880  << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena << " N-UNUSED-CHUNKS "
881  << minfo.ordblks << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
882  << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd << " N-CHUNKS " << minfo.hblks
883  << " ]"
884  << " HEAP-USED-BYTES " << minfo.uordblks << " HEAP-UNUSED-BYTES "
885  << minfo.fordblks
886 #endif
887  ;
888  }
889  }
890  }
891  }
892 
894  std::string const& mdlabel,
895  std::string const& mdname) {
896  update();
897  andPrint(type, mdlabel, mdname);
898  updateMax();
899  }
900 
901 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
903  SignificantEvent const& e,
904  std::map<std::string, std::string>& m) const {
905  {
906  std::ostringstream os;
907  os << title << "-a-COUNT";
908  m.insert(std::make_pair(os.str(), i2str(e.count)));
909  }
910  {
911  std::ostringstream os;
912  os << title << "-b-RUN";
913  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run()))));
914  }
915  {
916  std::ostringstream os;
917  os << title << "-c-EVENT";
918  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event()))));
919  }
920  {
921  std::ostringstream os;
922  os << title << "-d-VSIZE";
923  m.insert(std::make_pair(os.str(), d2str(e.vsize)));
924  }
925  {
926  std::ostringstream os;
927  os << title << "-e-DELTV";
928  m.insert(std::make_pair(os.str(), d2str(e.deltaVsize)));
929  }
930  {
931  std::ostringstream os;
932  os << title << "-f-RSS";
933  m.insert(std::make_pair(os.str(), d2str(e.rss)));
934  }
935  if (monitorPssAndPrivate_) {
936  {
937  std::ostringstream os;
938  os << title << "-g-PRIVATE";
939  m.insert(std::make_pair(os.str(), d2str(e.privateSize)));
940  }
941  {
942  std::ostringstream os;
943  os << title << "-h-PSS";
944  m.insert(std::make_pair(os.str(), d2str(e.pss)));
945  }
946  }
947  } // eventStatOutput
948 #endif
949 
950 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
952  std::ostringstream os;
953  os << " <" << title << ">\n";
954  os << " " << e.count << ": " << e.event;
955  os << " vsize " << e.vsize - e.deltaVsize << " + " << e.deltaVsize << " = " << e.vsize;
956  os << " rss: " << e.rss << "\n";
957  os << " </" << title << ">\n";
958  return os.str();
959  } // eventStatOutput
960 
961  std::string SimpleMemoryCheck::mallOutput(std::string title, size_t const& n) const {
962  std::ostringstream os;
963  os << " <" << title << ">\n";
964  os << " " << n << "\n";
965  os << " </" << title << ">\n";
966  return os.str();
967  }
968 #endif
969  // changelog 2
971  double dv,
972  edm::EventID const& currentEventID) {
973  if (count_ < num_to_skip_) {
974  m.totalEarlyVsize += dv;
975  if (dv > m.maxEarlyVsize)
976  m.maxEarlyVsize = dv;
977  } else {
978  ++m.postEarlyCount;
979  m.totalDeltaVsize += dv;
980  if (dv > m.maxDeltaVsize) {
981  m.maxDeltaVsize = dv;
982  m.eventMaxDeltaV = currentEventID;
983  }
984  }
985  } //updateModuleMemoryStats
986 
987  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se) {
988  os << "[" << se.count << "] " << se.event << " vsize = " << se.vsize << " deltaVsize = " << se.deltaVsize
989  << " rss = " << se.rss << " delta = " << se.deltaRss;
990 
991  if (se.monitorPssAndPrivate) {
992  os << " private = " << se.privateSize << " pss = " << se.pss;
993  }
994  return os;
995  }
996 
997  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& sm) {
998  if (sm.postEarlyCount > 0) {
999  os << "\nPost Early Events: TotalDeltaVsize: " << sm.totalDeltaVsize
1000  << " (avg: " << sm.totalDeltaVsize / sm.postEarlyCount << "; max: " << sm.maxDeltaVsize << " during "
1001  << sm.eventMaxDeltaV << ")";
1002  }
1003  if (sm.totalEarlyVsize > 0) {
1004  os << "\n Early Events: TotalDeltaVsize: " << sm.totalEarlyVsize << " (max: " << sm.maxEarlyVsize << ")";
1005  }
1006 
1007  return os;
1008  }
1009 
1010  } // end namespace service
1011 } // end namespace edm
1012 
1013 #if defined(__linux__)
1016 #endif
RunNumber_t run() const
Definition: EventID.h:39
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
MallocOpts get() const
Definition: MallocOpts.h:81
type
Definition: HCALResponse.h:21
EventNumber_t event() const
Definition: EventID.h:41
T getUntrackedParameter(std::string const &, T const &) const
void set_trim_thr(opt_type trim_thr)
Definition: MallocOpts.h:68
static std::string i2str(int i)
std::string eventStatOutput(std::string title, SignificantEvent const &e) const
void preSourceConstruction(const ModuleDescription &)
void set_mmap_max(opt_type mmap_max)
Definition: MallocOpts.h:64
friend std::ostream & operator<<(std::ostream &os, SimpleMemoryCheck::SignificantEvent const &se)
bool hasErrors() const
Definition: MallocOpts.h:61
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
edm::propagate_const< ProcInfo * > current_
std::atomic< bool > measurementUnderway_
void set_mmap_thr(opt_type mmap_thr)
Definition: MallocOpts.h:76
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void updateEventStats(edm::EventID const &e)
void watchPostEvent(PostEvent::slot_type const &iSlot)
std::atomic< bool > moduleMeasurementUnderway_
#define nullptr
void watchPreSourceConstruction(PreSourceConstruction::slot_type const &iSlot)
void watchPostSourceConstruction(PostSourceConstruction::slot_type const &iSlot)
std::string const & moduleName() const
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
void watchPostSourceEvent(PostSourceEvent::slot_type const &iSlot)
std::string const & moduleLabel() const
void andPrint(const std::string &type, const std::string &mdlabel, const std::string &mdname) const
std::atomic< unsigned int > moduleStreamID_
char const * label
edm::propagate_const< FILE * > smapsFile_
std::map< std::string, SignificantModule > SignificantModulesMap
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
ModuleDescription const * moduleDescription() const
char const * smapsLineBuffer() const
std::shared_ptr< T > & get_underlying_safe(propagate_const< std::shared_ptr< T >> &iP)
Definition: value.py:1
#define DEFINE_FWK_SERVICE(type)
Definition: ServiceMaker.h:105
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_
StreamID const & streamID() const
Definition: StreamContext.h:54
smapsInfo(double private_sz, double pss_sz)
void updateAndPrint(const std::string &type, const std::string &mdlabel, const std::string &mdname)
bool operator==(const smapsInfo &p) const
unsigned int value() const
Definition: StreamID.h:42
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
void preModule(StreamContext const &, ModuleCallingContext const &)
static std::string d2str(double d)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void updateModuleMemoryStats(SignificantModule &m, double dv, edm::EventID const &)
std::string error_message() const
Definition: MallocOpts.h:62
void postEvent(StreamContext const &)
HLT enums.
std::string mallOutput(std::string title, size_t const &n) const
#define update(a, b)
edm::propagate_const< char * > smapsLineBuffer_
void watchPostModuleBeginJob(PostModuleBeginJob::slot_type const &iSlot)
void postSourceConstruction(const ModuleDescription &)
EventID const & eventID() const
Definition: StreamContext.h:59
void postModuleBeginJob(const ModuleDescription &)
double averageGrowthRate(double current, double past, int count)
void set_top_pad(opt_type top_pad)
Definition: MallocOpts.h:72
SimpleMemoryCheck(const ParameterSet &, ActivityRegistry &)
void postModule(StreamContext const &, ModuleCallingContext const &)
std::pair< std::string, std::shared_ptr< void > > fetch(const cond::Hash &payloadId, Session &session)
Definition: CondDBFetch.cc:330
void postModuleConstruction(const ModuleDescription &)
bool operator>(const smapsInfo &p) const
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
MallocOptionSetter & getGlobalOptionSetter()
Definition: MallocOpts.cc:196
unsigned int id() const
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal
std::atomic< unsigned int > moduleID_