CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_13_patch3/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       typedef MallocOpts::opt_type opt_type;
00171       MallocOptionSetter& mopts = getGlobalOptionSetter();
00172 
00173       opt_type
00174       p_mmap_max = iPS.getUntrackedParameter<int>("M_MMAP_MAX"),
00175       p_trim_thr = iPS.getUntrackedParameter<int>("M_TRIM_THRESHOLD"),
00176       p_top_pad = iPS.getUntrackedParameter<int>("M_TOP_PAD"),
00177       p_mmap_thr = iPS.getUntrackedParameter<int>("M_MMAP_THRESHOLD");
00178 
00179       if(p_mmap_max >= 0) mopts.set_mmap_max(p_mmap_max);
00180       if(p_trim_thr >= 0) mopts.set_trim_thr(p_trim_thr);
00181       if(p_top_pad >= 0) mopts.set_top_pad(p_top_pad);
00182       if(p_mmap_thr >= 0) mopts.set_mmap_thr(p_mmap_thr);
00183 
00184       mopts.adjustMallocParams();
00185 
00186       if(mopts.hasErrors()) {
00187         LogWarning("MemoryCheck")
00188         << "ERROR: Problem with setting malloc options\n"
00189         << mopts.error_message();
00190       }
00191 
00192       if(iPS.getUntrackedParameter<bool>("dump") == true) {
00193         MallocOpts mo = mopts.get();
00194         LogWarning("MemoryCheck")
00195         << "Malloc options: " << mo << "\n";
00196       }
00197     }
00198 
00199     SimpleMemoryCheck::~SimpleMemoryCheck() {
00200 #ifdef LINUX
00201       if(0 != smapsFile_) {
00202         fclose(smapsFile_);
00203       }
00204 #endif
00205       if (smapsLineBuffer_) {
00206         //getline will create the memory using malloc
00207         free(smapsLineBuffer_);
00208       }
00209     }
00210 
00211     void SimpleMemoryCheck::fillDescriptions(ConfigurationDescriptions& descriptions) {
00212       ParameterSetDescription desc;
00213       desc.addUntracked<int>("ignoreTotal", 1);
00214       desc.addUntracked<bool>("showMallocInfo", false);
00215       desc.addUntracked<bool>("oncePerEventMode", false);
00216       desc.addUntracked<bool>("jobReportOutputOnly", false);
00217       desc.addUntracked<bool>("monitorPssAndPrivate", false);
00218       desc.addUntracked<bool>("moduleMemorySummary", false);
00219       desc.addUntracked<int>("M_MMAP_MAX", -1);
00220       desc.addUntracked<int>("M_TRIM_THRESHOLD", -1);
00221       desc.addUntracked<int>("M_TOP_PAD", -1);
00222       desc.addUntracked<int>("M_MMAP_THRESHOLD", -1);
00223       desc.addUntracked<bool>("dump", false);
00224       descriptions.add("SimpleMemoryCheck", desc);
00225     }
00226 
00227     void SimpleMemoryCheck::openFiles() {
00228 #ifdef LINUX
00229       if (monitorPssAndPrivate_) {
00230         std::ostringstream smapsNameOst;
00231         smapsNameOst <<"/proc/"<<getpid()<<"/smaps";
00232         if((smapsFile_ =fopen(smapsNameOst.str().c_str(), "r"))==0) {
00233           throw Exception(errors::Configuration) <<"Failed to open smaps file "<<smapsNameOst.str()<<std::endl;
00234         }
00235       }
00236 #endif
00237     }
00238 
00239     void SimpleMemoryCheck::postBeginJob() {
00240         growthRateVsize_ = current_->vsize;
00241         growthRateRss_ = current_->rss;
00242     }
00243 
00244     void SimpleMemoryCheck::preSourceConstruction(ModuleDescription const& md) {
00245       updateAndPrint("pre-ctor", md.moduleLabel(), md.moduleName());
00246     }
00247 
00248 
00249     void SimpleMemoryCheck::postSourceConstruction(ModuleDescription const& md) {
00250       updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
00251     }
00252 
00253     void SimpleMemoryCheck::postSource() {
00254       updateAndPrint("module", "source", "source");
00255     }
00256 
00257     void SimpleMemoryCheck::postModuleConstruction(ModuleDescription const& md) {
00258       updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
00259     }
00260 
00261     void SimpleMemoryCheck::postModuleBeginJob(ModuleDescription const& md) {
00262       updateAndPrint("beginJob", md.moduleLabel(), md.moduleName());
00263     }
00264 
00265     void SimpleMemoryCheck::postEndJob() {
00266       if(not jobReportOutputOnly_) {
00267         LogAbsolute("MemoryReport")                                 // changelog 1
00268         << "MemoryReport> Peak virtual size " << eventT1_.vsize << " Mbytes"
00269         << "\n"
00270         << " Key events increasing vsize: \n"
00271         << eventL2_ << "\n"
00272         << eventL1_ << "\n"
00273         << eventM_  << "\n"
00274         << eventR1_ << "\n"
00275         << eventR2_ << "\n"
00276         << eventT3_ << "\n"
00277         << eventT2_ << "\n"
00278         << eventT1_ ;
00279       }
00280       if(moduleSummaryRequested_ and not jobReportOutputOnly_) {                                // changelog 1
00281         LogAbsolute mmr("ModuleMemoryReport"); // at end of if block, mmr
00282                                                     // is destructed, causing
00283                                                     // message to be logged
00284         mmr << "ModuleMemoryReport> Each line has module label and: \n";
00285         mmr << "  (after early ignored events) \n";
00286         mmr <<
00287         "    count of times module executed; average increase in vsize \n";
00288         mmr <<
00289         "    maximum increase in vsize; event on which maximum occurred \n";
00290         mmr << "  (during early ignored events) \n";
00291         mmr << "    total and maximum vsize increases \n \n";
00292         for(SignificantModulesMap::iterator im = modules_.begin();
00293             im != modules_.end(); ++im) {
00294           SignificantModule const& m = im->second;
00295           if(m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0) continue;
00296           mmr << im->first << ": ";
00297           mmr << "n = " << m.postEarlyCount;
00298           if(m.postEarlyCount > 0) {
00299             mmr << " avg = " << m.totalDeltaVsize/m.postEarlyCount;
00300           }
00301           mmr <<  " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
00302           if(m.totalEarlyVsize > 0) {
00303             mmr << " early total: " << m.totalEarlyVsize;
00304             mmr << " max: " << m.maxEarlyVsize;
00305           }
00306           mmr << "\n";
00307         }
00308       } // end of if; mmr goes out of scope; log message is queued
00309 
00310       Service<JobReport> reportSvc;
00311                                                                 // changelog 1
00312 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00313 #ifdef  SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00314 //     std::map<std::string, double> reportData;
00315       std::map<std::string, std::string> reportData;
00316 
00317       if(eventL2_.vsize > 0)
00318               eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
00319       if(eventL1_.vsize > 0)
00320               eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
00321       if(eventM_.vsize > 0)
00322               eventStatOutput("LargestVsizeIncreaseEvent", eventM_,  reportData);
00323       if(eventR1_.vsize > 0)
00324               eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
00325       if(eventR2_.vsize > 0)
00326               eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
00327       if(eventT3_.vsize > 0)
00328               eventStatOutput("ThirdLargestVsizeEventT3",  eventT3_, reportData);
00329       if(eventT2_.vsize > 0)
00330               eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
00331       if(eventT1_.vsize > 0)
00332               eventStatOutput("LargestVsizeEventT1",       eventT1_, reportData);
00333 
00334       if(eventRssT3_.rss > 0)
00335         eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
00336       if(eventRssT2_.rss > 0)
00337         eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
00338       if(eventRssT1_.rss > 0)
00339         eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
00340       if(eventDeltaRssT3_.deltaRss > 0)
00341         eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
00342       if(eventDeltaRssT2_.deltaRss > 0)
00343         eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
00344       if(eventDeltaRssT1_.deltaRss > 0)
00345         eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
00346 
00347 #ifdef __linux__
00348       struct mallinfo minfo = mallinfo();
00349       reportData.insert(
00350         std::make_pair("HEAP_ARENA_SIZE_BYTES", i2str(minfo.arena)));
00351       reportData.insert(
00352         std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", i2str(minfo.ordblks)));
00353       reportData.insert(
00354         std::make_pair("HEAP_TOP_FREE_BYTES", i2str(minfo.keepcost)));
00355       reportData.insert(
00356         std::make_pair("HEAP_MAPPED_SIZE_BYTES", i2str(minfo.hblkhd)));
00357       reportData.insert(
00358         std::make_pair("HEAP_MAPPED_N_CHUNKS", i2str(minfo.hblks)));
00359       reportData.insert(
00360         std::make_pair("HEAP_USED_BYTES", i2str(minfo.uordblks)));
00361       reportData.insert(
00362         std::make_pair("HEAP_UNUSED_BYTES", i2str(minfo.fordblks)));
00363 #endif
00364 
00365       // Report Growth rates for VSize and Rss
00366       reportData.insert(
00367         std::make_pair("AverageGrowthRateVsize", d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
00368       reportData.insert(
00369         std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
00370       reportData.insert(
00371         std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
00372       reportData.insert(
00373         std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
00374 
00375       if(moduleSummaryRequested_) {                                // changelog 2
00376         for(SignificantModulesMap::iterator im = modules_.begin();
00377             im != modules_.end(); ++im) {
00378           SignificantModule const& m = im->second;
00379           if(m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0) continue;
00380           std::string label = im->first+":";
00381           reportData.insert(std::make_pair(label+"PostEarlyCount", i2str(m.postEarlyCount)));
00382           if(m.postEarlyCount > 0) {
00383             reportData.insert(std::make_pair(label+"AverageDeltaVsize",
00384                                              d2str(m.totalDeltaVsize/m.postEarlyCount)));
00385           }
00386                 reportData.insert(std::make_pair(label+"MaxDeltaVsize", d2str(m.maxDeltaVsize)));
00387           if(m.totalEarlyVsize > 0) {
00388             reportData.insert(std::make_pair(label+"TotalEarlyVsize", d2str(m.totalEarlyVsize)));
00389             reportData.insert(std::make_pair(label+"MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
00390           }
00391         }
00392       }
00393 
00394       std::map<std::string, std::string> reportMemoryProperties;
00395 
00396       if(FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
00397         char buf[128];
00398         char space[] = " ";
00399         size_t value;
00400 
00401         while(fgets(buf, sizeof(buf), fmeminfo)) {
00402           char* token = NULL;
00403           token = strtok(buf, space);
00404           if(token != NULL) {
00405             value = atol(strtok(NULL, space));
00406             std::string category = token;
00407             reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token)-1), i2str(value)));
00408           }
00409         }
00410 
00411         fclose(fmeminfo);
00412       }
00413 
00414 //      reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
00415       reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
00416       reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
00417 #endif
00418 
00419 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
00420       std::vector<std::string> reportData;
00421 
00422       if(eventL2_.vsize > 0) reportData.push_back(
00423               eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
00424       if(eventL1_.vsize > 0) reportData.push_back(
00425               eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
00426       if(eventM_.vsize > 0) reportData.push_back(
00427               eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
00428       if(eventR1_.vsize > 0) reportData.push_back(
00429               eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
00430       if(eventR2_.vsize > 0) reportData.push_back(
00431               eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
00432       if(eventT3_.vsize > 0) reportData.push_back(
00433               eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
00434       if(eventT2_.vsize > 0) reportData.push_back(
00435               eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
00436       if(eventT1_.vsize > 0) reportData.push_back(
00437               eventStatOutput("LargestVsizeEventT1", eventT1_));
00438 
00439       if(eventRssT3_.rss > 0)
00440         eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
00441       if(eventRssT2_.rss > 0)
00442         eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
00443       if(eventRssT1_.rss > 0)
00444         eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
00445       if(eventDeltaRssT3_.deltaRss > 0)
00446         eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
00447       if(eventDeltaRssT2_.deltaRss > 0)
00448         eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
00449       if(eventDeltaRssT1_.deltaRss > 0)
00450         eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
00451 
00452       struct mallinfo minfo = mallinfo();
00453       reportData.push_back(
00454         mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
00455       reportData.push_back(
00456         mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
00457       reportData.push_back(
00458         mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
00459       reportData.push_back(
00460         mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
00461       reportData.push_back(
00462         mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
00463       reportData.push_back(
00464         mallOutput("HEAP_USED_BYTES", minfo.uordblks));
00465       reportData.push_back(
00466         mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
00467 
00468       // Report Growth rates for VSize and Rss
00469       reportData.insert(
00470         std::make_pair("AverageGrowthRateVsize", d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
00471       reportData.insert(
00472         std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
00473       reportData.insert(
00474         std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
00475       reportData.insert(
00476         std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
00477 
00478       reportSvc->reportMemoryInfo(reportData);
00479       // This is a form of reportMemoryInfo taking s vector, not a map
00480 #endif
00481     } // postEndJob
00482 
00483     void SimpleMemoryCheck::preEventProcessing(EventID const& iID, Timestamp const&) {
00484       currentEventID_ = iID;                                        // changelog 2
00485     }
00486 
00487     void SimpleMemoryCheck::postEventProcessing(Event const& e, EventSetup const&) {
00488       ++count_;
00489       update();
00490       if (monitorPssAndPrivate_) {
00491         currentSmaps_ = fetchSmaps();
00492       }
00493       updateEventStats(e.id());
00494       if(oncePerEventMode_) {
00495         // should probably use be Run:Event or count_ for the label and name
00496         updateMax();
00497         andPrint("event", "", "");
00498       }
00499     }
00500 
00501     void SimpleMemoryCheck::preModule(ModuleDescription const&) {
00502       update();                                                        // changelog 2
00503       moduleEntryVsize_ = current_->vsize;
00504     }
00505 
00506     void SimpleMemoryCheck::postModule(ModuleDescription const& md) {
00507       if(!oncePerEventMode_) {
00508         updateAndPrint("module", md.moduleLabel(), md.moduleName());
00509       } else if(moduleSummaryRequested_) {                        // changelog 2
00510         update();
00511       }
00512       if(moduleSummaryRequested_) {                                // changelog 2
00513         double dv = current_->vsize - moduleEntryVsize_;
00514         std::string label =  md.moduleLabel();
00515         updateModuleMemoryStats (modules_[label], dv);
00516       }
00517     }
00518 
00519     void SimpleMemoryCheck::postFork(unsigned int, unsigned int) {
00520 #ifdef LINUX
00521       if(0 != smapsFile_) {
00522         fclose(smapsFile_);
00523       }
00524       openFiles();
00525 #endif      
00526     }
00527 
00528     void SimpleMemoryCheck::update() {
00529       std::swap(current_, previous_);
00530       *current_ = fetch();
00531     }
00532 
00533     void SimpleMemoryCheck::updateMax() {
00534       if((*current_ > max_) || oncePerEventMode_) {
00535           if(count_ >= num_to_skip_) {
00536           }
00537           max_ = *current_;
00538         }
00539     }
00540 
00541     void SimpleMemoryCheck::updateEventStats(EventID const& e) {
00542       if(count_ < num_to_skip_) return;
00543       if(count_ == num_to_skip_) {
00544         eventT1_.set(0, 0, e, this);
00545         eventM_.set (0, 0, e, this);
00546         eventRssT1_.set(0, 0, e, this);
00547         eventDeltaRssT1_.set(0, 0, e, this);
00548         return;
00549       }
00550       double vsize = current_->vsize;
00551       double deltaVsize = vsize - eventT1_.vsize;
00552 
00553       // Update significative events for Vsize
00554       if(vsize > eventT1_.vsize) {
00555         double deltaRss = current_->rss - eventT1_.rss;
00556         eventT3_ = eventT2_;
00557         eventT2_ = eventT1_;
00558         eventT1_.set(deltaVsize, deltaRss, e, this);
00559       } else if(vsize > eventT2_.vsize) {
00560         double deltaRss = current_->rss - eventT1_.rss;
00561         eventT3_ = eventT2_;
00562         eventT2_.set(deltaVsize, deltaRss, e, this);
00563       } else if(vsize > eventT3_.vsize) {
00564         double deltaRss = current_->rss - eventT1_.rss;
00565         eventT3_.set(deltaVsize, deltaRss, e, this);
00566       }
00567 
00568       if(deltaVsize > eventM_.deltaVsize) {
00569         double deltaRss = current_->rss - eventM_.rss;
00570         if(eventL1_.deltaVsize >= eventR1_.deltaVsize) {
00571           eventL2_ = eventL1_;
00572         } else {
00573           eventL2_ = eventR1_;
00574         }
00575         eventL1_ = eventM_;
00576         eventM_.set(deltaVsize, deltaRss, e, this);
00577         eventR1_ = SignificantEvent();
00578         eventR2_ = SignificantEvent();
00579       } else if(deltaVsize > eventR1_.deltaVsize) {
00580         double deltaRss = current_->rss - eventM_.rss;
00581         eventR2_ = eventR1_;
00582         eventR1_.set(deltaVsize, deltaRss, e, this);
00583       } else if(deltaVsize > eventR2_.deltaVsize) {
00584         double deltaRss = current_->rss - eventR1_.rss;
00585         eventR2_.set(deltaVsize, deltaRss, e, this);
00586       }
00587 
00588       // Update significative events for Rss
00589       double rss = current_->rss;
00590       double deltaRss = rss - eventRssT1_.rss;
00591 
00592       if(rss > eventRssT1_.rss) {
00593         eventRssT3_ = eventRssT2_;
00594         eventRssT2_ = eventRssT1_;
00595         eventRssT1_.set(deltaVsize, deltaRss, e, this);
00596       } else if(rss > eventRssT2_.rss) {
00597         eventRssT3_ = eventRssT2_;
00598         eventRssT2_.set(deltaVsize, deltaRss, e, this);
00599       } else if(rss > eventRssT3_.rss) {
00600         eventRssT3_.set(deltaVsize, deltaRss, e, this);
00601       }
00602       if(deltaRss > eventDeltaRssT1_.deltaRss) {
00603         eventDeltaRssT3_ = eventDeltaRssT2_;
00604         eventDeltaRssT2_ = eventDeltaRssT1_;
00605         eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
00606       } else if(deltaRss > eventDeltaRssT2_.deltaRss) {
00607         eventDeltaRssT3_ = eventDeltaRssT2_;
00608         eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
00609       } else if(deltaRss > eventDeltaRssT3_.deltaRss) {
00610         eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
00611       }
00612     } // updateEventStats
00613 
00614     void SimpleMemoryCheck::andPrint(std::string const& type,
00615                     std::string const& mdlabel, std::string const& mdname) const {
00616       if(not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
00617         if(count_ >= num_to_skip_) {
00618           double deltaVSIZE = current_->vsize - max_.vsize;
00619           double deltaRSS   = current_->rss - max_.rss;
00620           if(!showMallocInfo_) {  // default
00621             LogWarning("MemoryCheck")
00622             << "MemoryCheck: " << type << " "
00623             << mdname << ":" << mdlabel
00624             << " VSIZE " << current_->vsize << " " << deltaVSIZE
00625             << " RSS " << current_->rss << " " << deltaRSS
00626             << "\n";
00627           } else {
00628 #ifdef __linux__
00629             struct mallinfo minfo = mallinfo();
00630 #endif
00631             LogWarning("MemoryCheck")
00632             << "MemoryCheck: " << type << " "
00633             << mdname << ":" << mdlabel
00634             << " VSIZE " << current_->vsize << " " << deltaVSIZE
00635             << " RSS " << current_->rss << " " << deltaRSS
00636 #ifdef __linux__
00637             << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena
00638             << " N-UNUSED-CHUNKS " << minfo.ordblks
00639             << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
00640             << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd
00641             << " N-CHUNKS " << minfo.hblks << " ]"
00642             << " HEAP-USED-BYTES " << minfo.uordblks
00643             << " HEAP-UNUSED-BYTES " << minfo.fordblks
00644 #endif
00645             << "\n";
00646           }
00647         }
00648       }
00649     }
00650 
00651     void SimpleMemoryCheck::updateAndPrint(std::string const& type,
00652                     std::string const& mdlabel, std::string const& mdname) {
00653       update();
00654       andPrint(type, mdlabel, mdname);
00655       updateMax();
00656     }
00657 
00658 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00659     void
00660     SimpleMemoryCheck::eventStatOutput(std::string title,
00661                                        SignificantEvent const& e,
00662                                        std::map<std::string, std::string>& m) const {
00663       { std::ostringstream os;
00664         os << title << "-a-COUNT";
00665         m.insert(std::make_pair(os.str(), i2str(e.count))); }
00666       { std::ostringstream os;
00667         os << title << "-b-RUN";
00668         m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run())))); }
00669       { std::ostringstream os;
00670         os << title << "-c-EVENT";
00671         m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event())))); }
00672       { std::ostringstream os;
00673         os << title << "-d-VSIZE";
00674         m.insert(std::make_pair(os.str(), d2str(e.vsize))); }
00675       { std::ostringstream os;
00676         os << title << "-e-DELTV";
00677         m.insert(std::make_pair(os.str(), d2str(e.deltaVsize))); }
00678       { std::ostringstream os;
00679         os << title << "-f-RSS";
00680         m.insert(std::make_pair(os.str(), d2str(e.rss))); }
00681       if (monitorPssAndPrivate_) {
00682         { std::ostringstream os;
00683           os << title << "-g-PRIVATE";
00684           m.insert(std::make_pair(os.str(), d2str(e.privateSize))); }
00685         { std::ostringstream os;
00686           os << title << "-h-PSS";
00687           m.insert(std::make_pair(os.str(), d2str(e.pss))); }
00688       }
00689     } // eventStatOutput
00690 #endif
00691 
00692 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
00693     std::string
00694     SimpleMemoryCheck::eventStatOutput(std::string title,
00695                                            SignificantEvent const& e) const {
00696       std::ostringstream os;
00697       os << "  <" << title << ">\n";
00698       os << "    " << e.count << ": " << e.event;
00699       os << " vsize " << e.vsize-e.deltaVsize << " + " << e.deltaVsize
00700                                               << " = " << e.vsize;
00701       os << "  rss: " << e.rss << "\n";
00702       os << "  </" << title << ">\n";
00703       return os.str();
00704     } // eventStatOutput
00705 
00706     std::string
00707     SimpleMemoryCheck::mallOutput(std::string title, size_t const& n) const {
00708       std::ostringstream os;
00709       os << "  <" << title << ">\n";
00710       os << "    " << n << "\n";
00711       os << "  </" << title << ">\n";
00712       return os.str();
00713     }
00714 #endif
00715                                                                 // changelog 2
00716     void
00717     SimpleMemoryCheck::updateModuleMemoryStats(SignificantModule& m,
00718                                                double dv) {
00719       if(count_ < num_to_skip_) {
00720         m.totalEarlyVsize += dv;
00721         if(dv > m.maxEarlyVsize)  m.maxEarlyVsize = dv;
00722       } else {
00723         ++m.postEarlyCount;
00724         m.totalDeltaVsize += dv;
00725         if(dv > m.maxDeltaVsize) {
00726           m.maxDeltaVsize = dv;
00727           m.eventMaxDeltaV = currentEventID_;
00728         }
00729       }
00730     } //updateModuleMemoryStats
00731 
00732     std::ostream&
00733     operator<< (std::ostream& os,
00734                 SimpleMemoryCheck::SignificantEvent const& se) {
00735       os << "[" << se.count << "] "
00736       << se.event << "  vsize = " << se.vsize
00737       << " deltaVsize = " << se.deltaVsize
00738       << " rss = " << se.rss << " delta = " << se.deltaRss;
00739 
00740       if (se.monitorPssAndPrivate) {
00741         os <<" private = "<<se.privateSize<<" pss = "<<se.pss;
00742       }
00743       return os;
00744     }
00745 
00746     std::ostream&
00747     operator<< (std::ostream& os,
00748                 SimpleMemoryCheck::SignificantModule const& sm) {
00749       if(sm.postEarlyCount > 0) {
00750         os << "\nPost Early Events:  TotalDeltaVsize: " << sm.totalDeltaVsize
00751         << " (avg: " << sm.totalDeltaVsize/sm.postEarlyCount
00752         << "; max: " << sm.maxDeltaVsize
00753         << " during " << sm.eventMaxDeltaV << ")";
00754       }
00755       if(sm.totalEarlyVsize > 0) {
00756         os << "\n     Early Events:  TotalDeltaVsize: " << sm.totalEarlyVsize
00757         << " (max: " << sm.maxEarlyVsize << ")";
00758       }
00759 
00760       return os;
00761     }
00762 
00763   } // end namespace service
00764 } // end namespace edm
00765