CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/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     struct linux_proc {
00072       int pid; // %d
00073       std::string comm;
00074       char state; // %c
00075       int ppid; // %d
00076       int pgrp; // %d
00077       int session; // %d
00078       int tty; // %d
00079       int tpgid; // %d
00080       unsigned long flags; // %lu
00081       unsigned long minflt; // %lu
00082       unsigned long cminflt; // %lu
00083       unsigned long majflt; // %lu
00084       unsigned long cmajflt; // %lu
00085       unsigned long utime; // %lu
00086       unsigned long stime; // %lu
00087       long cutime; // %ld
00088       long cstime; // %ld
00089       long priority; // %ld
00090       long nice; // %ld
00091       long num_threads; // %ld
00092       long itrealvalue; // %ld
00093       int starttime; // %d
00094       unsigned long vsize; // %lu
00095       long rss; // %ld
00096       unsigned long rlim; // %lu
00097       unsigned long startcode; // %lu
00098       unsigned long endcode; // %lu
00099       unsigned long startstack; // %lu
00100       unsigned long kstkesp; // %lu
00101       unsigned long kstkeip; // %lu
00102       unsigned long signal; // %lu
00103       unsigned long blocked; // %lu
00104       unsigned long sigignore; // %lu
00105       unsigned long sigcatch; // %lu
00106       unsigned long wchan; // %lu
00107     };
00108 
00109     class Fetcher {
00110     public:
00111       friend Fetcher& operator>>(Fetcher&, int&);
00112       friend Fetcher& operator>>(Fetcher&, long&);
00113       friend Fetcher& operator>>(Fetcher&, unsigned int&);
00114       friend Fetcher& operator>>(Fetcher&, unsigned long&);
00115       friend Fetcher& operator>>(Fetcher&, char&);
00116       friend Fetcher& operator>>(Fetcher&, std::string&);
00117       
00118       explicit Fetcher(char* buffer) : 
00119         buffer_(buffer),
00120         save_(0),
00121         delims_(" \t\n\f\v\r") {
00122       }
00123     private:
00124       int getInt() {
00125         const char* t = getItem();
00126         //std::cout <<"int '"<<t <<"'"<<std::endl;
00127         return boost::lexical_cast<int>(t);
00128       }
00129       long getLong() {
00130         const char* t = getItem();
00131         //std::cout <<"long '"<<t <<"'"<<std::endl;
00132         return boost::lexical_cast<long>(t);
00133       }
00134       unsigned int getUInt() {
00135         const char* t = getItem();
00136         //std::cout <<"uint '"<<t <<"'"<<std::endl;
00137         return boost::lexical_cast<unsigned int>(t);
00138       }
00139       unsigned long getULong() {
00140         const char* t = getItem();
00141         //std::cout <<"ulong '"<<t <<"'"<<std::endl;
00142         return boost::lexical_cast<unsigned long>(t);
00143       }
00144       char getChar() {
00145         return *getItem();
00146       }
00147       std::string getString() {
00148         return std::string(getItem());
00149       }
00150       char* getItem() {
00151         char* item = strtok_r(buffer_, delims_, &save_); 
00152         assert(item);
00153         buffer_ = 0; // Null for subsequent strtok_r calls.
00154         return item;
00155       }
00156       char* buffer_;
00157       char* save_;
00158       char const* const delims_; 
00159     };
00160     
00161     Fetcher& operator>>(Fetcher& iFetch, int& oValue) {
00162       oValue = iFetch.getInt();
00163       return iFetch;
00164     }
00165     Fetcher& operator>>(Fetcher& iFetch, long& oValue) {
00166       oValue = iFetch.getLong();
00167       return iFetch;
00168     }
00169     Fetcher& operator>>(Fetcher& iFetch, unsigned int& oValue) {
00170       oValue = iFetch.getUInt();
00171       return iFetch;      
00172     }
00173     Fetcher& operator>>(Fetcher& iFetch, unsigned long& oValue) {
00174       oValue = iFetch.getULong();
00175       return iFetch;      
00176     }
00177     Fetcher& operator>>(Fetcher& iFetch, char& oValue) {
00178       oValue = iFetch.getChar();
00179       return iFetch;
00180     }
00181     Fetcher& operator>>(Fetcher& iFetch, std::string& oValue) {
00182       oValue = iFetch.getString();
00183       return iFetch;
00184     }
00185 
00186 
00187     procInfo SimpleMemoryCheck::fetch() {
00188       procInfo ret;
00189 
00190 #ifdef LINUX
00191       double pr_size = 0.0, pr_rssize = 0.0;
00192 
00193       linux_proc pinfo;
00194       int cnt;
00195 
00196       lseek(fd_, 0, SEEK_SET);
00197 
00198       if((cnt = read(fd_, buf_, sizeof(buf_) - 1)) < 0) {
00199         perror("Read of Proc file failed:");
00200         return procInfo();
00201       }
00202 
00203       if(cnt > 0) {
00204         buf_[cnt] = '\0';
00205 
00206 
00207         try {
00208           Fetcher fetcher(buf_);
00209           fetcher >> pinfo.pid
00210           >> pinfo.comm
00211           >> pinfo.state
00212           >> pinfo.ppid
00213           >> pinfo.pgrp
00214           >> pinfo.session
00215           >> pinfo.tty
00216           >> pinfo.tpgid
00217           >> pinfo.flags
00218           >> pinfo.minflt
00219           >> pinfo.cminflt
00220           >> pinfo.majflt
00221           >> pinfo.cmajflt
00222           >> pinfo.utime
00223           >> pinfo.stime
00224           >> pinfo.cutime
00225           >> pinfo.cstime
00226           >> pinfo.priority
00227           >> pinfo.nice
00228           >> pinfo.num_threads
00229           >> pinfo.itrealvalue
00230           >> pinfo.starttime
00231           >> pinfo.vsize
00232           >> pinfo.rss
00233           >> pinfo.rlim
00234           >> pinfo.startcode
00235           >> pinfo.endcode
00236           >> pinfo.startstack
00237           >> pinfo.kstkesp
00238           >> pinfo.kstkeip
00239           >> pinfo.signal
00240           >> pinfo.blocked
00241           >> pinfo.sigignore
00242           >> pinfo.sigcatch
00243           >> pinfo.wchan;
00244         } catch (boost::bad_lexical_cast& iE) {
00245           LogWarning("MemoryCheck")<<"Parsing of Prof file failed:"<<iE.what()<<std::endl;
00246           return procInfo();
00247         }
00248         
00249         // resident set size in pages
00250         pr_size = (double)pinfo.vsize;
00251         pr_rssize = (double)pinfo.rss;
00252 
00253         ret.vsize = pr_size / (1024.0*1024.0);
00254         ret.rss   = (pr_rssize * pg_size_) / (1024.0*1024.0);
00255       }
00256 #else
00257       ret.vsize = 0;
00258       ret.rss = 0;
00259 #endif
00260       return ret;
00261     }
00262     
00263     smapsInfo SimpleMemoryCheck::fetchSmaps() {
00264       smapsInfo ret;
00265       ret.private_ = 0;
00266       ret.pss_ = 0;
00267 #ifdef LINUX
00268       fseek(smapsFile_, 0, SEEK_SET);
00269       ssize_t read;
00270       
00271       /*
00272        The format of the report is
00273        Private_Clean:        0 kB
00274        Private_Dirty:       72 kB
00275        Swap:                 0 kB
00276        Pss:                 72 kB
00277        */
00278       
00279       while ((read = getline(&smapsLineBuffer_, &smapsLineBufferLen_, smapsFile_)) != -1) {
00280         if(read > 14) {
00281           //Private
00282           if(0==strncmp("Private_",smapsLineBuffer_,8)) {
00283             unsigned int value = atoi(smapsLineBuffer_+14);
00284             //Convert from kB to MB
00285             ret.private_ += static_cast<double>(value)/1024.;
00286           } else if(0==strncmp("Pss:",smapsLineBuffer_,4)) {
00287             unsigned int value = atoi(smapsLineBuffer_+4);
00288             //Convert from kB to MB
00289             ret.pss_ += static_cast<double>(value)/1024.;            
00290           }
00291         }
00292       }
00293 #endif
00294       return ret;
00295     }
00296 
00297     double SimpleMemoryCheck::averageGrowthRate(double current, double past, int count) {
00298       return(current-past)/(double)count;
00299     }
00300 
00301     SimpleMemoryCheck::SimpleMemoryCheck(ParameterSet const& iPS,
00302                                          ActivityRegistry&iReg)
00303     : a_()
00304     , b_()
00305     , current_(&a_)
00306     , previous_(&b_)
00307     , pg_size_(sysconf(_SC_PAGESIZE)) // getpagesize()
00308     , num_to_skip_(iPS.getUntrackedParameter<int>("ignoreTotal"))
00309     , showMallocInfo_(iPS.getUntrackedParameter<bool>("showMallocInfo"))
00310     , oncePerEventMode_(iPS.getUntrackedParameter<bool>("oncePerEventMode"))
00311     , jobReportOutputOnly_(iPS.getUntrackedParameter<bool>("jobReportOutputOnly"))
00312     , monitorPssAndPrivate_(iPS.getUntrackedParameter<bool>("monitorPssAndPrivate"))
00313     , count_()
00314     , smapsFile_(0)
00315     , smapsLineBuffer_(NULL)
00316     , smapsLineBufferLen_(0)
00317     , growthRateVsize_()
00318     , growthRateRss_()
00319     , moduleSummaryRequested_(iPS.getUntrackedParameter<bool>("moduleMemorySummary")) {
00320                                                                 // changelog 2
00321       // pg_size = (double)getpagesize();
00322       std::ostringstream ost;
00323 
00324       openFiles();
00325       iReg.watchPostForkReacquireResources(this,&SimpleMemoryCheck::postFork);
00326       
00327       if(!oncePerEventMode_) { // default, prints on increases
00328         iReg.watchPreSourceConstruction(this, &SimpleMemoryCheck::preSourceConstruction);
00329         iReg.watchPostSourceConstruction(this, &SimpleMemoryCheck::postSourceConstruction);
00330         iReg.watchPostSource(this, &SimpleMemoryCheck::postSource);
00331         iReg.watchPostModuleConstruction(this, &SimpleMemoryCheck::postModuleConstruction);
00332         iReg.watchPostModuleBeginJob(this, &SimpleMemoryCheck::postModuleBeginJob);
00333         iReg.watchPostProcessEvent(this, &SimpleMemoryCheck::postEventProcessing);
00334         iReg.watchPostModule(this, &SimpleMemoryCheck::postModule);
00335         iReg.watchPostBeginJob(this, &SimpleMemoryCheck::postBeginJob);
00336         iReg.watchPostEndJob(this, &SimpleMemoryCheck::postEndJob);
00337       } else {
00338         iReg.watchPostProcessEvent(this, &SimpleMemoryCheck::postEventProcessing);
00339         iReg.watchPostEndJob(this, &SimpleMemoryCheck::postEndJob);
00340       }
00341       if(moduleSummaryRequested_) {                                // changelog 2
00342         iReg.watchPreProcessEvent(this, &SimpleMemoryCheck::preEventProcessing);
00343         iReg.watchPreModule(this, &SimpleMemoryCheck::preModule);
00344         if(oncePerEventMode_) {
00345           iReg.watchPostModule(this, &SimpleMemoryCheck::postModule);
00346         }
00347       }
00348 
00349       // The following are not currenty used/implemented below for either
00350       // of the print modes (but are left here for reference)
00351       //  iReg.watchPostBeginJob(this,
00352       //       &SimpleMemoryCheck::postBeginJob);
00353       //  iReg.watchPreProcessEvent(this,
00354       //       &SimpleMemoryCheck::preEventProcessing);
00355       //  iReg.watchPreModule(this,
00356       //       &SimpleMemoryCheck::preModule);
00357 
00358       typedef MallocOpts::opt_type opt_type;
00359       MallocOptionSetter& mopts = getGlobalOptionSetter();
00360 
00361       opt_type
00362       p_mmap_max = iPS.getUntrackedParameter<int>("M_MMAP_MAX"),
00363       p_trim_thr = iPS.getUntrackedParameter<int>("M_TRIM_THRESHOLD"),
00364       p_top_pad = iPS.getUntrackedParameter<int>("M_TOP_PAD"),
00365       p_mmap_thr = iPS.getUntrackedParameter<int>("M_MMAP_THRESHOLD");
00366 
00367       if(p_mmap_max >= 0) mopts.set_mmap_max(p_mmap_max);
00368       if(p_trim_thr >= 0) mopts.set_trim_thr(p_trim_thr);
00369       if(p_top_pad >= 0) mopts.set_top_pad(p_top_pad);
00370       if(p_mmap_thr >= 0) mopts.set_mmap_thr(p_mmap_thr);
00371 
00372       mopts.adjustMallocParams();
00373 
00374       if(mopts.hasErrors()) {
00375         LogWarning("MemoryCheck")
00376         << "ERROR: Problem with setting malloc options\n"
00377         << mopts.error_message();
00378       }
00379 
00380       if(iPS.getUntrackedParameter<bool>("dump") == true) {
00381         MallocOpts mo = mopts.get();
00382         LogWarning("MemoryCheck")
00383         << "Malloc options: " << mo << "\n";
00384       }
00385     }
00386 
00387     SimpleMemoryCheck::~SimpleMemoryCheck() {
00388 #ifdef LINUX
00389       close(fd_);
00390       if(0 != smapsFile_) {
00391         fclose(smapsFile_);
00392       }
00393 #endif
00394       if (smapsLineBuffer_) {
00395         //getline will create the memory using malloc
00396         free(smapsLineBuffer_);
00397       }
00398     }
00399 
00400     void SimpleMemoryCheck::fillDescriptions(ConfigurationDescriptions& descriptions) {
00401       ParameterSetDescription desc;
00402       desc.addUntracked<int>("ignoreTotal", 1);
00403       desc.addUntracked<bool>("showMallocInfo", false);
00404       desc.addUntracked<bool>("oncePerEventMode", false);
00405       desc.addUntracked<bool>("jobReportOutputOnly", false);
00406       desc.addUntracked<bool>("monitorPssAndPrivate", false);
00407       desc.addUntracked<bool>("moduleMemorySummary", false);
00408       desc.addUntracked<int>("M_MMAP_MAX", -1);
00409       desc.addUntracked<int>("M_TRIM_THRESHOLD", -1);
00410       desc.addUntracked<int>("M_TOP_PAD", -1);
00411       desc.addUntracked<int>("M_MMAP_THRESHOLD", -1);
00412       desc.addUntracked<bool>("dump", false);
00413       descriptions.add("SimpleMemoryCheck", desc);
00414     }
00415 
00416     void SimpleMemoryCheck::openFiles() {
00417 #ifdef LINUX
00418       std::ostringstream ost;
00419       ost << "/proc/" << getpid() << "/stat";
00420       fname_ = ost.str();
00421       
00422       if((fd_ = open(ost.str().c_str(), O_RDONLY)) < 0) {
00423         throw Exception(errors::Configuration)
00424         << "Memory checker server: Failed to open " << ost.str() << std::endl;
00425       }
00426       if (monitorPssAndPrivate_) {
00427         std::ostringstream smapsNameOst;
00428         smapsNameOst <<"/proc/"<<getpid()<<"/smaps";
00429         if((smapsFile_ =fopen(smapsNameOst.str().c_str(), "r"))==0) {
00430           throw Exception(errors::Configuration) <<"Failed to open smaps file "<<smapsNameOst.str()<<std::endl;
00431         }
00432       }
00433 #endif
00434     }
00435 
00436     void SimpleMemoryCheck::postBeginJob() {
00437         growthRateVsize_ = current_->vsize;
00438         growthRateRss_ = current_->rss;
00439     }
00440 
00441     void SimpleMemoryCheck::preSourceConstruction(ModuleDescription const& md) {
00442       updateAndPrint("pre-ctor", md.moduleLabel(), md.moduleName());
00443     }
00444 
00445 
00446     void SimpleMemoryCheck::postSourceConstruction(ModuleDescription const& md) {
00447       updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
00448     }
00449 
00450     void SimpleMemoryCheck::postSource() {
00451       updateAndPrint("module", "source", "source");
00452     }
00453 
00454     void SimpleMemoryCheck::postModuleConstruction(ModuleDescription const& md) {
00455       updateAndPrint("ctor", md.moduleLabel(), md.moduleName());
00456     }
00457 
00458     void SimpleMemoryCheck::postModuleBeginJob(ModuleDescription const& md) {
00459       updateAndPrint("beginJob", md.moduleLabel(), md.moduleName());
00460     }
00461 
00462     void SimpleMemoryCheck::postEndJob() {
00463       if(not jobReportOutputOnly_) {
00464         LogAbsolute("MemoryReport")                                 // changelog 1
00465         << "MemoryReport> Peak virtual size " << eventT1_.vsize << " Mbytes"
00466         << "\n"
00467         << " Key events increasing vsize: \n"
00468         << eventL2_ << "\n"
00469         << eventL1_ << "\n"
00470         << eventM_  << "\n"
00471         << eventR1_ << "\n"
00472         << eventR2_ << "\n"
00473         << eventT3_ << "\n"
00474         << eventT2_ << "\n"
00475         << eventT1_ ;
00476       }
00477       if(moduleSummaryRequested_ and not jobReportOutputOnly_) {                                // changelog 1
00478         LogAbsolute mmr("ModuleMemoryReport"); // at end of if block, mmr
00479                                                     // is destructed, causing
00480                                                     // message to be logged
00481         mmr << "ModuleMemoryReport> Each line has module label and: \n";
00482         mmr << "  (after early ignored events) \n";
00483         mmr <<
00484         "    count of times module executed; average increase in vsize \n";
00485         mmr <<
00486         "    maximum increase in vsize; event on which maximum occurred \n";
00487         mmr << "  (during early ignored events) \n";
00488         mmr << "    total and maximum vsize increases \n \n";
00489         for(SignificantModulesMap::iterator im = modules_.begin();
00490             im != modules_.end(); ++im) {
00491           SignificantModule const& m = im->second;
00492           if(m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0) continue;
00493           mmr << im->first << ": ";
00494           mmr << "n = " << m.postEarlyCount;
00495           if(m.postEarlyCount > 0) {
00496             mmr << " avg = " << m.totalDeltaVsize/m.postEarlyCount;
00497           }
00498           mmr <<  " max = " << m.maxDeltaVsize << " " << m.eventMaxDeltaV;
00499           if(m.totalEarlyVsize > 0) {
00500             mmr << " early total: " << m.totalEarlyVsize;
00501             mmr << " max: " << m.maxEarlyVsize;
00502           }
00503           mmr << "\n";
00504         }
00505       } // end of if; mmr goes out of scope; log message is queued
00506 
00507       Service<JobReport> reportSvc;
00508                                                                 // changelog 1
00509 #define SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00510 #ifdef  SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00511 //     std::map<std::string, double> reportData;
00512       std::map<std::string, std::string> reportData;
00513 
00514       if(eventL2_.vsize > 0)
00515               eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_, reportData);
00516       if(eventL1_.vsize > 0)
00517               eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_, reportData);
00518       if(eventM_.vsize > 0)
00519               eventStatOutput("LargestVsizeIncreaseEvent", eventM_,  reportData);
00520       if(eventR1_.vsize > 0)
00521               eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_, reportData);
00522       if(eventR2_.vsize > 0)
00523               eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_, reportData);
00524       if(eventT3_.vsize > 0)
00525               eventStatOutput("ThirdLargestVsizeEventT3",  eventT3_, reportData);
00526       if(eventT2_.vsize > 0)
00527               eventStatOutput("SecondLargestVsizeEventT2", eventT2_, reportData);
00528       if(eventT1_.vsize > 0)
00529               eventStatOutput("LargestVsizeEventT1",       eventT1_, reportData);
00530 
00531       if(eventRssT3_.rss > 0)
00532         eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
00533       if(eventRssT2_.rss > 0)
00534         eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
00535       if(eventRssT1_.rss > 0)
00536         eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
00537       if(eventDeltaRssT3_.deltaRss > 0)
00538         eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
00539       if(eventDeltaRssT2_.deltaRss > 0)
00540         eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
00541       if(eventDeltaRssT1_.deltaRss > 0)
00542         eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
00543 
00544 #ifdef __linux__
00545       struct mallinfo minfo = mallinfo();
00546       reportData.insert(
00547         std::make_pair("HEAP_ARENA_SIZE_BYTES", i2str(minfo.arena)));
00548       reportData.insert(
00549         std::make_pair("HEAP_ARENA_N_UNUSED_CHUNKS", i2str(minfo.ordblks)));
00550       reportData.insert(
00551         std::make_pair("HEAP_TOP_FREE_BYTES", i2str(minfo.keepcost)));
00552       reportData.insert(
00553         std::make_pair("HEAP_MAPPED_SIZE_BYTES", i2str(minfo.hblkhd)));
00554       reportData.insert(
00555         std::make_pair("HEAP_MAPPED_N_CHUNKS", i2str(minfo.hblks)));
00556       reportData.insert(
00557         std::make_pair("HEAP_USED_BYTES", i2str(minfo.uordblks)));
00558       reportData.insert(
00559         std::make_pair("HEAP_UNUSED_BYTES", i2str(minfo.fordblks)));
00560 #endif
00561 
00562       // Report Growth rates for VSize and Rss
00563       reportData.insert(
00564         std::make_pair("AverageGrowthRateVsize", d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
00565       reportData.insert(
00566         std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
00567       reportData.insert(
00568         std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
00569       reportData.insert(
00570         std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
00571 
00572       if(moduleSummaryRequested_) {                                // changelog 2
00573         for(SignificantModulesMap::iterator im = modules_.begin();
00574             im != modules_.end(); ++im) {
00575           SignificantModule const& m = im->second;
00576           if(m.totalDeltaVsize == 0 && m.totalEarlyVsize == 0) continue;
00577           std::string label = im->first+":";
00578           reportData.insert(std::make_pair(label+"PostEarlyCount", i2str(m.postEarlyCount)));
00579           if(m.postEarlyCount > 0) {
00580             reportData.insert(std::make_pair(label+"AverageDeltaVsize",
00581                                              d2str(m.totalDeltaVsize/m.postEarlyCount)));
00582           }
00583                 reportData.insert(std::make_pair(label+"MaxDeltaVsize", d2str(m.maxDeltaVsize)));
00584           if(m.totalEarlyVsize > 0) {
00585             reportData.insert(std::make_pair(label+"TotalEarlyVsize", d2str(m.totalEarlyVsize)));
00586             reportData.insert(std::make_pair(label+"MaxEarlyDeltaVsize", d2str(m.maxEarlyVsize)));
00587           }
00588         }
00589       }
00590 
00591       std::map<std::string, std::string> reportMemoryProperties;
00592 
00593       if(FILE* fmeminfo = fopen("/proc/meminfo", "r")) {
00594         char buf[128];
00595         char space[] = " ";
00596         size_t value;
00597 
00598         while(fgets(buf, sizeof(buf), fmeminfo)) {
00599           char* token = NULL;
00600           token = strtok(buf, space);
00601           if(token != NULL) {
00602             value = atol(strtok(NULL, space));
00603             std::string category = token;
00604             reportMemoryProperties.insert(std::make_pair(category.substr(0, strlen(token)-1), i2str(value)));
00605           }
00606         }
00607 
00608         fclose(fmeminfo);
00609       }
00610 
00611 //      reportSvc->reportMemoryInfo(reportData, reportMemoryProperties);
00612       reportSvc->reportPerformanceSummary("ApplicationMemory", reportData);
00613       reportSvc->reportPerformanceSummary("SystemMemory", reportMemoryProperties);
00614 #endif
00615 
00616 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
00617       std::vector<std::string> reportData;
00618 
00619       if(eventL2_.vsize > 0) reportData.push_back(
00620               eventStatOutput("LargeVsizeIncreaseEventL2", eventL2_));
00621       if(eventL1_.vsize > 0) reportData.push_back(
00622               eventStatOutput("LargeVsizeIncreaseEventL1", eventL1_));
00623       if(eventM_.vsize > 0) reportData.push_back(
00624               eventStatOutput("LargestVsizeIncreaseEvent", eventM_));
00625       if(eventR1_.vsize > 0) reportData.push_back(
00626               eventStatOutput("LargeVsizeIncreaseEventR1", eventR1_));
00627       if(eventR2_.vsize > 0) reportData.push_back(
00628               eventStatOutput("LargeVsizeIncreaseEventR2", eventR2_));
00629       if(eventT3_.vsize > 0) reportData.push_back(
00630               eventStatOutput("ThirdLargestVsizeEventT3", eventT3_));
00631       if(eventT2_.vsize > 0) reportData.push_back(
00632               eventStatOutput("SecondLargestVsizeEventT2", eventT2_));
00633       if(eventT1_.vsize > 0) reportData.push_back(
00634               eventStatOutput("LargestVsizeEventT1", eventT1_));
00635 
00636       if(eventRssT3_.rss > 0)
00637         eventStatOutput("ThirdLargestRssEvent", eventRssT3_, reportData);
00638       if(eventRssT2_.rss > 0)
00639         eventStatOutput("SecondLargestRssEvent", eventRssT2_, reportData);
00640       if(eventRssT1_.rss > 0)
00641         eventStatOutput("LargestRssEvent", eventRssT1_, reportData);
00642       if(eventDeltaRssT3_.deltaRss > 0)
00643         eventStatOutput("ThirdLargestIncreaseRssEvent", eventDeltaRssT3_, reportData);
00644       if(eventDeltaRssT2_.deltaRss > 0)
00645         eventStatOutput("SecondLargestIncreaseRssEvent", eventDeltaRssT2_, reportData);
00646       if(eventDeltaRssT1_.deltaRss > 0)
00647         eventStatOutput("LargestIncreaseRssEvent", eventDeltaRssT1_, reportData);
00648 
00649       struct mallinfo minfo = mallinfo();
00650       reportData.push_back(
00651         mallOutput("HEAP_ARENA_SIZE_BYTES", minfo.arena));
00652       reportData.push_back(
00653         mallOutput("HEAP_ARENA_N_UNUSED_CHUNKS", minfo.ordblks));
00654       reportData.push_back(
00655         mallOutput("HEAP_TOP_FREE_BYTES", minfo.keepcost));
00656       reportData.push_back(
00657         mallOutput("HEAP_MAPPED_SIZE_BYTES", minfo.hblkhd));
00658       reportData.push_back(
00659         mallOutput("HEAP_MAPPED_N_CHUNKS", minfo.hblks));
00660       reportData.push_back(
00661         mallOutput("HEAP_USED_BYTES", minfo.uordblks));
00662       reportData.push_back(
00663         mallOutput("HEAP_UNUSED_BYTES", minfo.fordblks));
00664 
00665       // Report Growth rates for VSize and Rss
00666       reportData.insert(
00667         std::make_pair("AverageGrowthRateVsize", d2str(averageGrowthRate(current_->vsize, growthRateVsize_, count_))));
00668       reportData.insert(
00669         std::make_pair("PeakValueVsize", d2str(eventT1_.vsize)));
00670       reportData.insert(
00671         std::make_pair("AverageGrowthRateRss", d2str(averageGrowthRate(current_->rss, growthRateRss_, count_))));
00672       reportData.insert(
00673         std::make_pair("PeakValueRss", d2str(eventRssT1_.rss)));
00674 
00675       reportSvc->reportMemoryInfo(reportData);
00676       // This is a form of reportMemoryInfo taking s vector, not a map
00677 #endif
00678     } // postEndJob
00679 
00680     void SimpleMemoryCheck::preEventProcessing(EventID const& iID, Timestamp const&) {
00681       currentEventID_ = iID;                                        // changelog 2
00682     }
00683 
00684     void SimpleMemoryCheck::postEventProcessing(Event const& e, EventSetup const&) {
00685       ++count_;
00686       update();
00687       if (monitorPssAndPrivate_) {
00688         currentSmaps_ = fetchSmaps();
00689       }
00690       updateEventStats(e.id());
00691       if(oncePerEventMode_) {
00692         // should probably use be Run:Event or count_ for the label and name
00693         updateMax();
00694         andPrint("event", "", "");
00695       }
00696     }
00697 
00698     void SimpleMemoryCheck::preModule(ModuleDescription const&) {
00699       update();                                                        // changelog 2
00700       moduleEntryVsize_ = current_->vsize;
00701     }
00702 
00703     void SimpleMemoryCheck::postModule(ModuleDescription const& md) {
00704       if(!oncePerEventMode_) {
00705         updateAndPrint("module", md.moduleLabel(), md.moduleName());
00706       } else if(moduleSummaryRequested_) {                        // changelog 2
00707         update();
00708       }
00709       if(moduleSummaryRequested_) {                                // changelog 2
00710         double dv = current_->vsize - moduleEntryVsize_;
00711         std::string label =  md.moduleLabel();
00712         updateModuleMemoryStats (modules_[label], dv);
00713       }
00714     }
00715 
00716     void SimpleMemoryCheck::postFork(unsigned int, unsigned int) {
00717 #ifdef LINUX
00718       close(fd_);
00719       if(0 != smapsFile_) {
00720         fclose(smapsFile_);
00721       }
00722       openFiles();
00723 #endif      
00724     }
00725 
00726     void SimpleMemoryCheck::update() {
00727       std::swap(current_, previous_);
00728       *current_ = fetch();
00729     }
00730 
00731     void SimpleMemoryCheck::updateMax() {
00732       if((*current_ > max_) || oncePerEventMode_) {
00733           if(count_ >= num_to_skip_) {
00734           }
00735           max_ = *current_;
00736         }
00737     }
00738 
00739     void SimpleMemoryCheck::updateEventStats(EventID const& e) {
00740       if(count_ < num_to_skip_) return;
00741       if(count_ == num_to_skip_) {
00742         eventT1_.set(0, 0, e, this);
00743         eventM_.set (0, 0, e, this);
00744         eventRssT1_.set(0, 0, e, this);
00745         eventDeltaRssT1_.set(0, 0, e, this);
00746         return;
00747       }
00748       double vsize = current_->vsize;
00749       double deltaVsize = vsize - eventT1_.vsize;
00750 
00751       // Update significative events for Vsize
00752       if(vsize > eventT1_.vsize) {
00753         double deltaRss = current_->rss - eventT1_.rss;
00754         eventT3_ = eventT2_;
00755         eventT2_ = eventT1_;
00756         eventT1_.set(deltaVsize, deltaRss, e, this);
00757       } else if(vsize > eventT2_.vsize) {
00758         double deltaRss = current_->rss - eventT1_.rss;
00759         eventT3_ = eventT2_;
00760         eventT2_.set(deltaVsize, deltaRss, e, this);
00761       } else if(vsize > eventT3_.vsize) {
00762         double deltaRss = current_->rss - eventT1_.rss;
00763         eventT3_.set(deltaVsize, deltaRss, e, this);
00764       }
00765 
00766       if(deltaVsize > eventM_.deltaVsize) {
00767         double deltaRss = current_->rss - eventM_.rss;
00768         if(eventL1_.deltaVsize >= eventR1_.deltaVsize) {
00769           eventL2_ = eventL1_;
00770         } else {
00771           eventL2_ = eventR1_;
00772         }
00773         eventL1_ = eventM_;
00774         eventM_.set(deltaVsize, deltaRss, e, this);
00775         eventR1_ = SignificantEvent();
00776         eventR2_ = SignificantEvent();
00777       } else if(deltaVsize > eventR1_.deltaVsize) {
00778         double deltaRss = current_->rss - eventM_.rss;
00779         eventR2_ = eventR1_;
00780         eventR1_.set(deltaVsize, deltaRss, e, this);
00781       } else if(deltaVsize > eventR2_.deltaVsize) {
00782         double deltaRss = current_->rss - eventR1_.rss;
00783         eventR2_.set(deltaVsize, deltaRss, e, this);
00784       }
00785 
00786       // Update significative events for Rss
00787       double rss = current_->rss;
00788       double deltaRss = rss - eventRssT1_.rss;
00789 
00790       if(rss > eventRssT1_.rss) {
00791         eventRssT3_ = eventRssT2_;
00792         eventRssT2_ = eventRssT1_;
00793         eventRssT1_.set(deltaVsize, deltaRss, e, this);
00794       } else if(rss > eventRssT2_.rss) {
00795         eventRssT3_ = eventRssT2_;
00796         eventRssT2_.set(deltaVsize, deltaRss, e, this);
00797       } else if(rss > eventRssT3_.rss) {
00798         eventRssT3_.set(deltaVsize, deltaRss, e, this);
00799       }
00800       if(deltaRss > eventDeltaRssT1_.deltaRss) {
00801         eventDeltaRssT3_ = eventDeltaRssT2_;
00802         eventDeltaRssT2_ = eventDeltaRssT1_;
00803         eventDeltaRssT1_.set(deltaVsize, deltaRss, e, this);
00804       } else if(deltaRss > eventDeltaRssT2_.deltaRss) {
00805         eventDeltaRssT3_ = eventDeltaRssT2_;
00806         eventDeltaRssT2_.set(deltaVsize, deltaRss, e, this);
00807       } else if(deltaRss > eventDeltaRssT3_.deltaRss) {
00808         eventDeltaRssT3_.set(deltaVsize, deltaRss, e, this);
00809       }
00810     } // updateEventStats
00811 
00812     void SimpleMemoryCheck::andPrint(std::string const& type,
00813                     std::string const& mdlabel, std::string const& mdname) const {
00814       if(not jobReportOutputOnly_ && ((*current_ > max_) || oncePerEventMode_)) {
00815         if(count_ >= num_to_skip_) {
00816           double deltaVSIZE = current_->vsize - max_.vsize;
00817           double deltaRSS   = current_->rss - max_.rss;
00818           if(!showMallocInfo_) {  // default
00819             LogWarning("MemoryCheck")
00820             << "MemoryCheck: " << type << " "
00821             << mdname << ":" << mdlabel
00822             << " VSIZE " << current_->vsize << " " << deltaVSIZE
00823             << " RSS " << current_->rss << " " << deltaRSS
00824             << "\n";
00825           } else {
00826 #ifdef __linux__
00827             struct mallinfo minfo = mallinfo();
00828 #endif
00829             LogWarning("MemoryCheck")
00830             << "MemoryCheck: " << type << " "
00831             << mdname << ":" << mdlabel
00832             << " VSIZE " << current_->vsize << " " << deltaVSIZE
00833             << " RSS " << current_->rss << " " << deltaRSS
00834 #ifdef __linux__
00835             << " HEAP-ARENA [ SIZE-BYTES " << minfo.arena
00836             << " N-UNUSED-CHUNKS " << minfo.ordblks
00837             << " TOP-FREE-BYTES " << minfo.keepcost << " ]"
00838             << " HEAP-MAPPED [ SIZE-BYTES " << minfo.hblkhd
00839             << " N-CHUNKS " << minfo.hblks << " ]"
00840             << " HEAP-USED-BYTES " << minfo.uordblks
00841             << " HEAP-UNUSED-BYTES " << minfo.fordblks
00842 #endif
00843             << "\n";
00844           }
00845         }
00846       }
00847     }
00848 
00849     void SimpleMemoryCheck::updateAndPrint(std::string const& type,
00850                     std::string const& mdlabel, std::string const& mdname) {
00851       update();
00852       andPrint(type, mdlabel, mdname);
00853       updateMax();
00854     }
00855 
00856 #ifdef SIMPLE_MEMORY_CHECK_ORIGINAL_XML_OUTPUT
00857     void
00858     SimpleMemoryCheck::eventStatOutput(std::string title,
00859                                        SignificantEvent const& e,
00860                                        std::map<std::string, std::string>& m) const {
00861       { std::ostringstream os;
00862         os << title << "-a-COUNT";
00863         m.insert(std::make_pair(os.str(), i2str(e.count))); }
00864       { std::ostringstream os;
00865         os << title << "-b-RUN";
00866         m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.run())))); }
00867       { std::ostringstream os;
00868         os << title << "-c-EVENT";
00869         m.insert(std::make_pair(os.str(), d2str(static_cast<double>(e.event.event())))); }
00870       { std::ostringstream os;
00871         os << title << "-d-VSIZE";
00872         m.insert(std::make_pair(os.str(), d2str(e.vsize))); }
00873       { std::ostringstream os;
00874         os << title << "-e-DELTV";
00875         m.insert(std::make_pair(os.str(), d2str(e.deltaVsize))); }
00876       { std::ostringstream os;
00877         os << title << "-f-RSS";
00878         m.insert(std::make_pair(os.str(), d2str(e.rss))); }
00879       if (monitorPssAndPrivate_) {
00880         { std::ostringstream os;
00881           os << title << "-g-PRIVATE";
00882           m.insert(std::make_pair(os.str(), d2str(e.privateSize))); }
00883         { std::ostringstream os;
00884           os << title << "-h-PSS";
00885           m.insert(std::make_pair(os.str(), d2str(e.pss))); }
00886       }
00887     } // eventStatOutput
00888 #endif
00889 
00890 #ifdef SIMPLE_MEMORY_CHECK_DIFFERENT_XML_OUTPUT
00891     std::string
00892     SimpleMemoryCheck::eventStatOutput(std::string title,
00893                                            SignificantEvent const& e) const {
00894       std::ostringstream os;
00895       os << "  <" << title << ">\n";
00896       os << "    " << e.count << ": " << e.event;
00897       os << " vsize " << e.vsize-e.deltaVsize << " + " << e.deltaVsize
00898                                               << " = " << e.vsize;
00899       os << "  rss: " << e.rss << "\n";
00900       os << "  </" << title << ">\n";
00901       return os.str();
00902     } // eventStatOutput
00903 
00904     std::string
00905     SimpleMemoryCheck::mallOutput(std::string title, size_t const& n) const {
00906       std::ostringstream os;
00907       os << "  <" << title << ">\n";
00908       os << "    " << n << "\n";
00909       os << "  </" << title << ">\n";
00910       return os.str();
00911     }
00912 #endif
00913                                                                 // changelog 2
00914     void
00915     SimpleMemoryCheck::updateModuleMemoryStats(SignificantModule& m,
00916                                                double dv) {
00917       if(count_ < num_to_skip_) {
00918         m.totalEarlyVsize += dv;
00919         if(dv > m.maxEarlyVsize)  m.maxEarlyVsize = dv;
00920       } else {
00921         ++m.postEarlyCount;
00922         m.totalDeltaVsize += dv;
00923         if(dv > m.maxDeltaVsize) {
00924           m.maxDeltaVsize = dv;
00925           m.eventMaxDeltaV = currentEventID_;
00926         }
00927       }
00928     } //updateModuleMemoryStats
00929 
00930     std::ostream&
00931     operator<< (std::ostream& os,
00932                 SimpleMemoryCheck::SignificantEvent const& se) {
00933       os << "[" << se.count << "] "
00934       << se.event << "  vsize = " << se.vsize
00935       << " deltaVsize = " << se.deltaVsize
00936       << " rss = " << se.rss << " delta = " << se.deltaRss;
00937 
00938       if (se.monitorPssAndPrivate) {
00939         os <<" private = "<<se.privateSize<<" pss = "<<se.pss;
00940       }
00941       return os;
00942     }
00943 
00944     std::ostream&
00945     operator<< (std::ostream& os,
00946                 SimpleMemoryCheck::SignificantModule const& sm) {
00947       if(sm.postEarlyCount > 0) {
00948         os << "\nPost Early Events:  TotalDeltaVsize: " << sm.totalDeltaVsize
00949         << " (avg: " << sm.totalDeltaVsize/sm.postEarlyCount
00950         << "; max: " << sm.maxDeltaVsize
00951         << " during " << sm.eventMaxDeltaV << ")";
00952       }
00953       if(sm.totalEarlyVsize > 0) {
00954         os << "\n     Early Events:  TotalDeltaVsize: " << sm.totalEarlyVsize
00955         << " (max: " << sm.maxEarlyVsize << ")";
00956       }
00957 
00958       return os;
00959     }
00960 
00961   } // end namespace service
00962 } // end namespace edm
00963