CMS 3D CMS Logo

ThroughputService.cc
Go to the documentation of this file.
1 // C++ headers
2 #include <algorithm>
3 #include <chrono>
4 #include <ctime>
5 
6 // {fmt} headers
7 #include <fmt/printf.h>
8 
9 // CMSSW headers
14 #include "ThroughputService.h"
15 
16 using namespace std::literals;
17 
18 // describe the module's configuration
21  desc.addUntracked<uint32_t>("eventRange", 10000)->setComment("Preallocate a buffer for N events");
22  desc.addUntracked<uint32_t>("eventResolution", 1)->setComment("Sample the processing time every N events");
23  desc.addUntracked<bool>("printEventSummary", false);
24  desc.ifValue(edm::ParameterDescription<bool>("enableDQM", true, false), // "false" means untracked
25  // parameters if "enableDQM" is "true"
26  true >> (edm::ParameterDescription<bool>("dqmPathByProcesses", false, false) and
27  edm::ParameterDescription<std::string>("dqmPath", "HLT/Throughput", false) and
28  edm::ParameterDescription<double>("timeRange", 60000.0, false) and
29  edm::ParameterDescription<double>("timeResolution", 10.0, false)) or
30  // parameters if "enableDQM" is "false"
31  false >> edm::EmptyGroupDescription());
32  descriptions.add("ThroughputService", desc);
33 }
34 
36  : // startup time
37  m_startup(std::chrono::system_clock::now()),
38  // configuration
39  m_resolution(config.getUntrackedParameter<uint32_t>("eventResolution")),
40  m_counter(0),
41  m_events(config.getUntrackedParameter<uint32_t>("eventRange") / m_resolution), // allocate initial size
42  m_print_event_summary(config.getUntrackedParameter<bool>("printEventSummary")),
43  m_enable_dqm(config.getUntrackedParameter<bool>("enableDQM")),
44  m_dqm_bynproc(m_enable_dqm ? config.getUntrackedParameter<bool>("dqmPathByProcesses") : false),
45  m_dqm_path(m_enable_dqm ? config.getUntrackedParameter<std::string>("dqmPath") : ""),
46  m_time_range(m_enable_dqm ? config.getUntrackedParameter<double>("timeRange") : 0.),
47  m_time_resolution(m_enable_dqm ? config.getUntrackedParameter<double>("timeResolution") : 0.) {
48  m_events.clear(); // erases all elements, but does not free internal arrays
54 }
55 
57  auto concurrent_streams = bounds.maxNumberOfStreams();
58  auto concurrent_threads = bounds.maxNumberOfThreads();
59 
61  m_dqm_path += fmt::sprintf(
62  "/Running on %s with %d streams on %d threads", processor_model, concurrent_streams, concurrent_threads);
63 }
64 
66  // if the DQMStore is available, book the DQM histograms
67  // check that the DQMStore service is available
68  if (m_enable_dqm and not edm::Service<DQMStore>().isAvailable()) {
69  // the DQMStore is not available, disable all DQM plots
70  m_enable_dqm = false;
71  edm::LogWarning("ThroughputService") << "The DQMStore is not avalable, the DQM plots will not be generated";
72  }
73 
74  if (m_enable_dqm) {
75  std::string y_axis_title = fmt::sprintf("events / %g s", m_time_resolution);
76  unsigned int bins = std::round(m_time_range / m_time_resolution);
77  double range = bins * m_time_resolution;
78 
79  // clean characters that are deemed unsafe for DQM
80  // see the definition of `s_safe` in DQMServices/Core/src/DQMStore.cc
81  auto safe_for_dqm = "/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+=_()# "s;
82  for (auto& c : m_dqm_path)
83  if (safe_for_dqm.find(c) == std::string::npos)
84  c = '_';
85 
86  // define a callback that can book the histograms
87  auto bookTransactionCallback = [&, this](DQMStore::IBooker& booker, DQMStore::IGetter&) {
88  auto scope = dqm::reco::DQMStore::IBooker::UseRunScope(booker);
90  m_sourced_events = booker.book1D("throughput_sourced", "Throughput (sourced events)", bins, 0., range);
91  m_sourced_events->setXTitle("time [s]");
92  m_sourced_events->setYTitle(y_axis_title);
93  m_retired_events = booker.book1D("throughput_retired", "Throughput (retired events)", bins, 0., range);
94  m_retired_events->setXTitle("time [s]");
95  m_retired_events->setYTitle(y_axis_title);
96  };
97 
98  // book MonitorElement's for this run
99  edm::Service<DQMStore>()->meBookerGetter(bookTransactionCallback);
100  } else {
101  m_sourced_events = nullptr;
102  m_retired_events = nullptr;
103  }
104 }
105 
108  auto interval = std::chrono::duration_cast<std::chrono::duration<double>>(timestamp - m_startup).count();
109  if (m_enable_dqm) {
111  }
112 }
113 
116  auto interval = std::chrono::duration_cast<std::chrono::duration<double>>(timestamp - m_startup).count();
117  if (m_enable_dqm) {
119  }
120  ++m_counter;
121  if (m_counter % m_resolution == 0) {
122  m_events.push_back(timestamp);
123  }
124 }
125 
127  if (m_counter < 2 * m_resolution) {
128  // not enough mesurements to estimate the throughput
129  edm::LogWarning("ThroughputService") << "Not enough events to measure the throughput with a resolution of "
130  << m_resolution << " events";
131  return;
132  }
133 
134  edm::LogInfo info("ThroughputService");
135 
136  if (m_print_event_summary) {
137  for (uint32_t i = 0; i < m_events.size(); ++i) {
138  info << std::setw(8) << (i + 1) * m_resolution << ", " << std::setprecision(6) << edm::TimeOfDay(m_events[i])
139  << "\n";
140  }
141  info << '\n';
142  }
143 
144  // measure the time to process each block of m_resolution events
145  uint32_t blocks = m_counter / m_resolution - 1;
146  std::vector<double> delta(blocks);
147  for (uint32_t i = 0; i < blocks; ++i) {
148  delta[i] = std::chrono::duration_cast<std::chrono::duration<double>>(m_events[i + 1] - m_events[i]).count();
149  }
150  // measure the average and standard deviation of the time to process m_resolution
151  double time_avg = TMath::Mean(delta.begin(), delta.begin() + blocks);
152  double time_dev = TMath::StdDev(delta.begin(), delta.begin() + blocks);
153  // compute the throughput and its standard deviation across the job
154  double throughput_avg = double(m_resolution) / time_avg;
155  double throughput_dev = double(m_resolution) * time_dev / time_avg / time_avg;
156 
157  info << "Average throughput: " << throughput_avg << " ± " << throughput_dev << " ev/s";
158 }
159 
160 // declare ThroughputService as a framework Service
void preallocate(edm::service::SystemBounds const &bounds)
dqm::reco::MonitorElement * m_sourced_events
static const TGPicture * info(bool iBackgroundIsBlack)
void watchPreallocate(Preallocate::slot_type const &iSlot)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:36
void preSourceEvent(edm::StreamID sid)
void watchPostEvent(PostEvent::slot_type const &iSlot)
dqm::reco::MonitorElement * m_retired_events
void postEvent(edm::StreamContext const &sc)
Definition: config.py:1
tbb::concurrent_vector< std::chrono::system_clock::time_point > m_events
void preGlobalBeginRun(edm::GlobalContext const &gc)
void Fill(long long x)
virtual void setXTitle(std::string const &title)
std::string m_dqm_path
const std::string processor_model
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
void watchPreGlobalBeginRun(PreGlobalBeginRun::slot_type const &iSlot)
#define DEFINE_FWK_SERVICE(type)
Definition: ServiceMaker.h:97
virtual void setYTitle(std::string const &title)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
ThroughputService(const edm::ParameterSet &, edm::ActivityRegistry &)
std::atomic< uint32_t > m_counter
std::chrono::system_clock::time_point m_startup
const double m_time_resolution
const double m_time_range
void watchPreSourceEvent(PreSourceEvent::slot_type const &iSlot)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
const bool m_dqm_bynproc
Log< level::Warning, false > LogWarning
MonitorElement * book1D(TString const &name, TString const &title, int const nchX, double const lowX, double const highX, FUNC onbooking=NOOP())
Definition: DQMStore.h:98
UseScope< MonitorElementData::Scope::RUN > UseRunScope
Definition: DQMStore.h:541
const uint32_t m_resolution
def StdDev(data_list)
Definition: TkAlMap.py:117