33 #include "oneapi/tbb/concurrent_unordered_map.h" 44 using duration_t = std::chrono::microseconds;
45 using clock_t = std::chrono::steady_clock;
49 class StallStatistics {
54 StallStatistics() =
default;
57 unsigned numberOfStalls()
const {
return stallCounter_; }
61 duration_t totalStalledTime()
const {
return duration_t{totalTime_.load()}; }
62 duration_t maxStalledTime()
const {
return duration_t{maxTime_.load()}; }
67 void update(duration_t
const ms) {
69 auto const thisTime = ms.count();
70 totalTime_ += thisTime;
72 while (thisTime >
max && !maxTime_.compare_exchange_strong(
max, thisTime))
78 std::atomic<unsigned> stallCounter_{};
79 std::atomic<rep_t> totalTime_{};
80 std::atomic<rep_t> maxTime_{};
85 postSourceEvent =
's',
87 postModuleEventPrefetching =
'p',
88 preModuleEventAcquire =
'A',
89 postModuleEventAcquire =
'a',
91 preEventReadFromSource =
'R',
92 postEventReadFromSource =
'r',
93 postModuleEvent =
'm',
95 postESModulePrefetching =
'q',
98 preFrameworkTransition =
'F',
99 postFrameworkTransition =
'f' 116 os << static_cast<std::underlying_type_t<step>>(
s);
121 os << static_cast<std::underlying_type_t<Phase>>(
s);
125 template <
step S,
typename... ARGS>
127 std::ostringstream oss;
138 return Phase::streamBeginRun;
140 return Phase::streamBeginLumi;
144 return Phase::streamEndLumi;
146 return Phase::streamEndRun;
154 auto toTransition(
edm::StreamContext const& iContext) -> std::underlying_type_t<Phase> {
155 return static_cast<std::underlying_type_t<Phase>
>(toTransitionImpl(iContext));
162 return Phase::globalBeginRun;
164 return Phase::globalBeginLumi;
166 return Phase::globalEndLumi;
168 return Phase::globalEndLumi;
170 return Phase::globalEndRun;
172 return Phase::globalEndRun;
179 auto toTransition(
edm::GlobalContext const& iContext) -> std::underlying_type_t<Phase> {
180 return static_cast<std::underlying_type_t<Phase>
>(toTransitionImpl(iContext));
217 decltype(
now()) beginTime_{};
224 using ModuleID = decltype(std::declval<ModuleDescription>().
id());
225 oneapi::tbb::concurrent_unordered_map<std::pair<StreamID_value, ModuleID>,
226 std::pair<decltype(beginTime_), bool>,
230 std::vector<std::string> moduleLabels_{};
231 std::vector<StallStatistics> moduleStats_{};
232 std::vector<std::string> esModuleLabels_{};
241 constexpr char const*
const filename_default{
""};
253 std::chrono::round<duration_t>(duration<double>(iPS.getUntrackedParameter<
double>(
"stallThreshold")))} {
297 iRegistry.postESModuleRegistrationSignal_.connect([
this](
auto const& iDescription) {
298 if (esModuleLabels_.size() <= iDescription.id_) {
299 esModuleLabels_.resize(iDescription.id_ + 1);
301 if (not iDescription.label_.empty()) {
302 esModuleLabels_[iDescription.id_] = iDescription.label_;
304 esModuleLabels_[iDescription.id_] = iDescription.type_;
308 iRegistry.preESModuleSignal_.connect([
this](
auto const&,
auto const&
context) {
309 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
310 auto msg = assembleMessage<step::preESModule>(
311 numStreams_,
module_id(
context), std::underlying_type_t<Phase>(Phase::eventSetupCall),
t);
314 iRegistry.postESModuleSignal_.connect([
this](
auto const&,
auto const&
context) {
315 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
316 auto msg = assembleMessage<step::postESModule>(
317 numStreams_,
module_id(
context), std::underlying_type_t<Phase>(Phase::eventSetupCall),
t);
321 iRegistry.preallocateSignal_.connect(
322 [
this](service::SystemBounds
const& iBounds) { numStreams_ = iBounds.maxNumberOfStreams(); });
324 bool recordFrameworkTransitions = iPS.getUntrackedParameter<
bool>(
"recordFrameworkTransitions");
325 if (recordFrameworkTransitions) {
328 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
329 auto msg = assembleMessage<step::preFrameworkTransition>(
330 numStreams_, gc.luminosityBlockID().run(), gc.luminosityBlockID().luminosityBlock(), toTransition(gc),
t);
333 iRegistry.watchPreGlobalBeginRun(preGlobal);
334 iRegistry.watchPreGlobalBeginLumi(preGlobal);
335 iRegistry.watchPreGlobalEndLumi(preGlobal);
336 iRegistry.watchPreGlobalEndRun(preGlobal);
340 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
341 auto msg = assembleMessage<step::postFrameworkTransition>(
342 numStreams_, gc.luminosityBlockID().run(), gc.luminosityBlockID().luminosityBlock(), toTransition(gc),
t);
345 iRegistry.watchPostGlobalBeginRun(postGlobal);
346 iRegistry.watchPostGlobalBeginLumi(postGlobal);
347 iRegistry.watchPostGlobalEndLumi(postGlobal);
348 iRegistry.watchPostGlobalEndRun(postGlobal);
352 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
353 auto msg = assembleMessage<step::preFrameworkTransition>(
354 stream_id(sc), sc.eventID().run(), sc.eventID().luminosityBlock(), toTransition(sc),
t);
357 iRegistry.watchPreStreamBeginRun(preStream);
358 iRegistry.watchPreStreamBeginLumi(preStream);
359 iRegistry.watchPreStreamEndLumi(preStream);
360 iRegistry.watchPreStreamEndRun(preStream);
364 auto const t = duration_cast<duration_t>(
now() - beginTime_).
count();
365 auto msg = assembleMessage<step::postFrameworkTransition>(
366 stream_id(sc), sc.eventID().run(), sc.eventID().luminosityBlock(), toTransition(sc),
t);
369 iRegistry.watchPostStreamBeginRun(postStream);
370 iRegistry.watchPostStreamBeginLumi(postStream);
371 iRegistry.watchPostStreamEndLumi(postStream);
372 iRegistry.watchPostStreamEndRun(postStream);
376 std::ostringstream oss;
377 oss <<
"# Transition Symbol\n";
378 oss <<
"#----------------- ------\n";
379 oss <<
"# eventSetupCall " << Phase::eventSetupCall <<
"\n" 380 <<
"# globalBeginRun " << Phase::globalBeginRun <<
"\n" 381 <<
"# streamBeginRun " << Phase::streamBeginRun <<
"\n" 382 <<
"# globalBeginLumi " << Phase::globalBeginLumi <<
"\n" 383 <<
"# streamBeginLumi " << Phase::streamBeginLumi <<
"\n" 385 <<
"# streamEndLumi " << Phase::streamEndLumi <<
"\n" 386 <<
"# globalEndLumi " << Phase::globalEndLumi <<
"\n" 387 <<
"# streamEndRun " << Phase::streamEndRun <<
"\n" 388 <<
"# globalEndRun " << Phase::globalEndRun <<
"\n";
389 oss <<
"# Step Symbol Entries\n" 390 <<
"# -------------------------- ------ ------------------------------------------\n" 391 <<
"# preSourceEvent " << step::preSourceEvent <<
" <Stream ID> <Time since beginJob (ms)>\n" 392 <<
"# postSourceEvent " << step::postSourceEvent <<
" <Stream ID> <Time since beginJob (ms)>\n" 393 <<
"# preEvent " << step::preEvent
394 <<
" <Stream ID> <Run#> <LumiBlock#> <Event#> <Time since beginJob (ms)>\n" 395 <<
"# postModuleEventPrefetching " << step::postModuleEventPrefetching
396 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 397 <<
"# preModuleEventAcquire " << step::preModuleEventAcquire
398 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 399 <<
"# postModuleEventAcquire " << step::postModuleEventAcquire
400 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 401 <<
"# preModuleTransition " << step::preModuleEvent
402 <<
" <Stream ID> <Module ID> <Transition type> <Time since beginJob (ms)>\n" 403 <<
"# preEventReadFromSource " << step::preEventReadFromSource
404 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 405 <<
"# postEventReadFromSource " << step::postEventReadFromSource
406 <<
" <Stream ID> <Module ID> <Time since beginJob (ms)>\n" 407 <<
"# postModuleTransition " << step::postModuleEvent
408 <<
" <Stream ID> <Module ID> <Transition type> <Time since beginJob (ms)>\n" 409 <<
"# postEvent " << step::postEvent
410 <<
" <Stream ID> <Run#> <LumiBlock#> <Event#> <Time since beginJob (ms)>\n" 411 <<
"# postESModulePrefetching " << step::postESModulePrefetching
412 <<
" <Stream ID> <ESModule ID> <Transition type> <Time since beginJob (ms)>\n" 413 <<
"# preESModuleTransition " << step::preESModule
414 <<
" <StreamID> <ESModule ID> <TransitionType> <Time since beginJob (ms)>\n" 415 <<
"# postESModuleTransition " << step::postESModule
416 <<
" <StreamID> <ESModule ID> <TransitionType> <Time since beginJob (ms)>\n";
417 if (recordFrameworkTransitions) {
418 oss <<
"# preFrameworkTransition " << step::preFrameworkTransition
419 <<
" <Stream ID> <Run#> <LumiBlock#> <Transition type> <Time since beginJob (ms)>\n" 420 <<
"# postFrameworkTransition " << step::postFrameworkTransition
421 <<
" <Stream ID> <Run#> <LumiBlock#> <Transition type> <Time since beginJob (ms)>\n";
423 file_.
write(oss.str());
431 "Name of file to which detailed timing information should be written.\n" 432 "An empty filename argument (the default) indicates that no extra\n" 433 "information will be written to a dedicated file, but only the summary\n" 434 "including stalling-modules information will be logged.");
435 desc.addUntracked<
double>(
"stallThreshold", threshold_default)
437 "Threshold (in seconds) used to classify modules as stalled.\n" 438 "Microsecond granularity allowed.");
439 desc.addUntracked<
bool>(
"recordFrameworkTransitions",
false)
441 "When writing a file, include the framework state transitions:\n" 442 " stream and global, begin and end, Run and LuminosityBlock.");
443 descriptions.
add(
"StallMonitor",
desc);
445 "This service keeps track of various times in event-processing to determine which modules are stalling.");
460 auto const mid = md.
id();
487 std::ostringstream oss;
492 std::ostringstream oss;
507 auto msg = assembleMessage<step::preSourceEvent>(sid.
value(),
t);
513 auto msg = assembleMessage<step::postSourceEvent>(sid.
value(),
t);
520 auto msg = assembleMessage<step::preEvent>(
stream_id(sc),
eid.run(),
eid.luminosityBlock(),
eid.event(),
t);
531 auto msg = assembleMessage<step::postModuleEventPrefetching>(sid, mid,
t);
537 auto const preModEventAcquire =
now();
541 auto startT =
start.first.time_since_epoch();
544 auto t = duration_cast<duration_t>(preModEventAcquire -
beginTime_).
count();
545 auto msg = assembleMessage<step::preModuleEventAcquire>(sid, mid,
t);
550 auto const preFetch_to_preModEventAcquire = duration_cast<duration_t>(preModEventAcquire -
start.first);
553 moduleStats_[mid].update(preFetch_to_preModEventAcquire);
558 auto const postModEventAcquire = duration_cast<duration_t>(
now() -
beginTime_).
count();
559 auto msg = assembleMessage<step::postModuleEventAcquire>(
stream_id(sc),
module_id(mcc), postModEventAcquire);
564 auto const preModEvent =
now();
568 auto startT =
start.first.time_since_epoch();
572 assembleMessage<step::preModuleEvent>(sid, mid,
static_cast<std::underlying_type_t<Phase>
>(
Phase::Event),
t);
577 auto const preFetch_to_preModEvent = duration_cast<duration_t>(preModEvent -
start.first);
585 auto const tNow =
now();
589 auto msg = assembleMessage<step::preModuleEvent>(sid, mid, toTransition(sc),
t);
625 auto msg = assembleMessage<step::postModuleEvent>(
633 auto msg = assembleMessage<step::postEvent>(
stream_id(sc),
eid.run(),
eid.luminosityBlock(),
eid.event(),
t);
641 if (
stats.numberOfStalls() == 0u)
654 out <<
tag << space << col1 << space << col2 << space << col3 << space << col4 <<
'\n';
659 using seconds_d = duration<double>;
661 auto to_seconds_str = [](
auto const& duration) {
662 std::ostringstream oss;
663 auto const time = duration_cast<seconds_d>(duration).
count();
668 out << std::setfill(
' ');
670 if (
stats.label().empty() ||
671 stats.numberOfStalls() == 0u)
673 out << std::left <<
tag << space << col1(
stats.label()) << space << std::right << col2(
stats.numberOfStalls())
674 << space << col3(to_seconds_str(
stats.totalStalledTime())) << space
675 << col4(to_seconds_str(
stats.maxStalledTime())) <<
'\n';
void preModuleEvent(StreamContext const &, ModuleCallingContext const &)
auto module_id(edm::ModuleCallingContext const &mcc)
void preSourceEvent(StreamID)
ThreadSafeOutputFileStream file_
void postEvent(StreamContext const &)
decltype(now()) beginTime_
std::vector< std::string > esModuleLabels_
void preModuleConstruction(edm::ModuleDescription const &)
void swap(Association< C > &lhs, Association< C > &rhs)
void preModuleStreamTransition(StreamContext const &, ModuleCallingContext const &)
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
StallMonitor(ParameterSet const &, ActivityRegistry &)
std::ostream & operator<<(std::ostream &os, SimpleMemoryCheck::SignificantEvent const &se)
void preModuleEventAcquire(StreamContext const &, ModuleCallingContext const &)
#define DEFINE_FWK_SERVICE(type)
void setComment(std::string const &value)
void moduleIdToLabel(std::ostream &oStream, std::vector< std::string > const &iModuleLabels, char moduleIdSymbol, std::string const &iIDHeader, std::string const &iLabelHeader)
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 concatenate(std::ostream &os, T const t)
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
std::string const & moduleLabel() const
auto stream_id(edm::StreamContext const &cs)
void write(std::string &&msg)
void preModuleGlobalTransition(GlobalContext const &, ModuleCallingContext const &)
EventID const & max(EventID const &lh, EventID const &rh)