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