CMS 3D CMS Logo

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