CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/FWCore/Services/src/Memory.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Services
00004 // Class  :     Memory
00005 //
00006 // Implementation:
00007 //
00008 // Original Author:  Jim Kowalkowski
00009 //
00010 // Change Log
00011 //
00012 // 1 - Apr 25, 2008 M. Fischler
00013 //        Collect event summary information and output to XML file and logger
00014 //        at the end of the job.  Involves split-up of updateAndPrint method.
00015 //
00016 // 2 - May 7, 2008 M. Fischler
00017 //      Collect module summary information and output to XML file and logger
00018 //        at the end of the job.
00019 //
00020 // 3 - Jan 14, 2009 Natalia Garcia Nebot
00021 //        Added:        - Average rate of growth in RSS and peak value attained.
00022 //                - Average rate of growth in VSize over time, Peak VSize
00023 //
00024 //
00025 
00026 #include "FWCore/Services/src/Memory.h"
00027 
00028 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00029 #include "FWCore/Framework/interface/Event.h"
00030 #include "FWCore/MessageLogger/interface/JobReport.h"
00031 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00032 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00033 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00034 #include "FWCore/ServiceRegistry/interface/Service.h"
00035 #include "FWCore/Utilities/interface/Exception.h"
00036 #include "FWCore/Utilities/interface/MallocOpts.h"
00037 
00038 #include <cstring>
00039 #include <iostream>
00040 #ifdef __linux__
00041 #include <malloc.h>
00042 #endif
00043 #include <sstream>
00044 //#include <stdio.h>
00045 #include <string>
00046 //#include <string.h>
00047 #include <boost/lexical_cast.hpp>
00048 
00049 #ifdef __linux__
00050 #define LINUX 1
00051 #endif
00052 
00053 #include <fcntl.h>
00054 #include <unistd.h>
00055 
00056 namespace edm {
00057   namespace service {
00058 
00059     static std::string d2str(double d) {
00060       std::ostringstream t;
00061       t << d;
00062       return t.str();
00063     }
00064 
00065     static std::string i2str(int i) {
00066       std::ostringstream t;
00067       t << i;
00068       return t.str();
00069     }
00070 
00071     ProcInfo SimpleMemoryCheck::fetch() {
00072       return piFetcher_.fetch();
00073     }
00074     
00075     smapsInfo SimpleMemoryCheck::fetchSmaps() {
00076       smapsInfo ret;
00077       ret.private_ = 0;
00078       ret.pss_ = 0;
00079 #ifdef LINUX
00080       fseek(smapsFile_, 0, SEEK_SET);
00081       ssize_t read;
00082       
00083       /*
00084        The format of the report is
00085        Private_Clean:        0 kB
00086        Private_Dirty:       72 kB
00087        Swap:                 0 kB
00088        Pss:                 72 kB
00089        */
00090       
00091       while ((read = getline(&smapsLineBuffer_, &smapsLineBufferLen_, smapsFile_)) != -1) {
00092         if(read > 14) {
00093           //Private
00094           if(0==strncmp("Private_",smapsLineBuffer_,8)) {
00095             unsigned int value = atoi(smapsLineBuffer_+14);
00096             //Convert from kB to MB
00097             ret.private_ += static_cast<double>(value)/1024.;
00098           } else if(0==strncmp("Pss:",smapsLineBuffer_,4)) {
00099             unsigned int value = atoi(smapsLineBuffer_+4);
00100             //Convert from kB to MB
00101             ret.pss_ += static_cast<double>(value)/1024.;            
00102           }
00103         }
00104       }
00105 #endif
00106       return ret;
00107     }
00108 
00109     double SimpleMemoryCheck::averageGrowthRate(double current, double past, int count) {
00110       return(current-past)/(double)count;
00111     }
00112 
00113     SimpleMemoryCheck::SimpleMemoryCheck(ParameterSet const& iPS,
00114                                          ActivityRegistry&iReg)
00115     : a_()
00116     , b_()
00117     , current_(&a_)
00118     , previous_(&b_)
00119     , pg_size_(sysconf(_SC_PAGESIZE)) // getpagesize()
00120     , num_to_skip_(iPS.getUntrackedParameter<int>("ignoreTotal"))
00121     , showMallocInfo_(iPS.getUntrackedParameter<bool>("showMallocInfo"))
00122     , oncePerEventMode_(iPS.getUntrackedParameter<bool>("oncePerEventMode"))
00123     , jobReportOutputOnly_(iPS.getUntrackedParameter<bool>("jobReportOutputOnly"))
00124     , monitorPssAndPrivate_(iPS.getUntrackedParameter<bool>("monitorPssAndPrivate"))
00125     , count_()
00126     , smapsFile_(0)
00127     , smapsLineBuffer_(NULL)
00128     , smapsLineBufferLen_(0)
00129     , growthRateVsize_()
00130     , growthRateRss_()
00131     , moduleSummaryRequested_(iPS.getUntrackedParameter<bool>("moduleMemorySummary")) {
00132                                                                 // changelog 2
00133       // pg_size = (double)getpagesize();
00134       std::ostringstream ost;
00135 
00136       openFiles();
00137       iReg.watchPostForkReacquireResources(this,&SimpleMemoryCheck::postFork);
00138       
00139       if(!oncePerEventMode_) { // default, prints on increases
00140         iReg.watchPreSourceConstruction(this, &SimpleMemoryCheck::preSourceConstruction);
00141         iReg.watchPostSourceConstruction(this, &SimpleMemoryCheck::postSourceConstruction);
00142         iReg.watchPostSource(this, &SimpleMemoryCheck::postSource);
00143         iReg.watchPostModuleConstruction(this, &SimpleMemoryCheck::postModuleConstruction);
00144         iReg.watchPostModuleBeginJob(this, &SimpleMemoryCheck::postModuleBeginJob);
00145         iReg.watchPostProcessEvent(this, &SimpleMemoryCheck::postEventProcessing);
00146         iReg.watchPostModule(this, &SimpleMemoryCheck::postModule);
00147         iReg.watchPostBeginJob(this, &SimpleMemoryCheck::postBeginJob);
00148         iReg.watchPostEndJob(this, &SimpleMemoryCheck::postEndJob);
00149       } else {
00150         iReg.watchPostProcessEvent(this, &SimpleMemoryCheck::postEventProcessing);
00151         iReg.watchPostEndJob(this, &SimpleMemoryCheck::postEndJob);
00152       }
00153       if(moduleSummaryRequested_) {                                // changelog 2
00154         iReg.watchPreProcessEvent(this, &SimpleMemoryCheck::preEventProcessing);
00155         iReg.watchPreModule(this, &SimpleMemoryCheck::preModule);
00156         if(oncePerEventMode_) {
00157           iReg.watchPostModule(this, &SimpleMemoryCheck::postModule);
00158         }
00159       }
00160 
00161       // The following are not currenty used/implemented below for either
00162       // of the print modes (but are left here for reference)
00163       //  iReg.watchPostBeginJob(this,
00164       //       &SimpleMemoryCheck::postBeginJob);
00165       //  iReg.watchPreProcessEvent(this,
00166       //       &SimpleMemoryCheck::preEventProcessing);
00167       //  iReg.watchPreModule(this,
00168       //       &SimpleMemoryCheck::preModule);
00169 
00170 #ifndef __SANITIZE_ADDRESS__
00171       typedef MallocOpts::opt_type opt_type;
00172       MallocOptionSetter& mopts = getGlobalOptionSetter();
00173 
00174       opt_type
00175       p_mmap_max = iPS.getUntrackedParameter<int>("M_MMAP_MAX"),
00176       p_trim_thr = iPS.getUntrackedParameter<int>("M_TRIM_THRESHOLD"),
00177       p_top_pad = iPS.getUntrackedParameter<int>("M_TOP_PAD"),
00178       p_mmap_thr = iPS.getUntrackedParameter<int>("M_MMAP_THRESHOLD");
00179 
00180       if(p_mmap_max >= 0) mopts.set_mmap_max(p_mmap_max);
00181       if(p_trim_thr >= 0) mopts.set_trim_thr(p_trim_thr);
00182       if(p_top_pad >= 0) mopts.set_top_pad(p_top_pad);
00183       if(p_mmap_thr >= 0) mopts.set_mmap_thr(p_mmap_thr);
00184 
00185       mopts.adjustMallocParams();
00186 
00187       if(mopts.hasErrors()) {
00188         LogWarning("MemoryCheck")
00189         << "ERROR: Problem with setting malloc options\n"
00190         << mopts.error_message();
00191       }
00192 
00193       if(iPS.getUntrackedParameter<bool>("dump") == true) {
00194         MallocOpts mo = mopts.get();
00195         LogWarning("MemoryCheck")
00196         << "Malloc options: " << mo << "\n";
00197       }
00198 #endif
00199     }
00200 
00201     SimpleMemoryCheck::~SimpleMemoryCheck() {
00202 #ifdef LINUX
00203       if(0 != smapsFile_) {
00204         fclose(smapsFile_);
00205       }
00206 #endif
00207       if (smapsLineBuffer_) {
00208         //getline will create the memory using malloc
00209         free(smapsLineBuffer_);
00210       }
00211     }
00212 
00213     void SimpleMemoryCheck::fillDescriptions(ConfigurationDescriptions& descriptions) {
00214       ParameterSetDescription desc;
00215       desc.addUntracked<int>("ignoreTotal", 1);
00216       desc.addUntracked<bool>("showMallocInfo", false);
00217       desc.addUntracked<bool>("oncePerEventMode", false);
00218       desc.addUntracked<bool>("jobReportOutputOnly", false);
00219       desc.addUntracked<bool>("monitorPssAndPrivate", false);
00220       desc.addUntracked<bool>("moduleMemorySummary", false);
00221       desc.addUntracked<int>("M_MMAP_MAX", -1);
00222       desc.addUntracked<int>("M_TRIM_THRESHOLD", -1);
00223       desc.addUntracked<int>("M_TOP_PAD", -1);
00224       desc.addUntracked<int>("M_MMAP_THRESHOLD", -1);
00225       desc.addUntracked<bool>("dump", false);
00226       descriptions.add("SimpleMemoryCheck", desc);
00227     }
00228 
00229     void SimpleMemoryCheck::openFiles() {
00230 #ifdef LINUX
00231       if (monitorPssAndPrivate_) {
00232         std::ostringstream smapsNameOst;
00233         smapsNameOst <<"/proc/"<<getpid()<<"/smaps";
00234         if((smapsFile_ =fopen(smapsNameOst.str().c_str(), "r"))==0) {
00235           throw Exception(errors::Configuration) <<"Failed to open smaps file "<<smapsNameOst.str()<<std::endl;
00236         }
00237       }
00238 #endif
00239     }
00240 
00241     void SimpleMemoryCheck::postBeginJob() {
00242         growthRateVsize_ = current_->vsize;
00243         growthRateRss_ = current_->rss;
00244     }
00245 
00246     void SimpleMemoryCheck::preSourceConstruction(ModuleDescription const& md) {
00247       updateAndPrint("pre-ctor", md.moduleLabel(), md.moduleName());
00248     }
00249 
00250 
00251     void SimpleMemoryCheck::postSourceConstruction(ModuleDescription const& md) {
00252       updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
00253     }
00254 
00255     void SimpleMemoryCheck::postSource() {
00256       updateAndPrint("module", "source", "source");
00257     }
00258 
00259     void SimpleMemoryCheck::postModuleConstruction(ModuleDescription const& md) {
00260       updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
00261     }
00262 
00263     void SimpleMemoryCheck::postModuleBeginJob(ModuleDescription const& md) {
00264       updateAndPrint("beginJob", md.moduleLabel(), md.moduleName());
00265     }
00266 
00267     void SimpleMemoryCheck::postEndJob() {
00268       if(not jobReportOutputOnly_) {
00269         LogAbsolute("MemoryReport")                                 // changelog 1
00270         << "MemoryReport> Peak virtual size " << eventT1_.vsize << " Mbytes"
00271         << "\n"
00272         << " Key events increasing vsize: \n"
00273         << eventL2_ << "\n"
00274         << eventL1_ << "\n"
00275         << eventM_  << "\n"
00276         << eventR1_ << "\n"
00277         << eventR2_ << "\n"
00278         << eventT3_ << "\n"
00279         << eventT2_ << "\n"
00280         << eventT1_ ;
00281       }
00282       if(moduleSummaryRequested_ and not jobReportOutputOnly_) {                                // changelog 1
00283         LogAbsolute mmr("ModuleMemoryReport"); // at end of if block, mmr
00284                                                     // is destructed, causing
00285                                                     // message to be logged
00286         mmr << "ModuleMemoryReport> Each line has module label and: \n";
00287         mmr << "  (after early ignored events) \n";
00288         mmr <<
00289         "    count of times module executed; average increase in vsize \n";
00290         mmr <<
00291         "    maximum increase in vsize; event on which maximum occurred \n";
00292         mmr << "  (during early ignored events) \n";
00293         mmr << "    total and maximum vsize increases \n \n";
00294         for(SignificantModulesMap::iterator im = modules_.begin();
00295             im != modules_.end(); ++im) {
00296           SignificantModule const& m = im->second;
00297           if(m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0) continue;
00298           mmr << im->first << ": ";
00299           mmr << "n = " << m.postEarlyCount;
00300           if(m.postEarlyCount > 0) {
00301             mmr << " avg = " << m.totalDeltaVsize/m.postEarlyCount;
00302           }
00303           mmr <<  " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
00304           if(m.totalEarlyVsize > 0) {
00305             mmr << " early total: " << m.totalEarlyVsize;
00306             mmr << " max: " << m.maxEarlyVsize;
00307           }
00308           mmr << "\n";
00309         }
00310       } // end of if; mmr goes out of scope; log message is queued
00311 
00312       Service<JobReport> reportSvc;
00313                                                                 // changelog 1
00314 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00315 #ifdef  SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00316 //     std::map<std::string, double> reportData;
00317       std::map<std::string, std::string> reportData;
00318 
00319       if(eventL2_.vsize > 0)
00320               eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
00321       if(eventL1_.vsize > 0)
00322               eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
00323       if(eventM_.vsize > 0)
00324               eventStatOutput("LargestVsizeIncreaseEvent", eventM_,  reportData);
00325       if(eventR1_.vsize > 0)
00326               eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
00327       if(eventR2_.vsize > 0)
00328               eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
00329       if(eventT3_.vsize > 0)
00330               eventStatOutput("ThirdLargestVsizeEventT3",  eventT3_, reportData);
00331       if(eventT2_.vsize > 0)
00332               eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
00333       if(eventT1_.vsize > 0)
00334               eventStatOutput("LargestVsizeEventT1",       eventT1_, reportData);
00335 
00336       if(eventRssT3_.rss > 0)
00337         eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
00338       if(eventRssT2_.rss > 0)
00339         eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
00340       if(eventRssT1_.rss > 0)
00341         eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
00342       if(eventDeltaRssT3_.deltaRss > 0)
00343         eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
00344       if(eventDeltaRssT2_.deltaRss > 0)
00345         eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
00346       if(eventDeltaRssT1_.deltaRss > 0)
00347         eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
00348 
00349 #ifdef __linux__
00350       struct mallinfo minfo = mallinfo();
00351       reportData.insert(
00352         std::make_pair("HEAP_ARENA_SIZE_BYTES", i2str(minfo.arena)));
00353       reportData.insert(
00354         std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", i2str(minfo.ordblks)));
00355       reportData.insert(
00356         std::make_pair("HEAP_TOP_FREE_BYTES", i2str(minfo.keepcost)));
00357       reportData.insert(
00358         std::make_pair("HEAP_MAPPED_SIZE_BYTES", i2str(minfo.hblkhd)));
00359       reportData.insert(
00360         std::make_pair("HEAP_MAPPED_N_CHUNKS", i2str(minfo.hblks)));
00361       reportData.insert(
00362         std::make_pair("HEAP_USED_BYTES", i2str(minfo.uordblks)));
00363       reportData.insert(
00364         std::make_pair("HEAP_UNUSED_BYTES", i2str(minfo.fordblks)));
00365 #endif
00366 
00367       // Report Growth rates for VSize and Rss
00368       reportData.insert(
00369         std::make_pair("AverageGrowthRateVsize", d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
00370       reportData.insert(
00371         std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
00372       reportData.insert(
00373         std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
00374       reportData.insert(
00375         std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
00376 
00377       if(moduleSummaryRequested_) {                                // changelog 2
00378         for(SignificantModulesMap::iterator im = modules_.begin();
00379             im != modules_.end(); ++im) {
00380           SignificantModule const& m = im->second;
00381           if(m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0) continue;
00382           std::string label = im->first+":";
00383           reportData.insert(std::make_pair(label+"PostEarlyCount", i2str(m.postEarlyCount)));
00384           if(m.postEarlyCount > 0) {
00385             reportData.insert(std::make_pair(label+"AverageDeltaVsize",
00386                                              d2str(m.totalDeltaVsize/m.postEarlyCount)));
00387           }
00388                 reportData.insert(std::make_pair(label+"MaxDeltaVsize", d2str(m.maxDeltaVsize)));
00389           if(m.totalEarlyVsize > 0) {
00390             reportData.insert(std::make_pair(label+"TotalEarlyVsize", d2str(m.totalEarlyVsize)));
00391             reportData.insert(std::make_pair(label+"MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
00392           }
00393         }
00394       }
00395 
00396       std::map<std::string, std::string> reportMemoryProperties;
00397 
00398       if(FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
00399         char buf[128];
00400         char space[] = " ";
00401         size_t value;
00402 
00403         while(fgets(buf, sizeof(buf), fmeminfo)) {
00404           char* token = NULL;
00405           token = strtok(buf, space);
00406           if(token != NULL) {
00407             value = atol(strtok(NULL, space));
00408             std::string category = token;
00409             reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token)-1), i2str(value)));
00410           }
00411         }
00412 
00413         fclose(fmeminfo);
00414       }
00415 
00416 //      reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
00417       reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
00418       reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
00419 #endif
00420 
00421 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
00422       std::vector<std::string> reportData;
00423 
00424       if(eventL2_.vsize > 0) reportData.push_back(
00425               eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
00426       if(eventL1_.vsize > 0) reportData.push_back(
00427               eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
00428       if(eventM_.vsize > 0) reportData.push_back(
00429               eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
00430       if(eventR1_.vsize > 0) reportData.push_back(
00431               eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
00432       if(eventR2_.vsize > 0) reportData.push_back(
00433               eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
00434       if(eventT3_.vsize > 0) reportData.push_back(
00435               eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
00436       if(eventT2_.vsize > 0) reportData.push_back(
00437               eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
00438       if(eventT1_.vsize > 0) reportData.push_back(
00439               eventStatOutput("LargestVsizeEventT1", eventT1_));
00440 
00441       if(eventRssT3_.rss > 0)
00442         eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
00443       if(eventRssT2_.rss > 0)
00444         eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
00445       if(eventRssT1_.rss > 0)
00446         eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
00447       if(eventDeltaRssT3_.deltaRss > 0)
00448         eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
00449       if(eventDeltaRssT2_.deltaRss > 0)
00450         eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
00451       if(eventDeltaRssT1_.deltaRss > 0)
00452         eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
00453 
00454       struct mallinfo minfo = mallinfo();
00455       reportData.push_back(
00456         mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
00457       reportData.push_back(
00458         mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
00459       reportData.push_back(
00460         mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
00461       reportData.push_back(
00462         mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
00463       reportData.push_back(
00464         mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
00465       reportData.push_back(
00466         mallOutput("HEAP_USED_BYTES", minfo.uordblks));
00467       reportData.push_back(
00468         mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
00469 
00470       // Report Growth rates for VSize and Rss
00471       reportData.insert(
00472         std::make_pair("AverageGrowthRateVsize", d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
00473       reportData.insert(
00474         std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
00475       reportData.insert(
00476         std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
00477       reportData.insert(
00478         std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
00479 
00480       reportSvc->reportMemoryInfo(reportData);
00481       // This is a form of reportMemoryInfo taking s vector, not a map
00482 #endif
00483     } // postEndJob
00484 
00485     void SimpleMemoryCheck::preEventProcessing(EventID const& iID, Timestamp const&) {
00486       currentEventID_ = iID;                                        // changelog 2
00487     }
00488 
00489     void SimpleMemoryCheck::postEventProcessing(Event const& e, EventSetup const&) {
00490       ++count_;
00491       update();
00492       if (monitorPssAndPrivate_) {
00493         currentSmaps_ = fetchSmaps();
00494       }
00495       updateEventStats(e.id());
00496       if(oncePerEventMode_) {
00497         // should probably use be Run:Event or count_ for the label and name
00498         updateMax();
00499         andPrint("event", "", "");
00500       }
00501     }
00502 
00503     void SimpleMemoryCheck::preModule(ModuleDescription const&) {
00504       update();                                                        // changelog 2
00505       moduleEntryVsize_ = current_->vsize;
00506     }
00507 
00508     void SimpleMemoryCheck::postModule(ModuleDescription const& md) {
00509       if(!oncePerEventMode_) {
00510         updateAndPrint("module", md.moduleLabel(), md.moduleName());
00511       } else if(moduleSummaryRequested_) {                        // changelog 2
00512         update();
00513       }
00514       if(moduleSummaryRequested_) {                                // changelog 2
00515         double dv = current_->vsize - moduleEntryVsize_;
00516         std::string label =  md.moduleLabel();
00517         updateModuleMemoryStats (modules_[label], dv);
00518       }
00519     }
00520 
00521     void SimpleMemoryCheck::postFork(unsigned int, unsigned int) {
00522 #ifdef LINUX
00523       if(0 != smapsFile_) {
00524         fclose(smapsFile_);
00525       }
00526       openFiles();
00527 #endif      
00528     }
00529 
00530     void SimpleMemoryCheck::update() {
00531       std::swap(current_, previous_);
00532       *current_ = fetch();
00533     }
00534 
00535     void SimpleMemoryCheck::updateMax() {
00536       if((*current_ > max_) || oncePerEventMode_) {
00537           if(count_ >= num_to_skip_) {
00538           }
00539           max_ = *current_;
00540         }
00541     }
00542 
00543     void SimpleMemoryCheck::updateEventStats(EventID const& e) {
00544       if(count_ < num_to_skip_) return;
00545       if(count_ == num_to_skip_) {
00546         eventT1_.set(0, 0, e, this);
00547         eventM_.set (0, 0, e, this);
00548         eventRssT1_.set(0, 0, e, this);
00549         eventDeltaRssT1_.set(0, 0, e, this);
00550         return;
00551       }
00552       double vsize = current_->vsize;
00553       double deltaVsize = vsize - eventT1_.vsize;
00554 
00555       // Update significative events for Vsize
00556       if(vsize > eventT1_.vsize) {
00557         double deltaRss = current_->rss - eventT1_.rss;
00558         eventT3_ = eventT2_;
00559         eventT2_ = eventT1_;
00560         eventT1_.set(deltaVsize, deltaRss, e, this);
00561       } else if(vsize > eventT2_.vsize) {
00562         double deltaRss = current_->rss - eventT1_.rss;
00563         eventT3_ = eventT2_;
00564         eventT2_.set(deltaVsize, deltaRss, e, this);
00565       } else if(vsize > eventT3_.vsize) {
00566         double deltaRss = current_->rss - eventT1_.rss;
00567         eventT3_.set(deltaVsize, deltaRss, e, this);
00568       }
00569 
00570       if(deltaVsize > eventM_.deltaVsize) {
00571         double deltaRss = current_->rss - eventM_.rss;
00572         if(eventL1_.deltaVsize >= eventR1_.deltaVsize) {
00573           eventL2_ = eventL1_;
00574         } else {
00575           eventL2_ = eventR1_;
00576         }
00577         eventL1_ = eventM_;
00578         eventM_.set(deltaVsize, deltaRss, e, this);
00579         eventR1_ = SignificantEvent();
00580         eventR2_ = SignificantEvent();
00581       } else if(deltaVsize > eventR1_.deltaVsize) {
00582         double deltaRss = current_->rss - eventM_.rss;
00583         eventR2_ = eventR1_;
00584         eventR1_.set(deltaVsize, deltaRss, e, this);
00585       } else if(deltaVsize > eventR2_.deltaVsize) {
00586         double deltaRss = current_->rss - eventR1_.rss;
00587         eventR2_.set(deltaVsize, deltaRss, e, this);
00588       }
00589 
00590       // Update significative events for Rss
00591       double rss = current_->rss;
00592       double deltaRss = rss - eventRssT1_.rss;
00593 
00594       if(rss > eventRssT1_.rss) {
00595         eventRssT3_ = eventRssT2_;
00596         eventRssT2_ = eventRssT1_;
00597         eventRssT1_.set(deltaVsize, deltaRss, e, this);
00598       } else if(rss > eventRssT2_.rss) {
00599         eventRssT3_ = eventRssT2_;
00600         eventRssT2_.set(deltaVsize, deltaRss, e, this);
00601       } else if(rss > eventRssT3_.rss) {
00602         eventRssT3_.set(deltaVsize, deltaRss, e, this);
00603       }
00604       if(deltaRss > eventDeltaRssT1_.deltaRss) {
00605         eventDeltaRssT3_ = eventDeltaRssT2_;
00606         eventDeltaRssT2_ = eventDeltaRssT1_;
00607         eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
00608       } else if(deltaRss > eventDeltaRssT2_.deltaRss) {
00609         eventDeltaRssT3_ = eventDeltaRssT2_;
00610         eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
00611       } else if(deltaRss > eventDeltaRssT3_.deltaRss) {
00612         eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
00613       }
00614     } // updateEventStats
00615 
00616     void SimpleMemoryCheck::andPrint(std::string const& type,
00617                     std::string const& mdlabel, std::string const& mdname) const {
00618       if(not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
00619         if(count_ >= num_to_skip_) {
00620           double deltaVSIZE = current_->vsize - max_.vsize;
00621           double deltaRSS   = current_->rss - max_.rss;
00622           if(!showMallocInfo_) {  // default
00623             LogWarning("MemoryCheck")
00624             << "MemoryCheck: " << type << " "
00625             << mdname << ":" << mdlabel
00626             << " VSIZE " << current_->vsize << " " << deltaVSIZE
00627             << " RSS " << current_->rss << " " << deltaRSS
00628             << "\n";
00629           } else {
00630 #ifdef __linux__
00631             struct mallinfo minfo = mallinfo();
00632 #endif
00633             LogWarning("MemoryCheck")
00634             << "MemoryCheck: " << type << " "
00635             << mdname << ":" << mdlabel
00636             << " VSIZE " << current_->vsize << " " << deltaVSIZE
00637             << " RSS " << current_->rss << " " << deltaRSS
00638 #ifdef __linux__
00639             << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena
00640             << " N-UNUSED-CHUNKS " << minfo.ordblks
00641             << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
00642             << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd
00643             << " N-CHUNKS " << minfo.hblks << " ]"
00644             << " HEAP-USED-BYTES " << minfo.uordblks
00645             << " HEAP-UNUSED-BYTES " << minfo.fordblks
00646 #endif
00647             << "\n";
00648           }
00649         }
00650       }
00651     }
00652 
00653     void SimpleMemoryCheck::updateAndPrint(std::string const& type,
00654                     std::string const& mdlabel, std::string const& mdname) {
00655       update();
00656       andPrint(type, mdlabel, mdname);
00657       updateMax();
00658     }
00659 
00660 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00661     void
00662     SimpleMemoryCheck::eventStatOutput(std::string title,
00663                                        SignificantEvent const& e,
00664                                        std::map<std::string, std::string>& m) const {
00665       { std::ostringstream os;
00666         os << title << "-a-COUNT";
00667         m.insert(std::make_pair(os.str(), i2str(e.count))); }
00668       { std::ostringstream os;
00669         os << title << "-b-RUN";
00670         m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run())))); }
00671       { std::ostringstream os;
00672         os << title << "-c-EVENT";
00673         m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event())))); }
00674       { std::ostringstream os;
00675         os << title << "-d-VSIZE";
00676         m.insert(std::make_pair(os.str(), d2str(e.vsize))); }
00677       { std::ostringstream os;
00678         os << title << "-e-DELTV";
00679         m.insert(std::make_pair(os.str(), d2str(e.deltaVsize))); }
00680       { std::ostringstream os;
00681         os << title << "-f-RSS";
00682         m.insert(std::make_pair(os.str(), d2str(e.rss))); }
00683       if (monitorPssAndPrivate_) {
00684         { std::ostringstream os;
00685           os << title << "-g-PRIVATE";
00686           m.insert(std::make_pair(os.str(), d2str(e.privateSize))); }
00687         { std::ostringstream os;
00688           os << title << "-h-PSS";
00689           m.insert(std::make_pair(os.str(), d2str(e.pss))); }
00690       }
00691     } // eventStatOutput
00692 #endif
00693 
00694 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
00695     std::string
00696     SimpleMemoryCheck::eventStatOutput(std::string title,
00697                                            SignificantEvent const& e) const {
00698       std::ostringstream os;
00699       os << "  <" << title << ">\n";
00700       os << "    " << e.count << ": " << e.event;
00701       os << " vsize " << e.vsize-e.deltaVsize << " + " << e.deltaVsize
00702                                               << " = " << e.vsize;
00703       os << "  rss: " << e.rss << "\n";
00704       os << "  </" << title << ">\n";
00705       return os.str();
00706     } // eventStatOutput
00707 
00708     std::string
00709     SimpleMemoryCheck::mallOutput(std::string title, size_t const& n) const {
00710       std::ostringstream os;
00711       os << "  <" << title << ">\n";
00712       os << "    " << n << "\n";
00713       os << "  </" << title << ">\n";
00714       return os.str();
00715     }
00716 #endif
00717                                                                 // changelog 2
00718     void
00719     SimpleMemoryCheck::updateModuleMemoryStats(SignificantModule& m,
00720                                                double dv) {
00721       if(count_ < num_to_skip_) {
00722         m.totalEarlyVsize += dv;
00723         if(dv > m.maxEarlyVsize)  m.maxEarlyVsize = dv;
00724       } else {
00725         ++m.postEarlyCount;
00726         m.totalDeltaVsize += dv;
00727         if(dv > m.maxDeltaVsize) {
00728           m.maxDeltaVsize = dv;
00729           m.eventMaxDeltaV = currentEventID_;
00730         }
00731       }
00732     } //updateModuleMemoryStats
00733 
00734     std::ostream&
00735     operator<< (std::ostream& os,
00736                 SimpleMemoryCheck::SignificantEvent const& se) {
00737       os << "[" << se.count << "] "
00738       << se.event << "  vsize = " << se.vsize
00739       << " deltaVsize = " << se.deltaVsize
00740       << " rss = " << se.rss << " delta = " << se.deltaRss;
00741 
00742       if (se.monitorPssAndPrivate) {
00743         os <<" private = "<<se.privateSize<<" pss = "<<se.pss;
00744       }
00745       return os;
00746     }
00747 
00748     std::ostream&
00749     operator<< (std::ostream& os,
00750                 SimpleMemoryCheck::SignificantModule const& sm) {
00751       if(sm.postEarlyCount > 0) {
00752         os << "\nPost Early Events:  TotalDeltaVsize: " << sm.totalDeltaVsize
00753         << " (avg: " << sm.totalDeltaVsize/sm.postEarlyCount
00754         << "; max: " << sm.maxDeltaVsize
00755         << " during " << sm.eventMaxDeltaV << ")";
00756       }
00757       if(sm.totalEarlyVsize > 0) {
00758         os << "\n     Early Events:  TotalDeltaVsize: " << sm.totalEarlyVsize
00759         << " (max: " << sm.maxEarlyVsize << ")";
00760       }
00761 
00762       return os;
00763     }
00764 
00765   } // end namespace service
00766 } // end namespace edm
00767