CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/FWCore/Services/src/Timing.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Services
00004 // Class  :     Timing
00005 //
00006 // Implementation:
00007 //
00008 // Original Author:  Jim Kowalkowski
00009 //
00010 // Change Log
00011 //
00012 // 1 - mf 4/22/08   Facilitate summary output to job report and logs:
00013 //                    In Timing ctor, default for report_summary_ changed to true
00014 //                  In postEndJob, add output to logger
00015 //
00016 // 2 - 2009/01/14 10:29:00, Natalia Garcia Nebot
00017 //        Modified the service to add some new measurements to report:
00018 //                - Average time per event (cpu and wallclock)
00019 //                - Fastest time per event (cpu and wallclock)
00020 //                - Slowest time per event (cpu and wallclock)
00021 //
00022 // 3 - mf 3/18/09  Change use of LogAbsolute to LogImportant
00023 //                   so that users can throttle the messages
00024 //                 for selected destinations.  LogImportant
00025 //                 is treated at the same level as LogError, so
00026 //                 by default the behavior will not change, but
00027 //                 there will now be a way to control the verbosity.
00028 //
00029 // 4 - mf 3/18/09  The per-event output TimeEvent is changed to LogPrint.
00030 //                   The per-module output TimeModule is changed to LogPrint.
00031 //
00032 // 5 - wmtan 2010/03/16
00033 //                   Fixed the constructor to initialize all data members!
00034 //                   Standardized coding style
00035 //
00036 
00037 #include "FWCore/Services/interface/Timing.h"
00038 
00039 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00040 #include "FWCore/MessageLogger/interface/JobReport.h"
00041 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00042 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00043 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00044 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00045 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
00046 #include "FWCore/ServiceRegistry/interface/Service.h"
00047 #include "FWCore/Utilities/interface/Exception.h"
00048 
00049 #include <iostream>
00050 #include <sstream>
00051 #include <sys/resource.h>
00052 #include <sys/time.h>
00053 
00054 namespace edm {
00055   namespace service {
00056 
00057     static std::string d2str(double d) {
00058         std::stringstream t;
00059         t << d;
00060         return t.str();
00061     }
00062 
00063     static double getTime() {
00064       struct timeval t;
00065       if(gettimeofday(&t, 0) < 0)
00066         throw cms::Exception("SysCallFailed", "Failed call to gettimeofday");
00067       return static_cast<double>(t.tv_sec) + (static_cast<double>(t.tv_usec) * 1E-6);
00068     }
00069 
00070     static double getCPU() {
00071         struct rusage usage;
00072         getrusage(RUSAGE_SELF, &usage);
00073 
00074         double totalCPUTime = 0.0;
00075         // User code
00076         totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
00077         // System functions
00078         totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
00079         return totalCPUTime;
00080     }
00081 
00082     Timing::Timing(ParameterSet const& iPS, ActivityRegistry& iRegistry) :
00083         curr_event_(),
00084         curr_job_time_(0.),
00085         curr_job_cpu_(0.),
00086         curr_event_time_(0.),
00087         curr_event_cpu_(0.),
00088         curr_module_time_(0.),
00089         total_event_cpu_(0.),
00090         summary_only_(iPS.getUntrackedParameter<bool>("summaryOnly")),
00091         report_summary_(iPS.getUntrackedParameter<bool>("useJobReport")),
00092         max_event_time_(0.),
00093         max_event_cpu_(0.),
00094         min_event_time_(0.),
00095         min_event_cpu_(0.),
00096         total_event_count_(0) {
00097       iRegistry.watchPostBeginJob(this, &Timing::postBeginJob);
00098       iRegistry.watchPostEndJob(this, &Timing::postEndJob);
00099 
00100       iRegistry.watchPreProcessEvent(this, &Timing::preEventProcessing);
00101       iRegistry.watchPostProcessEvent(this, &Timing::postEventProcessing);
00102 
00103       if(not summary_only_) {
00104         iRegistry.watchPreModule(this, &Timing::preModule);
00105         iRegistry.watchPostModule(this, &Timing::postModule);
00106       }
00107     }
00108 
00109     Timing::~Timing() {
00110     }
00111 
00112     void Timing::fillDescriptions(ConfigurationDescriptions& descriptions) {
00113       ParameterSetDescription desc;
00114       desc.addUntracked<bool>("summaryOnly", false)->setComment(
00115       "If 'true' do not report timing for each event");
00116       desc.addUntracked<bool>("useJobReport", true)->setComment(
00117        "If 'true' write summary information to JobReport");
00118       descriptions.add("Timing", desc);
00119       descriptions.setComment(
00120        "This service reports the time it takes to run each module in a job.");
00121     }
00122 
00123     void Timing::postBeginJob() {
00124       curr_job_time_ = getTime();
00125       curr_job_cpu_ = getCPU();
00126       total_event_cpu_ = 0.0;
00127 
00128       //LogInfo("TimeReport")
00129       if(not summary_only_) {
00130         LogImportant("TimeReport")                                // ChangeLog 3
00131         << "TimeReport> Report activated" << "\n"
00132         << "TimeReport> Report columns headings for events: "
00133         << "eventnum runnum timetaken\n"
00134         << "TimeReport> Report columns headings for modules: "
00135         << "eventnum runnum modulelabel modulename timetakeni\n"
00136         << "TimeReport> JobTime=" << curr_job_time_  << " JobCPU=" << curr_job_cpu_  << "\n";
00137       }
00138     }
00139 
00140     void Timing::postEndJob() {
00141       double total_job_time = getTime() - curr_job_time_;
00142       double average_event_time = total_job_time / total_event_count_;
00143 
00144       double total_job_cpu = getCPU() - curr_job_cpu_;
00145       double average_event_cpu = total_event_cpu_ / total_event_count_;
00146 
00147       //LogAbsolute("FwkJob")
00148       //LogAbsolute("TimeReport")                                // Changelog 1
00149       LogImportant("TimeReport")                                // Changelog 3
00150         << "TimeReport> Time report complete in "
00151         << total_job_time << " seconds"
00152         << "\n"
00153         << " Time Summary: \n"
00154         << " - Min event:   " << min_event_time_ << "\n"
00155         << " - Max event:   " << max_event_time_ << "\n"
00156         << " - Avg event:   " << average_event_time << "\n"
00157         << " - Total job:   " << total_job_time << "\n"
00158         << " CPU Summary: \n"
00159         << " - Min event:   " << min_event_cpu_ << "\n"
00160         << " - Max event:   " << max_event_cpu_ << "\n"
00161         << " - Avg event:   " << average_event_cpu << "\n"
00162         << " - Total job:   " << total_job_cpu << "\n"
00163         << " - Total event: " << total_event_cpu_ << "\n";
00164 
00165       if(report_summary_) {
00166         Service<JobReport> reportSvc;
00167 //        std::map<std::string, double> reportData;
00168         std::map<std::string, std::string> reportData;
00169 
00170         reportData.insert(std::make_pair("MinEventTime", d2str(min_event_time_)));
00171         reportData.insert(std::make_pair("MaxEventTime", d2str(max_event_time_)));
00172         reportData.insert(std::make_pair("AvgEventTime", d2str(average_event_time)));
00173         reportData.insert(std::make_pair("TotalJobTime", d2str(total_job_time)));
00174         reportData.insert(std::make_pair("MinEventCPU", d2str(min_event_cpu_)));
00175         reportData.insert(std::make_pair("MaxEventCPU", d2str(max_event_cpu_)));
00176         reportData.insert(std::make_pair("AvgEventCPU", d2str(average_event_cpu)));
00177         reportData.insert(std::make_pair("TotalJobCPU", d2str(total_job_cpu)));
00178         reportData.insert(std::make_pair("TotalEventCPU", d2str(total_event_cpu_)));
00179 
00180         reportSvc->reportPerformanceSummary("Timing", reportData);
00181 //        reportSvc->reportTimingInfo(reportData);
00182       }
00183     }
00184 
00185     void Timing::preEventProcessing(EventID const& iID, Timestamp const&) {
00186       curr_event_ = iID;
00187       curr_event_time_ = getTime();
00188       curr_event_cpu_ = getCPU();
00189     }
00190 
00191     void Timing::postEventProcessing(Event const&, EventSetup const&) {
00192       curr_event_cpu_ = getCPU() - curr_event_cpu_;
00193       total_event_cpu_ += curr_event_cpu_;
00194 
00195       curr_event_time_ = getTime() - curr_event_time_;
00196 
00197       if(not summary_only_) {
00198         LogPrint("TimeEvent")                                // ChangeLog 3
00199         << "TimeEvent> "
00200         << curr_event_.event() << " "
00201         << curr_event_.run() << " "
00202         << curr_event_time_ << " "
00203         << curr_event_cpu_ << " "
00204         << total_event_cpu_;
00205       }
00206       if(total_event_count_ == 0) {
00207         max_event_time_ = curr_event_time_;
00208         min_event_time_ = curr_event_time_;
00209         max_event_cpu_ = curr_event_cpu_;
00210         min_event_cpu_ = curr_event_cpu_;
00211       }
00212 
00213       if(curr_event_time_ > max_event_time_) max_event_time_ = curr_event_time_;
00214       if(curr_event_time_ < min_event_time_) min_event_time_ = curr_event_time_;
00215       if(curr_event_cpu_ > max_event_cpu_) max_event_cpu_ = curr_event_cpu_;
00216       if(curr_event_cpu_ < min_event_cpu_) min_event_cpu_ = curr_event_cpu_;
00217       total_event_count_ = total_event_count_ + 1;
00218     }
00219 
00220     void Timing::preModule(ModuleDescription const&) {
00221       curr_module_time_ = getTime();
00222     }
00223 
00224     void Timing::postModule(ModuleDescription const& desc) {
00225       double t = getTime() - curr_module_time_;
00226       //LogInfo("TimeModule")
00227       if(not summary_only_) {
00228         LogPrint("TimeModule") << "TimeModule> "                // ChangeLog 4
00229            << curr_event_.event() << " "
00230            << curr_event_.run() << " "
00231            << desc.moduleLabel() << " "
00232            << desc.moduleName() << " "
00233            << t;
00234       }
00235 
00236     }
00237   }
00238 }
00239