30 #include "oneapi/tbb/concurrent_unordered_map.h" 40 using duration_t = std::chrono::microseconds;
41 using clock_t = std::chrono::steady_clock;
51 class StallStatistics {
56 StallStatistics() =
default;
59 unsigned numberOfStalls()
const {
return stallCounter_; }
63 duration_t totalStalledTime()
const {
return duration_t{totalTime_.load()}; }
64 duration_t maxStalledTime()
const {
return duration_t{maxTime_.load()}; }
69 void update(duration_t
const ms) {
71 auto const thisTime = ms.count();
72 totalTime_ += thisTime;
74 while (thisTime >
max && !maxTime_.compare_exchange_strong(
max, thisTime))
80 std::atomic<unsigned> stallCounter_{};
81 std::atomic<rep_t> totalTime_{};
82 std::atomic<rep_t> maxTime_{};
92 template <
typename H,
typename...
T>
95 concatenate(os,
t...);
100 postSourceEvent =
's',
102 postModuleEventPrefetching =
'p',
103 preModuleEventAcquire =
'A',
104 postModuleEventAcquire =
'a',
105 preModuleEvent =
'M',
106 preEventReadFromSource =
'R',
107 postEventReadFromSource =
'r',
108 postModuleEvent =
'm',
110 postESModulePrefetching =
'q',
129 os << static_cast<std::underlying_type_t<step>>(
s);
134 os << static_cast<std::underlying_type_t<Phase>>(
s);
138 template <
step S,
typename... ARGS>
140 std::ostringstream oss;
142 concatenate(oss,
args...);
150 case StreamContext::Transition::kBeginRun:
151 return Phase::streamBeginRun;
152 case StreamContext::Transition::kBeginLuminosityBlock:
153 return Phase::streamBeginLumi;
154 case StreamContext::Transition::kEvent:
156 case StreamContext::Transition::kEndLuminosityBlock:
157 return Phase::streamEndLumi;
158 case StreamContext::Transition::kEndRun:
159 return Phase::streamEndRun;
167 auto toTransition(
edm::StreamContext const& iContext) -> std::underlying_type_t<Phase> {
168 return static_cast<std::underlying_type_t<Phase>
>(toTransitionImpl(iContext));
174 case GlobalContext::Transition::kBeginRun:
175 return Phase::globalBeginRun;
176 case GlobalContext::Transition::kBeginLuminosityBlock:
177 return Phase::globalBeginLumi;
178 case GlobalContext::Transition::kEndLuminosityBlock:
179 return Phase::globalEndLumi;
180 case GlobalContext::Transition::kWriteLuminosityBlock:
181 return Phase::globalEndLumi;
182 case GlobalContext::Transition::kEndRun:
183 return Phase::globalEndRun;
184 case GlobalContext::Transition::kWriteRun:
185 return Phase::globalEndRun;
192 auto toTransition(
edm::GlobalContext const& iContext) -> std::underlying_type_t<Phase> {
193 return static_cast<std::underlying_type_t<Phase>
>(toTransitionImpl(iContext));
230 decltype(
now()) beginTime_{};
237 using ModuleID = decltype(std::declval<ModuleDescription>().
id());
238 oneapi::tbb::concurrent_unordered_map<std::pair<StreamID_value, ModuleID>,
239 std::pair<decltype(beginTime_), bool>,
243 std::vector<std::string> moduleLabels_{};
244 std::vector<StallStatistics> moduleStats_{};
245 std::vector<std::string> esModuleLabels_{};
254 constexpr
char const*
const filename_default{
""};
255 constexpr
double threshold_default{0.1};
266 std::chrono::round<duration_t>(duration<double>(iPS.getUntrackedParameter<
double>(
"stallThreshold")))} {
310 iRegistry.postESModuleRegistrationSignal_.connect([
this](
auto const& iDescription) {
311 if (esModuleLabels_.size() <= iDescription.id_) {
312 esModuleLabels_.resize(iDescription.id_ + 1);
314 if (not iDescription.label_.empty()) {
315 esModuleLabels_[iDescription.id_] = iDescription.label_;
317 esModuleLabels_[iDescription.id_] = iDescription.type_;
321 iRegistry.preESModuleSignal_.connect([
this](
auto const&,
auto const&
context) {
322 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
323 auto msg = assembleMessage<step::preESModule>(
324 numStreams_, module_id(
context), std::underlying_type_t<Phase>(Phase::eventSetupCall),
t);
327 iRegistry.postESModuleSignal_.connect([
this](
auto const&,
auto const&
context) {
328 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
329 auto msg = assembleMessage<step::postESModule>(
330 numStreams_, module_id(
context), std::underlying_type_t<Phase>(Phase::eventSetupCall),
t);
334 iRegistry.preallocateSignal_.connect(
335 [
this](service::SystemBounds
const& iBounds) { numStreams_ = iBounds.maxNumberOfStreams(); });
337 std::ostringstream oss;
338 oss <<
"# Transition Symbol\n";
339 oss <<
"#----------------- ------\n";
340 oss <<
"# eventSetupCall " << Phase::eventSetupCall <<
"\n" 341 <<
"# globalBeginRun " << Phase::globalBeginRun <<
"\n" 342 <<
"# streamBeginRun " << Phase::streamBeginRun <<
"\n" 343 <<
"# globalBeginLumi " << Phase::globalBeginLumi <<
"\n" 344 <<
"# streamBeginLumi " << Phase::streamBeginLumi <<
"\n" 346 <<
"# streamEndLumi " << Phase::streamEndLumi <<
"\n" 347 <<
"# globalEndLumi " << Phase::globalEndLumi <<
"\n" 348 <<
"# streamEndRun " << Phase::streamEndRun <<
"\n" 349 <<
"# globalEndRun " << Phase::globalEndRun <<
"\n";
350 oss <<
"# Step Symbol Entries\n" 351 <<
"# -------------------------- ------ ------------------------------------------\n" 352 <<
"# preSourceEvent " << step::preSourceEvent <<
" <Stream ID> <Time since beginJob (ms)>\n" 353 <<
"# postSourceEvent " << step::postSourceEvent <<
" <Stream ID> <Time since beginJob (ms)>\n" 354 <<
"# preEvent " << step::preEvent
355 <<
" <Stream ID> <Run#> <LumiBlock#> <Event#> <Time since beginJob (ms)>\n" 356 <<
"# postModuleEventPrefetching " << step::postModuleEventPrefetching
357 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 358 <<
"# preModuleEventAcquire " << step::preModuleEventAcquire
359 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 360 <<
"# postModuleEventAcquire " << step::postModuleEventAcquire
361 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 362 <<
"# preModuleTransition " << step::preModuleEvent
363 <<
" <Stream ID> <Module ID> <Transition type> <Time since beginJob (ms)>\n" 364 <<
"# preEventReadFromSource " << step::preEventReadFromSource
365 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 366 <<
"# postEventReadFromSource " << step::postEventReadFromSource
367 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 368 <<
"# postModuleTransition " << step::postModuleEvent
369 <<
" <Stream ID> <Module ID> <Transition type> <Time since beginJob (ms)>\n" 370 <<
"# postEvent " << step::postEvent
371 <<
" <Stream ID> <Run#> <LumiBlock#> <Event#> <Time since beginJob (ms)>\n" 372 <<
"# postESModulePrefetching " << step::postESModulePrefetching
373 <<
" <Stream ID> <ESModule ID> <Transition type> <Time since beginJob (ms)>\n" 374 <<
"# preESModuleTransition " << step::preESModule
375 <<
" <StreamID> <ESModule ID> <TransitionType> <Time since beginJob (ms)>\n" 376 <<
"# postESModuleTransition " << step::postESModule
377 <<
" <StreamID> <ESModule ID> <TransitionType> <Time since beginJob (ms)>\n";
378 file_.
write(oss.str());
386 "Name of file to which detailed timing information should be written.\n" 387 "An empty filename argument (the default) indicates that no extra\n" 388 "information will be written to a dedicated file, but only the summary\n" 389 "including stalling-modules information will be logged.");
390 desc.addUntracked<
double>(
"stallThreshold", threshold_default)
392 "Threshold (in seconds) used to classify modules as stalled.\n" 393 "Microsecond granularity allowed.");
394 descriptions.
add(
"StallMonitor",
desc);
396 "This service keeps track of various times in event-processing to determine which modules are stalling.");
411 auto const mid = md.
id();
442 std::ostringstream oss;
443 oss <<
"\n# " << col0 << space << lastCol <<
'\n';
444 oss <<
"# " <<
std::string(col0.width() + space.size() + lastCol.size(),
'-') <<
'\n';
450 oss <<
"#M " << std::setw(
width) << std::left << col0(
i) << space << std::left <<
moduleLabels_[
i] <<
'\n';
460 std::ostringstream oss;
461 oss <<
"\n# " << col0 << space << lastCol <<
'\n';
462 oss <<
"# " <<
std::string(col0.width() + space.size() + lastCol.size(),
'-') <<
'\n';
468 oss <<
"#N " << std::setw(
width) << std::left << col0(
i) << space << std::left <<
esModuleLabels_[
i] <<
'\n';
484 auto msg = assembleMessage<step::preSourceEvent>(sid.
value(),
t);
490 auto msg = assembleMessage<step::postSourceEvent>(sid.
value(),
t);
497 auto msg = assembleMessage<step::preEvent>(stream_id(sc),
eid.run(),
eid.luminosityBlock(),
eid.event(),
t);
502 auto const sid = stream_id(sc);
503 auto const mid = module_id(mcc);
508 auto msg = assembleMessage<step::postModuleEventPrefetching>(sid, mid,
t);
514 auto const preModEventAcquire =
now();
515 auto const sid = stream_id(sc);
516 auto const mid = module_id(mcc);
518 auto startT =
start.first.time_since_epoch();
521 auto t = duration_cast<duration_t>(preModEventAcquire -
beginTime_).
count();
522 auto msg = assembleMessage<step::preModuleEventAcquire>(sid, mid,
t);
527 auto const preFetch_to_preModEventAcquire = duration_cast<duration_t>(preModEventAcquire -
start.first);
530 moduleStats_[mid].update(preFetch_to_preModEventAcquire);
535 auto const postModEventAcquire = duration_cast<duration_t>(
now() -
beginTime_).
count();
536 auto msg = assembleMessage<step::postModuleEventAcquire>(stream_id(sc), module_id(mcc), postModEventAcquire);
541 auto const preModEvent =
now();
542 auto const sid = stream_id(sc);
543 auto const mid = module_id(mcc);
545 auto startT =
start.first.time_since_epoch();
549 assembleMessage<step::preModuleEvent>(sid, mid,
static_cast<std::underlying_type_t<Phase>
>(
Phase::Event),
t);
554 auto const preFetch_to_preModEvent = duration_cast<duration_t>(preModEvent -
start.first);
562 auto const tNow =
now();
563 auto const sid = stream_id(sc);
564 auto const mid = module_id(mcc);
566 auto msg = assembleMessage<step::preModuleEvent>(sid, mid, toTransition(sc),
t);
572 auto msg = assembleMessage<step::postModuleEvent>(stream_id(sc), module_id(mcc), toTransition(sc),
t);
578 auto msg = assembleMessage<step::preModuleEvent>(
numStreams_, module_id(mcc), toTransition(gc),
t);
584 auto msg = assembleMessage<step::postModuleEvent>(
numStreams_, module_id(mcc), toTransition(gc), postModTime);
590 auto msg = assembleMessage<step::preEventReadFromSource>(stream_id(sc), module_id(mcc),
t);
596 auto msg = assembleMessage<step::postEventReadFromSource>(stream_id(sc), module_id(mcc),
t);
602 auto msg = assembleMessage<step::postModuleEvent>(
603 stream_id(sc), module_id(mcc),
static_cast<std::underlying_type_t<Phase>
>(
Phase::Event), postModEvent);
610 auto msg = assembleMessage<step::postEvent>(stream_id(sc),
eid.run(),
eid.luminosityBlock(),
eid.event(),
t);
618 if (
stats.numberOfStalls() == 0u)
631 out <<
tag << space << col1 << space << col2 << space << col3 << space << col4 <<
'\n';
636 using seconds_d = duration<double>;
638 auto to_seconds_str = [](
auto const& duration) {
639 std::ostringstream oss;
640 auto const time = duration_cast<seconds_d>(duration).
count();
645 out << std::setfill(
' ');
647 if (
stats.label().empty() ||
648 stats.numberOfStalls() == 0u)
650 out << std::left <<
tag << space << col1(
stats.label()) << space << std::right << col2(
stats.numberOfStalls())
651 << space << col3(to_seconds_str(
stats.totalStalledTime())) << space
652 << col4(to_seconds_str(
stats.maxStalledTime())) <<
'\n';
ModuleDescription const * moduleDescription() const
void preModuleEvent(StreamContext const &, ModuleCallingContext const &)
void preSourceEvent(StreamID)
ThreadSafeOutputFileStream file_
void postEvent(StreamContext const &)
decltype(now()) beginTime_
std::vector< std::string > esModuleLabels_
std::ostream & operator<<(std::ostream &out, const ALILine &li)
void preModuleConstruction(edm::ModuleDescription const &)
void swap(Association< C > &lhs, Association< C > &rhs)
void preModuleStreamTransition(StreamContext const &, ModuleCallingContext const &)
static std::string to_string(const XMLCh *ch)
void preModuleDestruction(edm::ModuleDescription const &)
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
T getUntrackedParameter(std::string const &, T const &) const
std::vector< std::string > moduleLabels_
void postModuleEventPrefetching(StreamContext const &, ModuleCallingContext const &)
void preEventReadFromSource(StreamContext const &, ModuleCallingContext const &)
duration_t const stallThreshold_
void preEvent(StreamContext const &)
Transition transition() const
void preModuleEventAcquire(StreamContext const &, ModuleCallingContext const &)
#define DEFINE_FWK_SERVICE(type)
void setComment(std::string const &value)
void postModuleEventAcquire(StreamContext const &, ModuleCallingContext const &)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
void postEventReadFromSource(StreamContext const &, ModuleCallingContext const &)
void postModuleGlobalTransition(GlobalContext const &, ModuleCallingContext const &)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
oneapi::tbb::concurrent_unordered_map< std::pair< StreamID_value, ModuleID >, std::pair< decltype(beginTime_), bool >, edm::StdPairHasher > stallStart_
Transition transition() const
void postModuleStreamTransition(StreamContext const &, ModuleCallingContext const &)
void postSourceEvent(StreamID)
void postModuleEvent(StreamContext const &, ModuleCallingContext const &)
decltype(std::declval< StreamID >().value()) StreamID_value
EventID const & eventID() const
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
std::vector< StallStatistics > moduleStats_
unsigned int value() const
decltype(std::declval< ModuleDescription >().id()) ModuleID
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
std::string const & moduleLabel() const
void write(std::string &&msg)
edm::eventsetup::ComponentDescription const * componentDescription() const
void preModuleGlobalTransition(GlobalContext const &, ModuleCallingContext const &)