CMS 3D CMS Logo

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