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_;
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 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
552  struct mallinfo2 minfo = mallinfo2();
553 #else
554  struct mallinfo minfo = mallinfo();
555 #endif
556  reportData.insert(std::make_pair("HEAP_ARENA_SIZE_BYTES", std::to_string(minfo.arena)));
557  reportData.insert(std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", std::to_string(minfo.ordblks)));
558  reportData.insert(std::make_pair("HEAP_TOP_FREE_BYTES", std::to_string(minfo.keepcost)));
559  reportData.insert(std::make_pair("HEAP_MAPPED_SIZE_BYTES", std::to_string(minfo.hblkhd)));
560  reportData.insert(std::make_pair("HEAP_MAPPED_N_CHUNKS", std::to_string(minfo.hblks)));
561  reportData.insert(std::make_pair("HEAP_USED_BYTES", std::to_string(minfo.uordblks)));
562  reportData.insert(std::make_pair("HEAP_UNUSED_BYTES", std::to_string(minfo.fordblks)));
563 #endif
564 
565  // Report Growth rates for VSize and Rss
566  reportData.insert(std::make_pair("AverageGrowthRateVsize",
568  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
569  reportData.insert(
570  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
571  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
572 
573  if (moduleSummaryRequested_) { // changelog 2
574  for (SignificantModulesMap::iterator im = modules_.begin(); im != modules_.end(); ++im) {
575  SignificantModule const& m = im->second;
576  if (m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0)
577  continue;
578  std::string label = im->first + ":";
579  reportData.insert(std::make_pair(label + "PostEarlyCount", i2str(m.postEarlyCount)));
580  if (m.postEarlyCount > 0) {
581  reportData.insert(std::make_pair(label + "AverageDeltaVsize", d2str(m.totalDeltaVsize / m.postEarlyCount)));
582  }
583  reportData.insert(std::make_pair(label + "MaxDeltaVsize", d2str(m.maxDeltaVsize)));
584  if (m.totalEarlyVsize > 0) {
585  reportData.insert(std::make_pair(label + "TotalEarlyVsize", d2str(m.totalEarlyVsize)));
586  reportData.insert(std::make_pair(label + "MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
587  }
588  }
589  }
590 
591  std::map<std::string, std::string> reportMemoryProperties;
592 
593  if (FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
594  char buf[128];
595  char space[] = " ";
596  size_t value;
597  while (fgets(buf, sizeof(buf), fmeminfo)) {
598  char* saveptr;
599  char* token = nullptr;
600  token = strtok_r(buf, space, &saveptr);
601  if (token != nullptr) {
602  value = atol(strtok_r(nullptr, space, &saveptr));
604  reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token) - 1), i2str(value)));
605  }
606  }
607 
608  fclose(fmeminfo);
609  }
610 
611  // reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
612  reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
613  reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
614 #endif
615 
616 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
617  std::vector<std::string> reportData;
618 
619  if (eventL2_.vsize > 0)
620  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
621  if (eventL1_.vsize > 0)
622  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
623  if (eventM_.vsize > 0)
624  reportData.push_back(eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
625  if (eventR1_.vsize > 0)
626  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
627  if (eventR2_.vsize > 0)
628  reportData.push_back(eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
629  if (eventT3_.vsize > 0)
630  reportData.push_back(eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
631  if (eventT2_.vsize > 0)
632  reportData.push_back(eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
633  if (eventT1_.vsize > 0)
634  reportData.push_back(eventStatOutput("LargestVsizeEventT1", eventT1_));
635 
636  if (eventRssT3_.rss > 0)
637  eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
638  if (eventRssT2_.rss > 0)
639  eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
640  if (eventRssT1_.rss > 0)
641  eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
642  if (eventDeltaRssT3_.deltaRss > 0)
643  eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
644  if (eventDeltaRssT2_.deltaRss > 0)
645  eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
646  if (eventDeltaRssT1_.deltaRss > 0)
647  eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
648 
649 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
650  struct mallinfo2 minfo = mallinfo2();
651 #else
652  struct mallinfo minfo = mallinfo();
653 #endif
654  reportData.push_back(mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
655  reportData.push_back(mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
656  reportData.push_back(mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
657  reportData.push_back(mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
658  reportData.push_back(mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
659  reportData.push_back(mallOutput("HEAP_USED_BYTES", minfo.uordblks));
660  reportData.push_back(mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
661 
662  // Report Growth rates for VSize and Rss
663  reportData.insert(std::make_pair("AverageGrowthRateVsize",
665  reportData.insert(std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
666  reportData.insert(
667  std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
668  reportData.insert(std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
669 
670  reportSvc->reportMemoryInfo(reportData);
671  // This is a form of reportMemoryInfo taking s vector, not a map
672 #endif
673  } // postEndJob
674 
676  ++count_;
677  bool expected = false;
678  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
679  std::shared_ptr<void> guard(
680  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
681  update();
682  if (monitorPssAndPrivate_) {
684  }
685  updateEventStats(iContext.eventID());
686  if (oncePerEventMode_) {
687  // should probably use be Run:Event or count_ for the label and name
688  updateMax();
689  andPrint("event", "", "");
690  }
691  }
692  }
693 
694  void SimpleMemoryCheck::preModule(StreamContext const& iStreamContext, ModuleCallingContext const& iModuleContext) {
695  bool expectedMeasurementUnderway = false;
696  if (measurementUnderway_.compare_exchange_strong(expectedMeasurementUnderway, true, std::memory_order_acq_rel)) {
697  std::shared_ptr<void> guard(
698  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
699  bool expectedModuleMeasurementUnderway = false;
700  if (moduleMeasurementUnderway_.compare_exchange_strong(expectedModuleMeasurementUnderway, true)) {
701  update();
702  // changelog 2
703  moduleEntryVsize_ = current_->vsize;
704  moduleStreamID_.store(iStreamContext.streamID().value(), std::memory_order_release);
705  moduleID_.store(iModuleContext.moduleDescription()->id(), std::memory_order_release);
706  }
707  }
708  }
709 
710  void SimpleMemoryCheck::postModule(StreamContext const& iStreamContext,
711  ModuleCallingContext const& iModuleContext) {
712  if (!oncePerEventMode_) {
713  bool expected = false;
714  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
715  std::shared_ptr<void> guard(
716  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
717  auto const md = iModuleContext.moduleDescription();
718  updateAndPrint("module", md->moduleLabel(), md->moduleName());
719  }
720  }
721 
723  //is this the module instance we are measuring?
724  if (moduleMeasurementUnderway_.load(std::memory_order_acquire) and
725  (iStreamContext.streamID().value() == moduleStreamID_.load(std::memory_order_acquire)) and
726  (iModuleContext.moduleDescription()->id() == moduleID_.load(std::memory_order_acquire))) {
727  //Need to release our module measurement lock
728  std::shared_ptr<void> guardModuleMeasurementUnderway(
729  nullptr, [this](void const*) { moduleMeasurementUnderway_.store(false, std::memory_order_release); });
730  bool expected = false;
731  if (measurementUnderway_.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) {
732  std::shared_ptr<void> guardMeasurementUnderway(
733  nullptr, [this](void const*) { measurementUnderway_.store(false, std::memory_order_release); });
734  if (oncePerEventMode_) {
735  update();
736  }
737  // changelog 2
738  double dv = current_->vsize - moduleEntryVsize_;
739  std::string label = iModuleContext.moduleDescription()->moduleLabel();
740  updateModuleMemoryStats(modules_[label], dv, iStreamContext.eventID());
741  }
742  }
743  }
744  }
745 
748  *current_ = fetch();
749  }
750 
752  if ((*current_ > max_) || oncePerEventMode_) {
753  if (count_ >= num_to_skip_) {
754  }
755  max_ = *current_;
756  }
757  }
758 
760  if (count_ < num_to_skip_)
761  return;
762  if (count_ == num_to_skip_) {
763  eventT1_.set(0, 0, e, this);
764  eventM_.set(0, 0, e, this);
765  eventRssT1_.set(0, 0, e, this);
766  eventDeltaRssT1_.set(0, 0, e, this);
767  return;
768  }
769  double vsize = current_->vsize;
770  double deltaVsize = vsize - eventT1_.vsize;
771 
772  // Update significative events for Vsize
773  if (vsize > eventT1_.vsize) {
774  double deltaRss = current_->rss - eventT1_.rss;
775  eventT3_ = eventT2_;
776  eventT2_ = eventT1_;
777  eventT1_.set(deltaVsize, deltaRss, e, this);
778  } else if (vsize > eventT2_.vsize) {
779  double deltaRss = current_->rss - eventT1_.rss;
780  eventT3_ = eventT2_;
781  eventT2_.set(deltaVsize, deltaRss, e, this);
782  } else if (vsize > eventT3_.vsize) {
783  double deltaRss = current_->rss - eventT1_.rss;
784  eventT3_.set(deltaVsize, deltaRss, e, this);
785  }
786 
787  if (deltaVsize > eventM_.deltaVsize) {
788  double deltaRss = current_->rss - eventM_.rss;
790  eventL2_ = eventL1_;
791  } else {
792  eventL2_ = eventR1_;
793  }
794  eventL1_ = eventM_;
795  eventM_.set(deltaVsize, deltaRss, e, this);
798  } else if (deltaVsize > eventR1_.deltaVsize) {
799  double deltaRss = current_->rss - eventM_.rss;
800  eventR2_ = eventR1_;
801  eventR1_.set(deltaVsize, deltaRss, e, this);
802  } else if (deltaVsize > eventR2_.deltaVsize) {
803  double deltaRss = current_->rss - eventR1_.rss;
804  eventR2_.set(deltaVsize, deltaRss, e, this);
805  }
806 
807  // Update significative events for Rss
808  double rss = current_->rss;
809  double deltaRss = rss - eventRssT1_.rss;
810 
811  if (rss > eventRssT1_.rss) {
814  eventRssT1_.set(deltaVsize, deltaRss, e, this);
815  } else if (rss > eventRssT2_.rss) {
817  eventRssT2_.set(deltaVsize, deltaRss, e, this);
818  } else if (rss > eventRssT3_.rss) {
819  eventRssT3_.set(deltaVsize, deltaRss, e, this);
820  }
821  if (deltaRss > eventDeltaRssT1_.deltaRss) {
824  eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
825  } else if (deltaRss > eventDeltaRssT2_.deltaRss) {
827  eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
828  } else if (deltaRss > eventDeltaRssT3_.deltaRss) {
829  eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
830  }
831  } // updateEventStats
832 
834  std::string const& mdlabel,
835  std::string const& mdname) const {
836  if (not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
837  if (count_ >= num_to_skip_) {
838  double deltaVSIZE = current_->vsize - max_.vsize;
839  double deltaRSS = current_->rss - max_.rss;
840  if (!showMallocInfo_) { // default
841  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
842  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
843  << deltaRSS;
844  } else {
845 #ifdef __linux__
846 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 33)
847  struct mallinfo2 minfo = mallinfo2();
848 #else
849  struct mallinfo minfo = mallinfo();
850 #endif
851 #endif
852  LogWarning("MemoryCheck") << "MemoryCheck: " << type << " " << mdname << ":" << mdlabel << " VSIZE "
853  << current_->vsize << " " << deltaVSIZE << " RSS " << current_->rss << " "
854  << deltaRSS
855 #ifdef __linux__
856  << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena << " N-UNUSED-CHUNKS "
857  << minfo.ordblks << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
858  << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd << " N-CHUNKS " << minfo.hblks
859  << " ]"
860  << " HEAP-USED-BYTES " << minfo.uordblks << " HEAP-UNUSED-BYTES "
861  << minfo.fordblks
862 #endif
863  ;
864  }
865  }
866  }
867  }
868 
870  std::string const& mdlabel,
871  std::string const& mdname) {
872  update();
873  andPrint(type, mdlabel, mdname);
874  updateMax();
875  }
876 
877 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
879  SignificantEvent const& e,
880  std::map<std::string, std::string>& m) const {
881  {
882  std::ostringstream os;
883  os << title << "-a-COUNT";
884  m.insert(std::make_pair(os.str(), i2str(e.count)));
885  }
886  {
887  std::ostringstream os;
888  os << title << "-b-RUN";
889  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run()))));
890  }
891  {
892  std::ostringstream os;
893  os << title << "-c-EVENT";
894  m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event()))));
895  }
896  {
897  std::ostringstream os;
898  os << title << "-d-VSIZE";
899  m.insert(std::make_pair(os.str(), d2str(e.vsize)));
900  }
901  {
902  std::ostringstream os;
903  os << title << "-e-DELTV";
904  m.insert(std::make_pair(os.str(), d2str(e.deltaVsize)));
905  }
906  {
907  std::ostringstream os;
908  os << title << "-f-RSS";
909  m.insert(std::make_pair(os.str(), d2str(e.rss)));
910  }
911  if (monitorPssAndPrivate_) {
912  {
913  std::ostringstream os;
914  os << title << "-g-PRIVATE";
915  m.insert(std::make_pair(os.str(), d2str(e.privateSize)));
916  }
917  {
918  std::ostringstream os;
919  os << title << "-h-PSS";
920  m.insert(std::make_pair(os.str(), d2str(e.pss)));
921  }
922  }
923  } // eventStatOutput
924 #endif
925 
926 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
927  std::string SimpleMemoryCheck::eventStatOutput(std::string title, SignificantEvent const& e) const {
928  std::ostringstream os;
929  os << " <" << title << ">\n";
930  os << " " << e.count << ": " << e.event;
931  os << " vsize " << e.vsize - e.deltaVsize << " + " << e.deltaVsize << " = " << e.vsize;
932  os << " rss: " << e.rss << "\n";
933  os << " </" << title << ">\n";
934  return os.str();
935  } // eventStatOutput
936 
938  std::ostringstream os;
939  os << " <" << title << ">\n";
940  os << " " << n << "\n";
941  os << " </" << title << ">\n";
942  return os.str();
943  }
944 #endif
945  // changelog 2
947  double dv,
948  edm::EventID const& currentEventID) {
949  if (count_ < num_to_skip_) {
950  m.totalEarlyVsize += dv;
951  if (dv > m.maxEarlyVsize)
952  m.maxEarlyVsize = dv;
953  } else {
954  ++m.postEarlyCount;
955  m.totalDeltaVsize += dv;
956  if (dv > m.maxDeltaVsize) {
957  m.maxDeltaVsize = dv;
958  m.eventMaxDeltaV = currentEventID;
959  }
960  }
961  } //updateModuleMemoryStats
962 
963  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantEvent const& se) {
964  os << "[" << se.count << "] " << se.event << " vsize = " << se.vsize << " deltaVsize = " << se.deltaVsize
965  << " rss = " << se.rss << " delta = " << se.deltaRss;
966 
967  if (se.monitorPssAndPrivate) {
968  os << " private = " << se.privateSize << " pss = " << se.pss;
969  }
970  return os;
971  }
972 
973  std::ostream& operator<<(std::ostream& os, SimpleMemoryCheck::SignificantModule const& sm) {
974  if (sm.postEarlyCount > 0) {
975  os << "\nPost Early Events: TotalDeltaVsize: " << sm.totalDeltaVsize
976  << " (avg: " << sm.totalDeltaVsize / sm.postEarlyCount << "; max: " << sm.maxDeltaVsize << " during "
977  << sm.eventMaxDeltaV << ")";
978  }
979  if (sm.totalEarlyVsize > 0) {
980  os << "\n Early Events: TotalDeltaVsize: " << sm.totalEarlyVsize << " (max: " << sm.maxEarlyVsize << ")";
981  }
982 
983  return os;
984  }
985 
986  } // end namespace service
987 } // end namespace edm
988 
989 #if defined(__linux__)
992 #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:54
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:59
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_