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 
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;
167  if (monitorPssAndPrivate) {
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_;
484  }
485  if (moduleSummaryRequested_ and not jobReportOutputOnly_) { // changelog 1
486  LogAbsolute mmr("ModuleMemoryReport"); // at end of if block, mmr
487  // is destructed, causing
488  // message to be logged
489  mmr << "ModuleMemoryReport> Each line has module label and: \n";
490  mmr << " (after early ignored events) \n";
491  mmr << " count of times module executed; average increase in vsize \n";
492  mmr << " maximum increase in vsize; event on which maximum occurred \n";
493  mmr << " (during early ignored events) \n";
494  mmr << " total and maximum vsize increases \n \n";
495  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
496  SignificantModule const& m = im->second;
497  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
498  continue;
499  mmr << im->first << ": ";
500  mmr << "n = " << m.postEarlyCount;
501  if (m.postEarlyCount > 0) {
502  mmr << " avg = " << m.totalDeltaVsize / m.postEarlyCount;
503  }
504  mmr << " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
505  if (m.totalEarlyVsize > 0) {
506  mmr << " early total: " << m.totalEarlyVsize;
507  mmr << " max: " << m.maxEarlyVsize;
508  }
509  mmr << "\n";
510  }
511  } // end of if; mmr goes out of scope; log message is queued
512 
513  Service<JobReport> reportSvc;
514  // changelog 1
515 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
516 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
517  // std::map<std::string, double> reportData;
518  std::map<std::string, std::string> reportData;
519 
520  if (eventL2_.vsize > 0)
521  eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
522  if (eventL1_.vsize > 0)
523  eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
524  if (eventM_.vsize > 0)
525  eventStatOutput("LargestVsizeIncreaseEvent", eventM_, reportData);
526  if (eventR1_.vsize > 0)
527  eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
528  if (eventR2_.vsize > 0)
529  eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
530  if (eventT3_.vsize > 0)
531  eventStatOutput("ThirdLargestVsizeEventT3", eventT3_, reportData);
532  if (eventT2_.vsize > 0)
533  eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
534  if (eventT1_.vsize > 0)
535  eventStatOutput("LargestVsizeEventT1", eventT1_, reportData);
536 
537  if (eventRssT3_.rss > 0)
538  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
539  if (eventRssT2_.rss > 0)
540  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
541  if (eventRssT1_.rss > 0)
542  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
543  if (eventDeltaRssT3_.deltaRss > 0)
544  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
545  if (eventDeltaRssT2_.deltaRss > 0)
546  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
547  if (eventDeltaRssT1_.deltaRss > 0)
548  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
549 
550 #ifdef __linux__
551  struct mallinfo minfo = mallinfo();
552  reportData.insert(std::make_pair("HEAP_ARENA_SIZE_BYTES", i2str(minfo.arena)));
553  reportData.insert(std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", i2str(minfo.ordblks)));
554  reportData.insert(std::make_pair("HEAP_TOP_FREE_BYTES", i2str(minfo.keepcost)));
555  reportData.insert(std::make_pair("HEAP_MAPPED_SIZE_BYTES", i2str(minfo.hblkhd)));
556  reportData.insert(std::make_pair("HEAP_MAPPED_N_CHUNKS", i2str(minfo.hblks)));
557  reportData.insert(std::make_pair("HEAP_USED_BYTES", i2str(minfo.uordblks)));
558  reportData.insert(std::make_pair("HEAP_UNUSED_BYTES", i2str(minfo.fordblks)));
559 #endif
560 
561  // Report Growth rates for VSize and Rss
562  reportData.insert(std::make_pair("AverageGrowthRateVsize",
564  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
565  reportData.insert(
566  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
567  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
568 
569  if (moduleSummaryRequested_) { // changelog 2
570  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
571  SignificantModule const& m = im->second;
572  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
573  continue;
574  std::string label = im->first + ":";
575  reportData.insert(std::make_pair(label + "PostEarlyCount", i2str(m.postEarlyCount)));
576  if (m.postEarlyCount > 0) {
577  reportData.insert(std::make_pair(label + "AverageDeltaVsize", d2str(m.totalDeltaVsize / m.postEarlyCount)));
578  }
579  reportData.insert(std::make_pair(label + "MaxDeltaVsize", d2str(m.maxDeltaVsize)));
580  if (m.totalEarlyVsize > 0) {
581  reportData.insert(std::make_pair(label + "TotalEarlyVsize", d2str(m.totalEarlyVsize)));
582  reportData.insert(std::make_pair(label + "MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
583  }
584  }
585  }
586 
587  std::map<std::string, std::string> reportMemoryProperties;
588 
589  if (FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
590  char buf[128];
591  char space[] = " ";
592  size_t value;
593  while (fgets(buf, sizeof(buf), fmeminfo)) {
594  char* saveptr;
595  char* token = nullptr;
596  token = strtok_r(buf, space, &saveptr);
597  if (token != nullptr) {
598  value = atol(strtok_r(nullptr, space, &saveptr));
600  reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token) - 1), i2str(value)));
601  }
602  }
603 
604  fclose(fmeminfo);
605  }
606 
607  // reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
608  reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
609  reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
610 #endif
611 
612 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
613  std::vector<std::string> reportData;
614 
615  if (eventL2_.vsize > 0)
616  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
617  if (eventL1_.vsize > 0)
618  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
619  if (eventM_.vsize > 0)
620  reportData.push_back(eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
621  if (eventR1_.vsize > 0)
622  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
623  if (eventR2_.vsize > 0)
624  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
625  if (eventT3_.vsize > 0)
626  reportData.push_back(eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
627  if (eventT2_.vsize > 0)
628  reportData.push_back(eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
629  if (eventT1_.vsize > 0)
630  reportData.push_back(eventStatOutput("LargestVsizeEventT1", eventT1_));
631 
632  if (eventRssT3_.rss > 0)
633  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
634  if (eventRssT2_.rss > 0)
635  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
636  if (eventRssT1_.rss > 0)
637  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
638  if (eventDeltaRssT3_.deltaRss > 0)
639  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
640  if (eventDeltaRssT2_.deltaRss > 0)
641  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
642  if (eventDeltaRssT1_.deltaRss > 0)
643  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
644 
645  struct mallinfo minfo = mallinfo();
646  reportData.push_back(mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
647  reportData.push_back(mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
648  reportData.push_back(mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
649  reportData.push_back(mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
650  reportData.push_back(mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
651  reportData.push_back(mallOutput("HEAP_USED_BYTES", minfo.uordblks));
652  reportData.push_back(mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
653 
654  // Report Growth rates for VSize and Rss
655  reportData.insert(std::make_pair("AverageGrowthRateVsize",
657  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
658  reportData.insert(
659  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
660  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
661 
662  reportSvc->reportMemoryInfo(reportData);
663  // This is a form of reportMemoryInfo taking s vector, not a map
664 #endif
665  } // postEndJob
666 
668  ++count_;
669  bool expected = false;
670  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
671  std::shared_ptr<void> guard(
672  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
673  update();
674  if (monitorPssAndPrivate_) {
676  }
677  updateEventStats(iContext.eventID());
678  if (oncePerEventMode_) {
679  // should probably use be Run:Event or count_ for the label and name
680  updateMax();
681  andPrint("event", "", "");
682  }
683  }
684  }
685 
686  void SimpleMemoryCheck::preModule(StreamContext const& iStreamContext, ModuleCallingContext const& iModuleContext) {
687  bool expectedMeasurementUnderway = false;
688  if (measurementUnderway_.compare_exchange_strong(expectedMeasurementUnderway, true, std::memory_order_acq_rel)) {
689  std::shared_ptr<void> guard(
690  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
691  bool expectedModuleMeasurementUnderway = false;
692  if (moduleMeasurementUnderway_.compare_exchange_strong(expectedModuleMeasurementUnderway, true)) {
693  update();
694  // changelog 2
695  moduleEntryVsize_ = current_->vsize;
696  moduleStreamID_.store(iStreamContext.streamID().value(), std::memory_order_release);
697  moduleID_.store(iModuleContext.moduleDescription()->id(), std::memory_order_release);
698  }
699  }
700  }
701 
702  void SimpleMemoryCheck::postModule(StreamContext const& iStreamContext,
703  ModuleCallingContext const& iModuleContext) {
704  if (!oncePerEventMode_) {
705  bool expected = false;
706  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
707  std::shared_ptr<void> guard(
708  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
709  auto const md = iModuleContext.moduleDescription();
710  updateAndPrint("module", md->moduleLabel(), md->moduleName());
711  }
712  }
713 
715  //is this the module instance we are measuring?
716  if (moduleMeasurementUnderway_.load(std::memory_order_acquire) and
717  (iStreamContext.streamID().value() == moduleStreamID_.load(std::memory_order_acquire)) and
718  (iModuleContext.moduleDescription()->id() == moduleID_.load(std::memory_order_acquire))) {
719  //Need to release our module measurement lock
720  std::shared_ptr<void> guardModuleMeasurementUnderway(
721  nullptr, [this](void const*) { moduleMeasurementUnderway_.store(false, std::memory_order_release); });
722  bool expected = false;
723  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
724  std::shared_ptr<void> guardMeasurementUnderway(
725  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
726  if (oncePerEventMode_) {
727  update();
728  }
729  // changelog 2
730  double dv = current_->vsize - moduleEntryVsize_;
731  std::string label = iModuleContext.moduleDescription()->moduleLabel();
732  updateModuleMemoryStats(modules_[label], dv, iStreamContext.eventID());
733  }
734  }
735  }
736  }
737 
740  *current_ = fetch();
741  }
742 
744  if ((*current_ > max_) || oncePerEventMode_) {
745  if (count_ >= num_to_skip_) {
746  }
747  max_ = *current_;
748  }
749  }
750 
752  if (count_ < num_to_skip_)
753  return;
754  if (count_ == num_to_skip_) {
755  eventT1_.set(0, 0, e, this);
756  eventM_.set(0, 0, e, this);
757  eventRssT1_.set(0, 0, e, this);
758  eventDeltaRssT1_.set(0, 0, e, this);
759  return;
760  }
761  double vsize = current_->vsize;
762  double deltaVsize = vsize - eventT1_.vsize;
763 
764  // Update significative events for Vsize
765  if (vsize > eventT1_.vsize) {
766  double deltaRss = current_->rss - eventT1_.rss;
767  eventT3_ = eventT2_;
768  eventT2_ = eventT1_;
769  eventT1_.set(deltaVsize, deltaRss, e, this);
770  } else if (vsize > eventT2_.vsize) {
771  double deltaRss = current_->rss - eventT1_.rss;
772  eventT3_ = eventT2_;
773  eventT2_.set(deltaVsize, deltaRss, e, this);
774  } else if (vsize > eventT3_.vsize) {
775  double deltaRss = current_->rss - eventT1_.rss;
776  eventT3_.set(deltaVsize, deltaRss, e, this);
777  }
778 
779  if (deltaVsize > eventM_.deltaVsize) {
780  double deltaRss = current_->rss - eventM_.rss;
782  eventL2_ = eventL1_;
783  } else {
784  eventL2_ = eventR1_;
785  }
786  eventL1_ = eventM_;
787  eventM_.set(deltaVsize, deltaRss, e, this);
790  } else if (deltaVsize > eventR1_.deltaVsize) {
791  double deltaRss = current_->rss - eventM_.rss;
792  eventR2_ = eventR1_;
793  eventR1_.set(deltaVsize, deltaRss, e, this);
794  } else if (deltaVsize > eventR2_.deltaVsize) {
795  double deltaRss = current_->rss - eventR1_.rss;
796  eventR2_.set(deltaVsize, deltaRss, e, this);
797  }
798 
799  // Update significative events for Rss
800  double rss = current_->rss;
801  double deltaRss = rss - eventRssT1_.rss;
802 
803  if (rss > eventRssT1_.rss) {
806  eventRssT1_.set(deltaVsize, deltaRss, e, this);
807  } else if (rss > eventRssT2_.rss) {
809  eventRssT2_.set(deltaVsize, deltaRss, e, this);
810  } else if (rss > eventRssT3_.rss) {
811  eventRssT3_.set(deltaVsize, deltaRss, e, this);
812  }
813  if (deltaRss > eventDeltaRssT1_.deltaRss) {
816  eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
817  } else if (deltaRss > eventDeltaRssT2_.deltaRss) {
819  eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
820  } else if (deltaRss > eventDeltaRssT3_.deltaRss) {
821  eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
822  }
823  } // updateEventStats
824 
826  std::string const& mdlabel,
827  std::string const& mdname) const {
828  if (not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
829  if (count_ >= num_to_skip_) {
830  double deltaVSIZE = current_->vsize - max_.vsize;
831  double deltaRSS = current_->rss - max_.rss;
832  if (!showMallocInfo_) { // default
833  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
834  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
835  << deltaRSS;
836  } else {
837 #ifdef __linux__
838  struct mallinfo minfo = mallinfo();
839 #endif
840  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
841  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
842  << deltaRSS
843 #ifdef __linux__
844  << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena << " N-UNUSED-CHUNKS "
845  << minfo.ordblks << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
846  << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd << " N-CHUNKS " << minfo.hblks
847  << " ]"
848  << " HEAP-USED-BYTES " << minfo.uordblks << " HEAP-UNUSED-BYTES "
849  << minfo.fordblks
850 #endif
851  ;
852  }
853  }
854  }
855  }
856 
858  std::string const& mdlabel,
859  std::string const& mdname) {
860  update();
861  andPrint(type, mdlabel, mdname);
862  updateMax();
863  }
864 
865 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
867  SignificantEvent const& e,
868  std::map<std::string, std::string>& m) const {
869  {
870  std::ostringstream os;
871  os << title << "-a-COUNT";
872  m.insert(std::make_pair(os.str(), i2str(e.count)));
873  }
874  {
875  std::ostringstream os;
876  os << title << "-b-RUN";
877  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run()))));
878  }
879  {
880  std::ostringstream os;
881  os << title << "-c-EVENT";
882  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event()))));
883  }
884  {
885  std::ostringstream os;
886  os << title << "-d-VSIZE";
887  m.insert(std::make_pair(os.str(), d2str(e.vsize)));
888  }
889  {
890  std::ostringstream os;
891  os << title << "-e-DELTV";
892  m.insert(std::make_pair(os.str(), d2str(e.deltaVsize)));
893  }
894  {
895  std::ostringstream os;
896  os << title << "-f-RSS";
897  m.insert(std::make_pair(os.str(), d2str(e.rss)));
898  }
899  if (monitorPssAndPrivate_) {
900  {
901  std::ostringstream os;
902  os << title << "-g-PRIVATE";
903  m.insert(std::make_pair(os.str(), d2str(e.privateSize)));
904  }
905  {
906  std::ostringstream os;
907  os << title << "-h-PSS";
908  m.insert(std::make_pair(os.str(), d2str(e.pss)));
909  }
910  }
911  } // eventStatOutput
912 #endif
913 
914 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
915  std::string SimpleMemoryCheck::eventStatOutput(std::string title, SignificantEvent const& e) const {
916  std::ostringstream os;
917  os << " <" << title << ">\n";
918  os << " " << e.count << ": " << e.event;
919  os << " vsize " << e.vsize - e.deltaVsize << " + " << e.deltaVsize << " = " << e.vsize;
920  os << " rss: " << e.rss << "\n";
921  os << " </" << title << ">\n";
922  return os.str();
923  } // eventStatOutput
924 
925  std::string SimpleMemoryCheck::mallOutput(std::string title, size_t const& n) const {
926  std::ostringstream os;
927  os << " <" << title << ">\n";
928  os << " " << n << "\n";
929  os << " </" << title << ">\n";
930  return os.str();
931  }
932 #endif
933  // changelog 2
935  double dv,
936  edm::EventID const& currentEventID) {
937  if (count_ < num_to_skip_) {
938  m.totalEarlyVsize += dv;
939  if (dv > m.maxEarlyVsize)
940  m.maxEarlyVsize = dv;
941  } else {
942  ++m.postEarlyCount;
943  m.totalDeltaVsize += dv;
944  if (dv > m.maxDeltaVsize) {
945  m.maxDeltaVsize = dv;
946  m.eventMaxDeltaV = currentEventID;
947  }
948  }
949  } //updateModuleMemoryStats
950 
951  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se) {
952  os << "[" << se.count << "] " << se.event << " vsize = " << se.vsize << " deltaVsize = " << se.deltaVsize
953  << " rss = " << se.rss << " delta = " << se.deltaRss;
954 
955  if (se.monitorPssAndPrivate) {
956  os << " private = " << se.privateSize << " pss = " << se.pss;
957  }
958  return os;
959  }
960 
961  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& sm) {
962  if (sm.postEarlyCount > 0) {
963  os << "\nPost Early Events: TotalDeltaVsize: " << sm.totalDeltaVsize
964  << " (avg: " << sm.totalDeltaVsize / sm.postEarlyCount << "; max: " << sm.maxDeltaVsize << " during "
965  << sm.eventMaxDeltaV << ")";
966  }
967  if (sm.totalEarlyVsize > 0) {
968  os << "\n Early Events: TotalDeltaVsize: " << sm.totalEarlyVsize << " (max: " << sm.maxEarlyVsize << ")";
969  }
970 
971  return os;
972  }
973 
974  } // end namespace service
975 } // end namespace edm
976 
977 #if defined(__linux__)
979 DEFINE_FWK_SERVICE(SimpleMemoryCheck);
980 #endif
RunNumber_t run() const
Definition: EventID.h:38
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
EventNumber_t event() const
Definition: EventID.h:40
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 &)
std::pair< ALIstring, ALIstring > pss
Definition: Fit.h:25
friend std::ostream & operator<<(std::ostream &os, SimpleMemoryCheck::SignificantEvent const &se)
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 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 &)
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
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)
unsigned int id() const
void watchPostBeginJob(PostBeginJob::slot_type const &iSlot)
convenience function for attaching to signal
std::atomic< unsigned int > moduleID_