Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:47:54

0001 // -*- C++ -*-
0002 //
0003 // Package:     Services
0004 // Class  :     Timing
0005 //
0006 // Implementation:
0007 //
0008 // Original Author:  Jim Kowalkowski
0009 //
0010 
0011 #include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
0012 
0013 #include "FWCore/Utilities/interface/TimingServiceBase.h"
0014 #include "DataFormats/Provenance/interface/ModuleDescription.h"
0015 #include "FWCore/MessageLogger/interface/JobReport.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0018 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0019 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0020 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
0021 #include "FWCore/ServiceRegistry/interface/GlobalContext.h"
0022 #include "FWCore/ServiceRegistry/interface/Service.h"
0023 #include "FWCore/ServiceRegistry/interface/StreamContext.h"
0024 #include "FWCore/ServiceRegistry/interface/ModuleCallingContext.h"
0025 #include "FWCore/ServiceRegistry/interface/ESModuleCallingContext.h"
0026 #include "FWCore/ServiceRegistry/interface/ProcessContext.h"
0027 #include "FWCore/ServiceRegistry/interface/SystemBounds.h"
0028 #include "FWCore/Utilities/interface/Exception.h"
0029 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0030 #include "FWCore/Framework/interface/EventSetupRecordKey.h"
0031 
0032 #include <iostream>
0033 #include <sstream>
0034 #include <sys/resource.h>
0035 #include <sys/time.h>
0036 #include <atomic>
0037 #include <exception>
0038 
0039 namespace edm {
0040 
0041   namespace eventsetup {
0042     struct ComponentDescription;
0043     class DataKey;
0044     class EventSetupRecordKey;
0045   }  // namespace eventsetup
0046 
0047   namespace service {
0048     class Timing : public TimingServiceBase {
0049     public:
0050       using time_point = std::chrono::steady_clock::time_point;
0051       using double_seconds = std::chrono::duration<double, std::ratio<1, 1>>;
0052 
0053       Timing(ParameterSet const&, ActivityRegistry&);
0054       ~Timing() override;
0055 
0056       static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0057 
0058       void addToCPUTime(double iTime) override;
0059       double getTotalCPU() const override;
0060 
0061     private:
0062       void preBeginJob(PathsAndConsumesOfModulesBase const&, ProcessContext const&);
0063       void beginProcessing();
0064       void postEndJob();
0065 
0066       void preEvent(StreamContext const&);
0067       void postEvent(StreamContext const&);
0068       void lastPostEvent(std::chrono::steady_clock::duration curr_event_time,
0069                          unsigned int index,
0070                          StreamContext const& iStream);
0071 
0072       void postModuleEvent(StreamContext const&, ModuleCallingContext const&);
0073 
0074       void preSourceEvent(StreamID);
0075       void postSourceEvent(StreamID);
0076 
0077       void preSourceLumi(LuminosityBlockIndex);
0078       void postSourceLumi(LuminosityBlockIndex);
0079 
0080       void preSourceRun(RunIndex);
0081       void postSourceRun(RunIndex);
0082 
0083       void preOpenFile(std::string const&);
0084       void postOpenFile(std::string const&);
0085 
0086       void preModule(ModuleDescription const& md);
0087       void postModule(ModuleDescription const& md);
0088 
0089       void preModuleGlobal(GlobalContext const&, ModuleCallingContext const&);
0090       void postModuleGlobal(GlobalContext const&, ModuleCallingContext const&);
0091 
0092       void postGlobalBeginRun(GlobalContext const&);
0093       void postGlobalBeginLumi(GlobalContext const&);
0094 
0095       void preModuleStream(StreamContext const&, ModuleCallingContext const&);
0096       void postModuleStream(StreamContext const&, ModuleCallingContext const&);
0097 
0098       double postCommon() const;
0099 
0100       void setTaskCallbacks(ActivityRegistry&);
0101       inline void addTask() { runningTasksChanged(true); }
0102       inline void removeTask() { runningTasksChanged(false); }
0103       void runningTasksChanged(bool iMoreTasks);
0104 
0105       time_point curr_job_time_;
0106       double curr_job_cpu_;                // seconds
0107       std::atomic<double> extra_job_cpu_;  //seconds
0108                                            //use last run time for determining end of processing
0109       std::atomic<time_point> end_loop_time_;
0110       std::atomic<double> end_loop_cpu_;
0111       std::vector<time_point> curr_events_time_;
0112       bool summary_only_;
0113       bool report_summary_;
0114       double threshold_;
0115 
0116       std::atomic<bool> updating_task_info_ = false;
0117       CMS_THREAD_GUARD(updating_task_info_) unsigned int num_running_tasks_ = 0;
0118       CMS_THREAD_GUARD(updating_task_info_) time_point last_task_change_time_ = time_point();
0119       CMS_THREAD_GUARD(updating_task_info_) double total_time_without_tasks_ = 0;
0120       //
0121       // Min Max and total event times for each Stream.
0122       //  Used for summary at end of job
0123       std::vector<double> max_events_time_;  // seconds
0124       std::vector<double> min_events_time_;  // seconds
0125       std::vector<double> sum_events_time_;
0126       std::atomic<unsigned long> total_event_count_;
0127       std::atomic<unsigned long> begin_lumi_count_;
0128       std::atomic<unsigned long> begin_run_count_;
0129       unsigned int nStreams_;
0130       unsigned int nThreads_;
0131 
0132       std::vector<std::unique_ptr<std::atomic<time_point>>> eventSetupModuleStartTimes_;
0133       std::vector<std::pair<uintptr_t, eventsetup::EventSetupRecordKey>> eventSetupModuleCallInfo_;
0134       std::atomic<double> accumulatedEventSetupModuleTimings_ = 0.;  //seconds
0135 
0136       std::vector<std::unique_ptr<std::atomic<unsigned int>>> countSubProcessesPreEvent_;
0137       std::vector<std::unique_ptr<std::atomic<unsigned int>>> countSubProcessesPostEvent_;
0138 
0139       bool configuredInTopLevelProcess_;
0140       unsigned int nSubProcesses_;
0141     };
0142   }  // namespace service
0143 }  // namespace edm
0144 
0145 namespace edm {
0146   namespace service {
0147 
0148     static std::string d2str(double d) {
0149       std::stringstream t;
0150       t << d;
0151       return t.str();
0152     }
0153 
0154     static std::string ui2str(unsigned int i) {
0155       std::stringstream t;
0156       t << i;
0157       return t.str();
0158     }
0159 
0160     static std::chrono::steady_clock::time_point getTime() { return std::chrono::steady_clock::now(); }
0161 
0162     static double getChildrenCPU() {
0163       struct rusage usage;
0164 
0165       getrusage(RUSAGE_CHILDREN, &usage);
0166       double totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
0167       totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
0168 
0169       return totalCPUTime;
0170     }
0171 
0172     static double getCPU() {
0173       struct rusage usage;
0174       getrusage(RUSAGE_SELF, &usage);
0175 
0176       double totalCPUTime = 0.0;
0177       // User code
0178       totalCPUTime = (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
0179       // System functions
0180       totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
0181 
0182       // Additionally, add in CPU usage from our child processes.
0183       getrusage(RUSAGE_CHILDREN, &usage);
0184       totalCPUTime += (double)usage.ru_utime.tv_sec + (double(usage.ru_utime.tv_usec) * 1E-6);
0185       totalCPUTime += (double)usage.ru_stime.tv_sec + (double(usage.ru_stime.tv_usec) * 1E-6);
0186 
0187       return totalCPUTime;
0188     }
0189 
0190     //NOTE: We use a per thread stack for module times since unscheduled
0191     // exectuion or tbb task spawning can cause a module to run on the
0192     // same thread as an already running module
0193     static std::vector<std::chrono::steady_clock::time_point>& moduleTimeStack() {
0194       static thread_local std::vector<std::chrono::steady_clock::time_point> s_stack;
0195       return s_stack;
0196     }
0197 
0198     static double popStack() {
0199       auto& modStack = moduleTimeStack();
0200       assert(!modStack.empty());
0201       auto curr_module_time = modStack.back();
0202       modStack.pop_back();
0203       std::chrono::duration<double, std::ratio<1, 1>> t = getTime() - curr_module_time;
0204       return t.count();
0205     }
0206 
0207     static void pushStack(bool configuredInTopLevelProcess) {
0208       if (!configuredInTopLevelProcess) {
0209         return;
0210       }
0211       auto& modStack = moduleTimeStack();
0212       modStack.push_back(getTime());
0213     }
0214 
0215     Timing::Timing(ParameterSet const& iPS, ActivityRegistry& iRegistry)
0216         : curr_job_time_(),
0217           curr_job_cpu_(0.),
0218           extra_job_cpu_(0.0),
0219           end_loop_time_(),
0220           end_loop_cpu_(0.0),
0221           curr_events_time_(),
0222           summary_only_(iPS.getUntrackedParameter<bool>("summaryOnly")),
0223           report_summary_(iPS.getUntrackedParameter<bool>("useJobReport")),
0224           threshold_(iPS.getUntrackedParameter<double>("excessiveTimeThreshold")),
0225           max_events_time_(),
0226           min_events_time_(),
0227           total_event_count_(0),
0228           begin_lumi_count_(0),
0229           begin_run_count_(0),
0230           configuredInTopLevelProcess_{false},
0231           nSubProcesses_{0} {
0232       iRegistry.watchPreBeginJob(this, &Timing::preBeginJob);
0233       iRegistry.watchBeginProcessing(this, &Timing::beginProcessing);
0234       iRegistry.watchPreEndJob([this]() {
0235         end_loop_time_ = getTime();
0236         end_loop_cpu_ = getCPU();
0237       });
0238       iRegistry.watchPostEndJob(this, &Timing::postEndJob);
0239 
0240       iRegistry.watchPreEvent(this, &Timing::preEvent);
0241       iRegistry.watchPostEvent(this, &Timing::postEvent);
0242 
0243       bool checkThreshold = true;
0244       if (threshold_ <= 0.0) {
0245         //we need to ignore the threshold check
0246         threshold_ = std::numeric_limits<double>::max();
0247         checkThreshold = false;
0248       }
0249 
0250       if ((not summary_only_) || (checkThreshold)) {
0251         iRegistry.watchPreModuleEvent(this, &Timing::preModuleStream);
0252         iRegistry.watchPostModuleEvent(this, &Timing::postModuleEvent);
0253         iRegistry.watchPreModuleEventAcquire(this, &Timing::preModuleStream);
0254         iRegistry.watchPostModuleEventAcquire(this, &Timing::postModuleEvent);
0255       }
0256       if (checkThreshold) {
0257         iRegistry.watchPreSourceEvent(this, &Timing::preSourceEvent);
0258         iRegistry.watchPostSourceEvent(this, &Timing::postSourceEvent);
0259 
0260         iRegistry.watchPreSourceLumi(this, &Timing::preSourceLumi);
0261         iRegistry.watchPostSourceLumi(this, &Timing::postSourceLumi);
0262 
0263         iRegistry.watchPreSourceRun(this, &Timing::preSourceRun);
0264         iRegistry.watchPostSourceRun(this, &Timing::postSourceRun);
0265 
0266         iRegistry.watchPreOpenFile(this, &Timing::preOpenFile);
0267         iRegistry.watchPostOpenFile(this, &Timing::postOpenFile);
0268 
0269         iRegistry.watchPreEventReadFromSource(this, &Timing::preModuleStream);
0270         iRegistry.watchPostEventReadFromSource(this, &Timing::postModuleStream);
0271 
0272         iRegistry.watchPreModuleConstruction(this, &Timing::preModule);
0273         iRegistry.watchPostModuleConstruction(this, &Timing::postModule);
0274 
0275         iRegistry.watchPreModuleDestruction(this, &Timing::preModule);
0276         iRegistry.watchPostModuleDestruction(this, &Timing::postModule);
0277 
0278         iRegistry.watchPreModuleBeginJob(this, &Timing::preModule);
0279         iRegistry.watchPostModuleBeginJob(this, &Timing::postModule);
0280 
0281         iRegistry.watchPreModuleEndJob(this, &Timing::preModule);
0282         iRegistry.watchPostModuleEndJob(this, &Timing::postModule);
0283 
0284         iRegistry.watchPreModuleStreamBeginRun(this, &Timing::preModuleStream);
0285         iRegistry.watchPostModuleStreamBeginRun(this, &Timing::postModuleStream);
0286         iRegistry.watchPreModuleStreamEndRun(this, &Timing::preModuleStream);
0287         iRegistry.watchPostModuleStreamEndRun(this, &Timing::postModuleStream);
0288 
0289         iRegistry.watchPreModuleStreamBeginLumi(this, &Timing::preModuleStream);
0290         iRegistry.watchPostModuleStreamBeginLumi(this, &Timing::postModuleStream);
0291         iRegistry.watchPreModuleStreamEndLumi(this, &Timing::preModuleStream);
0292         iRegistry.watchPostModuleStreamEndLumi(this, &Timing::postModuleStream);
0293 
0294         iRegistry.watchPreModuleGlobalBeginRun(this, &Timing::preModuleGlobal);
0295         iRegistry.watchPostModuleGlobalBeginRun(this, &Timing::postModuleGlobal);
0296         iRegistry.watchPreModuleGlobalEndRun(this, &Timing::preModuleGlobal);
0297         iRegistry.watchPostModuleGlobalEndRun(this, &Timing::postModuleGlobal);
0298 
0299         iRegistry.watchPreModuleGlobalBeginLumi(this, &Timing::preModuleGlobal);
0300         iRegistry.watchPostModuleGlobalBeginLumi(this, &Timing::postModuleGlobal);
0301         iRegistry.watchPreModuleGlobalEndLumi(this, &Timing::preModuleGlobal);
0302         iRegistry.watchPostModuleGlobalEndLumi(this, &Timing::postModuleGlobal);
0303 
0304         iRegistry.watchPreSourceConstruction(this, &Timing::preModule);
0305         iRegistry.watchPostSourceConstruction(this, &Timing::postModule);
0306       }
0307 
0308       auto preESModuleLambda = [this](auto const& recordKey, auto const& context) {
0309         addTask();
0310         //find available slot
0311         auto startTime = getTime();
0312         bool foundSlot = false;
0313         do {
0314           for (size_t i = 0; i < eventSetupModuleStartTimes_.size(); ++i) {
0315             auto& slot = *eventSetupModuleStartTimes_[i];
0316             std::chrono::steady_clock::time_point expect;
0317             if (slot.compare_exchange_strong(expect, startTime)) {
0318               foundSlot = true;
0319               eventSetupModuleCallInfo_[i].first = uintptr_t(context.componentDescription());
0320               eventSetupModuleCallInfo_[i].second = recordKey;
0321               break;
0322             }
0323           }
0324           //if foundSlot == false then other threads stole the slots before this thread
0325           // so should check starting over again
0326         } while (not foundSlot);
0327       };
0328       iRegistry.watchPreESModule(preESModuleLambda);
0329       iRegistry.watchPreESModuleAcquire(preESModuleLambda);
0330 
0331       auto postESModuleLambda = [this](auto const& recordKey, auto const& context) {
0332         removeTask();
0333         auto stopTime = getTime();
0334         for (size_t i = 0; i < eventSetupModuleStartTimes_.size(); ++i) {
0335           auto const& info = eventSetupModuleCallInfo_[i];
0336           if (info.first == uintptr_t(context.componentDescription()) and info.second == recordKey) {
0337             auto startTime = eventSetupModuleStartTimes_[i]->exchange(std::chrono::steady_clock::time_point());
0338             auto expect = accumulatedEventSetupModuleTimings_.load();
0339             double_seconds timeDiff = stopTime - startTime;
0340             auto accumulatedTime = expect + timeDiff.count();
0341             while (not accumulatedEventSetupModuleTimings_.compare_exchange_strong(expect, accumulatedTime)) {
0342               accumulatedTime = expect + timeDiff.count();
0343             }
0344             break;
0345           }
0346         }
0347       };
0348       iRegistry.watchPostESModule(postESModuleLambda);
0349       iRegistry.watchPostESModuleAcquire(postESModuleLambda);
0350 
0351       iRegistry.watchPostGlobalBeginRun(this, &Timing::postGlobalBeginRun);
0352       iRegistry.watchPostGlobalBeginLumi(this, &Timing::postGlobalBeginLumi);
0353 
0354       iRegistry.watchPreallocate([this](service::SystemBounds const& iBounds) {
0355         nStreams_ = iBounds.maxNumberOfStreams();
0356         nThreads_ = iBounds.maxNumberOfThreads();
0357         curr_events_time_.resize(nStreams_, time_point());
0358         sum_events_time_.resize(nStreams_, 0.);
0359         max_events_time_.resize(nStreams_, 0.);
0360         min_events_time_.resize(nStreams_, 1.E6);
0361         eventSetupModuleStartTimes_.reserve(nThreads_);
0362         for (unsigned int i = 0; i < nThreads_; ++i) {
0363           eventSetupModuleStartTimes_.emplace_back(std::make_unique<std::atomic<time_point>>());
0364         }
0365         eventSetupModuleCallInfo_.resize(nThreads_);
0366 
0367         for (unsigned int i = 0; i < nStreams_; ++i) {
0368           countSubProcessesPreEvent_.emplace_back(std::make_unique<std::atomic<unsigned int>>(0));
0369           countSubProcessesPostEvent_.emplace_back(std::make_unique<std::atomic<unsigned int>>(0));
0370         }
0371       });
0372       setTaskCallbacks(iRegistry);
0373     }
0374 
0375     void Timing::setTaskCallbacks(ActivityRegistry& iRegistry) {
0376       iRegistry.watchPreSourceEvent([this](auto) { addTask(); });
0377       iRegistry.watchPostSourceEvent([this](auto) { removeTask(); });
0378 
0379       iRegistry.watchPreModuleEvent([this](auto, auto) { addTask(); });
0380       iRegistry.watchPostModuleEvent([this](auto, auto) { removeTask(); });
0381       iRegistry.watchPreModuleEventAcquire([this](auto, auto) { addTask(); });
0382       iRegistry.watchPostModuleEventAcquire([this](auto, auto) { removeTask(); });
0383 
0384       iRegistry.watchPreSourceLumi([this](auto) { addTask(); });
0385       iRegistry.watchPostSourceLumi([this](auto) { removeTask(); });
0386 
0387       iRegistry.watchPreSourceRun([this](auto) { addTask(); });
0388       iRegistry.watchPostSourceRun([this](auto) { removeTask(); });
0389 
0390       iRegistry.watchPreEventReadFromSource([this](auto, auto) { addTask(); });
0391       iRegistry.watchPostEventReadFromSource([this](auto, auto) { removeTask(); });
0392 
0393       iRegistry.watchPreModuleStreamBeginRun([this](auto, auto) { addTask(); });
0394       iRegistry.watchPostModuleStreamBeginRun([this](auto, auto) { removeTask(); });
0395       iRegistry.watchPreModuleStreamEndRun([this](auto, auto) { addTask(); });
0396       iRegistry.watchPostModuleStreamEndRun([this](auto, auto) { removeTask(); });
0397 
0398       iRegistry.watchPreModuleStreamBeginLumi([this](auto, auto) { addTask(); });
0399       iRegistry.watchPostModuleStreamBeginLumi([this](auto, auto) { removeTask(); });
0400       iRegistry.watchPreModuleStreamEndLumi([this](auto, auto) { addTask(); });
0401       iRegistry.watchPostModuleStreamEndLumi([this](auto, auto) { removeTask(); });
0402 
0403       iRegistry.watchPreModuleGlobalBeginRun([this](auto, auto) { addTask(); });
0404       iRegistry.watchPostModuleGlobalBeginRun([this](auto, auto) { removeTask(); });
0405       iRegistry.watchPreModuleGlobalEndRun([this](auto, auto) { addTask(); });
0406       iRegistry.watchPostModuleGlobalEndRun([this](auto, auto) { removeTask(); });
0407 
0408       iRegistry.watchPreModuleGlobalBeginLumi([this](auto, auto) { addTask(); });
0409       iRegistry.watchPostModuleGlobalBeginLumi([this](auto, auto) { removeTask(); });
0410       iRegistry.watchPreModuleGlobalEndLumi([this](auto, auto) { addTask(); });
0411       iRegistry.watchPostModuleGlobalEndLumi([this](auto, auto) { removeTask(); });
0412 
0413       //account for any time ESSources spend looking up new IOVs
0414       iRegistry.watchPreESSyncIOV([this](auto const&) { addTask(); });
0415       iRegistry.watchPostESSyncIOV([this](auto const&) { removeTask(); });
0416     }
0417 
0418     Timing::~Timing() {}
0419 
0420     void Timing::addToCPUTime(double iTime) {
0421       //For accounting purposes we effectively can say we started earlier
0422       double expected = extra_job_cpu_.load();
0423       while (not extra_job_cpu_.compare_exchange_strong(expected, expected + iTime)) {
0424       }
0425     }
0426 
0427     double Timing::getTotalCPU() const { return getCPU(); }
0428 
0429     void Timing::fillDescriptions(ConfigurationDescriptions& descriptions) {
0430       ParameterSetDescription desc;
0431       desc.addUntracked<bool>("summaryOnly", false)->setComment("If 'true' do not report timing for each event");
0432       desc.addUntracked<bool>("useJobReport", true)->setComment("If 'true' write summary information to JobReport");
0433       desc.addUntracked<double>("excessiveTimeThreshold", 0.)
0434           ->setComment(
0435               "Amount of time in seconds before reporting a module or source has taken excessive time. A value of 0.0 "
0436               "turns off this reporting.");
0437       descriptions.add("Timing", desc);
0438       descriptions.setComment("This service reports the time it takes to run each module in a job.");
0439     }
0440 
0441     void Timing::preBeginJob(PathsAndConsumesOfModulesBase const& pathsAndConsumes, ProcessContext const& pc) {
0442       if (pc.isSubProcess()) {
0443         ++nSubProcesses_;
0444       } else {
0445         configuredInTopLevelProcess_ = true;
0446       }
0447     }
0448 
0449     void Timing::beginProcessing() {
0450       if (!configuredInTopLevelProcess_) {
0451         return;
0452       }
0453       curr_job_time_ = getTime();
0454       curr_job_cpu_ = getCPU();
0455       last_task_change_time_ = curr_job_time_;
0456 
0457       if (not summary_only_) {
0458         LogImportant("TimeReport")
0459             << "TimeReport> Report activated"
0460             << "\n"
0461             << "TimeReport> Report columns headings for events: "
0462             << "eventnum runnum timetaken\n"
0463             << "TimeReport> Report columns headings for modules: "
0464             << "eventnum runnum modulelabel modulename timetaken\n"
0465             << "TimeReport> JobTime="
0466             << std::chrono::time_point_cast<std::chrono::seconds>(curr_job_time_).time_since_epoch().count()
0467             << " JobCPU=" << curr_job_cpu_ << "\n";
0468       }
0469     }
0470 
0471     void Timing::postEndJob() {
0472       if (!configuredInTopLevelProcess_) {
0473         LogImportant("TimeReport") << "\nTimeReport> This instance of the Timing Service will be disabled because it "
0474                                       "is configured in a SubProcess.\n"
0475                                    << "If multiple instances of the TimingService were configured only the one in the "
0476                                       "top level process will function.\n"
0477                                    << "The other instance(s) will simply print this message and do nothing.\n\n";
0478         return;
0479       }
0480 
0481       const auto job_end_time = getTime();
0482       const double job_end_cpu = getCPU();
0483       auto total_job_time = double_seconds(job_end_time - jobStartTime()).count();
0484 
0485       double total_job_cpu = job_end_cpu + extra_job_cpu_;
0486 
0487       const double job_end_children_cpu = getChildrenCPU();
0488 
0489       const double total_initialization_time = double_seconds(curr_job_time_ - jobStartTime()).count();
0490       const double total_initialization_cpu = curr_job_cpu_;
0491 
0492       if (time_point() == jobStartTime()) {
0493         //did not capture beginning time
0494         total_job_time = double_seconds(job_end_time - curr_job_time_).count();
0495         total_job_cpu = job_end_cpu + extra_job_cpu_ - curr_job_cpu_;
0496       }
0497 
0498       double min_event_time = *(std::min_element(min_events_time_.begin(), min_events_time_.end()));
0499       double max_event_time = *(std::max_element(max_events_time_.begin(), max_events_time_.end()));
0500 
0501       auto total_loop_time = double_seconds(end_loop_time_.load() - curr_job_time_).count();
0502       auto total_loop_cpu = end_loop_cpu_ + extra_job_cpu_ - curr_job_cpu_;
0503 
0504       if (end_loop_time_.load() == time_point()) {
0505         total_loop_time = 0.0;
0506         total_loop_cpu = 0.0;
0507       }
0508 
0509       double sum_all_events_time = 0;
0510       for (auto t : sum_events_time_) {
0511         sum_all_events_time += t;
0512       }
0513 
0514       double average_event_time = 0.0;
0515       if (total_event_count_ != 0) {
0516         average_event_time = sum_all_events_time / total_event_count_;
0517       }
0518 
0519       double event_throughput = 0.0;
0520       if (total_loop_time != 0.0) {
0521         event_throughput = total_event_count_ / total_loop_time;
0522       }
0523 
0524       LogImportant("TimeReport") << "TimeReport> Time report complete in " << total_job_time << " seconds"
0525                                  << "\n"
0526                                  << " Time Summary: \n"
0527                                  << " - Min event:   " << min_event_time << "\n"
0528                                  << " - Max event:   " << max_event_time << "\n"
0529                                  << " - Avg event:   " << average_event_time << "\n"
0530                                  << " - Total loop:  " << total_loop_time << "\n"
0531                                  << " - Total init:  " << total_initialization_time << "\n"
0532                                  << " - Total job:   " << total_job_time << "\n"
0533                                  << " - Total EventSetup: " << accumulatedEventSetupModuleTimings_.load() << "\n"
0534                                  << " - Total non-module: " << total_time_without_tasks_ << "\n"
0535                                  << " Event Throughput: " << event_throughput << " ev/s\n"
0536                                  << " CPU Summary: \n"
0537                                  << " - Total loop:     " << total_loop_cpu << "\n"
0538                                  << " - Total init:     " << total_initialization_cpu << "\n"
0539                                  << " - Total extra:    " << extra_job_cpu_ << "\n"
0540                                  << " - Total children: " << job_end_children_cpu << "\n"
0541                                  << " - Total job:      " << total_job_cpu << "\n"
0542                                  << " Processing Summary: \n"
0543                                  << " - Number of Events:  " << total_event_count_ << "\n"
0544                                  << " - Number of Global Begin Lumi Calls:  " << begin_lumi_count_ << "\n"
0545                                  << " - Number of Global Begin Run Calls: " << begin_run_count_ << "\n";
0546 
0547       if (report_summary_) {
0548         Service<JobReport> reportSvc;
0549         std::map<std::string, std::string> reportData;
0550 
0551         reportData.insert(std::make_pair("MinEventTime", d2str(min_event_time)));
0552         reportData.insert(std::make_pair("MaxEventTime", d2str(max_event_time)));
0553         reportData.insert(std::make_pair("AvgEventTime", d2str(average_event_time)));
0554         reportData.insert(std::make_pair("EventThroughput", d2str(event_throughput)));
0555         reportData.insert(std::make_pair("TotalJobTime", d2str(total_job_time)));
0556         reportData.insert(std::make_pair("TotalJobCPU", d2str(total_job_cpu)));
0557         reportData.insert(std::make_pair("TotalJobChildrenCPU", d2str(job_end_children_cpu)));
0558         reportData.insert(std::make_pair("TotalLoopTime", d2str(total_loop_time)));
0559         reportData.insert(std::make_pair("TotalEventSetupTime", d2str(accumulatedEventSetupModuleTimings_.load())));
0560         reportData.insert(std::make_pair("TotalNonModuleTime", d2str(total_time_without_tasks_)));
0561         reportData.insert(std::make_pair("TotalLoopCPU", d2str(total_loop_cpu)));
0562         reportData.insert(std::make_pair("TotalInitTime", d2str(total_initialization_time)));
0563         reportData.insert(std::make_pair("TotalInitCPU", d2str(total_initialization_cpu)));
0564         reportData.insert(std::make_pair("NumberOfStreams", ui2str(nStreams_)));
0565         reportData.insert(std::make_pair("NumberOfThreads", ui2str(nThreads_)));
0566         reportSvc->reportPerformanceSummary("Timing", reportData);
0567 
0568         std::map<std::string, std::string> reportData1;
0569         reportData1.insert(std::make_pair("NumberEvents", ui2str(total_event_count_)));
0570         reportData1.insert(std::make_pair("NumberBeginLumiCalls", ui2str(begin_lumi_count_)));
0571         reportData1.insert(std::make_pair("NumberBeginRunCalls", ui2str(begin_run_count_)));
0572         reportSvc->reportPerformanceSummary("ProcessingSummary", reportData1);
0573       }
0574     }
0575 
0576     void Timing::preEvent(StreamContext const& iStream) {
0577       if (!configuredInTopLevelProcess_) {
0578         return;
0579       }
0580       auto index = iStream.streamID().value();
0581       if (nSubProcesses_ == 0u) {
0582         curr_events_time_[index] = getTime();
0583       } else {
0584         unsigned int count = ++(*countSubProcessesPreEvent_[index]);
0585         if (count == 1) {
0586           curr_events_time_[index] = getTime();
0587         } else if (count == (nSubProcesses_ + 1)) {
0588           *countSubProcessesPreEvent_[index] = 0;
0589         }
0590       }
0591     }
0592 
0593     void Timing::postEvent(StreamContext const& iStream) {
0594       if (!configuredInTopLevelProcess_) {
0595         return;
0596       }
0597       auto index = iStream.streamID().value();
0598       if (nSubProcesses_ == 0u) {
0599         lastPostEvent(getTime() - curr_events_time_[index], index, iStream);
0600       } else {
0601         unsigned int count = ++(*countSubProcessesPostEvent_[index]);
0602         if (count == (nSubProcesses_ + 1)) {
0603           lastPostEvent(getTime() - curr_events_time_[index], index, iStream);
0604           *countSubProcessesPostEvent_[index] = 0;
0605         }
0606       }
0607     }
0608 
0609     void Timing::lastPostEvent(std::chrono::steady_clock::duration curr_event_time,
0610                                unsigned int index,
0611                                StreamContext const& iStream) {
0612       double curr_event_time_d = double_seconds(curr_event_time).count();
0613       sum_events_time_[index] += curr_event_time_d;
0614 
0615       if (not summary_only_) {
0616         auto const& eventID = iStream.eventID();
0617         LogPrint("TimeEvent") << "TimeEvent> " << eventID.event() << " " << eventID.run() << " " << curr_event_time_d;
0618       }
0619       if (curr_event_time_d > max_events_time_[index])
0620         max_events_time_[index] = curr_event_time_d;
0621       if (curr_event_time_d < min_events_time_[index])
0622         min_events_time_[index] = curr_event_time_d;
0623       ++total_event_count_;
0624     }
0625 
0626     void Timing::postModuleEvent(StreamContext const& iStream, ModuleCallingContext const& iModule) {
0627       if (!configuredInTopLevelProcess_) {
0628         return;
0629       }
0630       auto const& eventID = iStream.eventID();
0631       auto const& desc = *(iModule.moduleDescription());
0632       double t = postCommon();
0633       if (not summary_only_) {
0634         LogPrint("TimeModule") << "TimeModule> " << eventID.event() << " " << eventID.run() << " " << desc.moduleLabel()
0635                                << " " << desc.moduleName() << " " << t;
0636       }
0637     }
0638 
0639     void Timing::preSourceEvent(StreamID sid) { pushStack(configuredInTopLevelProcess_); }
0640 
0641     void Timing::postSourceEvent(StreamID sid) { postCommon(); }
0642 
0643     void Timing::preSourceLumi(LuminosityBlockIndex index) { pushStack(configuredInTopLevelProcess_); }
0644 
0645     void Timing::postSourceLumi(LuminosityBlockIndex index) { postCommon(); }
0646 
0647     void Timing::preSourceRun(RunIndex index) { pushStack(configuredInTopLevelProcess_); }
0648 
0649     void Timing::postSourceRun(RunIndex index) { postCommon(); }
0650 
0651     void Timing::preOpenFile(std::string const& lfn) { pushStack(configuredInTopLevelProcess_); }
0652 
0653     void Timing::postOpenFile(std::string const& lfn) { postCommon(); }
0654 
0655     void Timing::preModule(ModuleDescription const&) { pushStack(configuredInTopLevelProcess_); }
0656 
0657     void Timing::postModule(ModuleDescription const& desc) { postCommon(); }
0658 
0659     void Timing::preModuleGlobal(GlobalContext const&, ModuleCallingContext const&) {
0660       pushStack(configuredInTopLevelProcess_);
0661     }
0662 
0663     void Timing::postModuleGlobal(GlobalContext const&, ModuleCallingContext const& mcc) { postCommon(); }
0664 
0665     void Timing::postGlobalBeginRun(GlobalContext const& gc) {
0666       if (!configuredInTopLevelProcess_) {
0667         return;
0668       }
0669       if (!gc.processContext()->isSubProcess()) {
0670         ++begin_run_count_;
0671       }
0672     }
0673 
0674     void Timing::postGlobalBeginLumi(GlobalContext const& gc) {
0675       if (!configuredInTopLevelProcess_) {
0676         return;
0677       }
0678       if (!gc.processContext()->isSubProcess()) {
0679         ++begin_lumi_count_;
0680       }
0681     }
0682 
0683     void Timing::preModuleStream(StreamContext const&, ModuleCallingContext const&) {
0684       pushStack(configuredInTopLevelProcess_);
0685     }
0686 
0687     void Timing::postModuleStream(StreamContext const&, ModuleCallingContext const& mcc) { postCommon(); }
0688 
0689     double Timing::postCommon() const {
0690       if (!configuredInTopLevelProcess_) {
0691         return 0.0;
0692       }
0693       double t = popStack();
0694       if (t > threshold_) {
0695         LogError("ExcessiveTime")
0696             << "ExcessiveTime: Module used " << t
0697             << " seconds of time which exceeds the error threshold configured in the Timing Service of " << threshold_
0698             << " seconds.";
0699       }
0700       return t;
0701     }
0702 
0703     void Timing::runningTasksChanged(bool iMoreTasks) {
0704       const auto presentTime = getTime();
0705       bool expected = false;
0706       while (not updating_task_info_.compare_exchange_strong(expected, true)) {
0707         expected = false;
0708       }
0709       auto previousNumberOfTasks = iMoreTasks ? num_running_tasks_++ : num_running_tasks_--;
0710       total_time_without_tasks_ +=
0711           (nThreads_ - previousNumberOfTasks) * double_seconds(presentTime - last_task_change_time_).count();
0712       last_task_change_time_ = presentTime;
0713       updating_task_info_ = false;
0714     }
0715   }  // namespace service
0716 }  // namespace edm
0717 
0718 using edm::service::Timing;
0719 
0720 typedef edm::serviceregistry::AllArgsMaker<edm::TimingServiceBase, Timing> TimingMaker;
0721 DEFINE_FWK_SERVICE_MAKER(Timing, TimingMaker);