CMS 3D CMS Logo

TriggerRatesMonitor.cc
Go to the documentation of this file.
1 // Note to self: the implementation uses TH1F's to store the L1T and HLT rates.
2 // Assuming a maximum rate of 100 kHz times a period of 23.31 s, one needs to store counts up to ~2.3e6.
3 // A "float" has 24 bits of precision, so it can store up to 2**24 ~ 16.7e6 without loss of precision.
4 
5 // C++ headers
6 #include <algorithm>
7 #include <string>
8 #include <vector>
9 
10 #include <fmt/printf.h>
11 
12 // boost headers
13 #include <boost/regex.hpp>
14 
15 // CMSSW headers
30 
31 namespace {
32 
34 
35  struct RunBasedHistograms {
36  // HLT configuration
37  struct HLTIndices {
38  unsigned int index_l1_seed;
39  unsigned int index_prescale;
40 
41  HLTIndices() : index_l1_seed((unsigned int)-1), index_prescale((unsigned int)-1) {}
42  };
43 
45  std::vector<HLTIndices> hltIndices;
46 
47  std::vector<std::vector<unsigned int>> datasets;
48  std::vector<std::vector<unsigned int>> streams;
49 
50  // L1T and HLT rate plots
51 
52  // per-path HLT plots
53  struct HLTRatesPlots {
54  MonitorElement *pass_l1_seed;
55  MonitorElement *pass_prescale;
59  };
60 
61  // overall event count and event types
62  MonitorElement *events_processed;
63  std::vector<MonitorElement *> tcds_counts;
64 
65  // L1T triggers
66  std::vector<MonitorElement *> l1t_counts;
67 
68  // HLT triggers
69  std::vector<std::vector<HLTRatesPlots>> hlt_by_dataset_counts;
70 
71  // datasets
72  std::vector<MonitorElement *> dataset_counts;
73 
74  // streams
75  std::vector<MonitorElement *> stream_counts;
76 
77  RunBasedHistograms()
78  : // L1T and HLT configuration
79  hltConfig(),
80  hltIndices(),
81  datasets(),
82  streams(),
83  // overall event count and event types
84  events_processed(),
85  tcds_counts(),
86  // L1T triggers
87  l1t_counts(),
88  // HLT triggers
89  hlt_by_dataset_counts(),
90  // datasets
91  dataset_counts(),
92  // streams
93  stream_counts() {}
94  };
95 } // namespace
96 
97 class TriggerRatesMonitor : public DQMGlobalEDAnalyzer<RunBasedHistograms> {
98 public:
99  explicit TriggerRatesMonitor(edm::ParameterSet const &);
100  ~TriggerRatesMonitor() override = default;
101 
102  static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
103 
104 private:
105  void dqmBeginRun(edm::Run const &, edm::EventSetup const &, RunBasedHistograms &) const override;
107  edm::Run const &,
108  edm::EventSetup const &,
109  RunBasedHistograms &) const override;
110  void dqmAnalyze(edm::Event const &, edm::EventSetup const &, RunBasedHistograms const &) const override;
111 
112  // TCDS trigger types
113  // see https://twiki.cern.ch/twiki/bin/viewauth/CMS/TcdsEventRecord
114  static constexpr const char *const s_tcds_trigger_types[] = {
115  "Empty", // 0 - No trigger
116  "Physics", // 1 - GT trigger
117  "Calibration", // 2 - Sequence trigger (calibration)
118  "Random", // 3 - Random trigger
119  "Auxiliary", // 4 - Auxiliary (CPM front panel NIM input) trigger
120  nullptr, // 5 - reserved
121  nullptr, // 6 - reserved
122  nullptr, // 7 - reserved
123  "Cyclic", // 8 - Cyclic trigger
124  "Bunch-pattern", // 9 - Bunch-pattern trigger
125  "Software", // 10 - Software trigger
126  "TTS", // 11 - TTS-sourced trigger
127  nullptr, // 12 - reserved
128  nullptr, // 13 - reserved
129  nullptr, // 14 - reserved
130  nullptr // 15 - reserved
131  };
132 
133  // module configuration
138  const uint32_t m_lumisections_range;
139 };
140 
141 // definition
142 constexpr const char *const TriggerRatesMonitor::s_tcds_trigger_types[];
143 
146  desc.addUntracked<edm::InputTag>("l1tResults", edm::InputTag("gtStage2Digis"));
147  desc.addUntracked<edm::InputTag>("hltResults", edm::InputTag("TriggerResults"));
148  desc.addUntracked<std::string>("dqmPath", "HLT/TriggerRates");
149  desc.addUntracked<uint32_t>("lumisectionRange", 2500); // ~16 hours
150  descriptions.add("triggerRatesMonitor", desc);
151 }
152 
154  : // module configuration
155  m_l1tMenuToken{esConsumes<edm::Transition::BeginRun>()},
156  m_l1t_results(consumes<GlobalAlgBlkBxCollection>(config.getUntrackedParameter<edm::InputTag>("l1tResults"))),
157  m_hlt_results(consumes<edm::TriggerResults>(config.getUntrackedParameter<edm::InputTag>("hltResults"))),
158  m_dqm_path(config.getUntrackedParameter<std::string>("dqmPath")),
159  m_lumisections_range(config.getUntrackedParameter<uint32_t>("lumisectionRange")) {}
160 
162  edm::EventSetup const &setup,
163  RunBasedHistograms &histograms) const {
164  histograms.tcds_counts.clear();
165  histograms.tcds_counts.resize(sizeof(s_tcds_trigger_types) / sizeof(const char *));
166 
167  // cache the L1T trigger menu
168  histograms.l1t_counts.clear();
169  histograms.l1t_counts.resize(GlobalAlgBlk::maxPhysicsTriggers);
170 
171  // initialise the HLTConfigProvider
172  bool changed = true;
175  if (histograms.hltConfig.init(run, setup, labels.process, changed)) {
176  // number of trigger paths in labels.process
177  auto const nTriggers = histograms.hltConfig.size();
178  histograms.hltIndices.resize(nTriggers);
179 
180  unsigned int const nDatasets = histograms.hltConfig.datasetNames().size();
181  histograms.hlt_by_dataset_counts.clear();
182  histograms.hlt_by_dataset_counts.resize(nDatasets);
183 
184  histograms.datasets.clear();
185  histograms.datasets.resize(nDatasets);
186  for (unsigned int i = 0; i < nDatasets; ++i) {
187  auto const &paths = histograms.hltConfig.datasetContent(i);
188  histograms.hlt_by_dataset_counts[i].resize(paths.size());
189  histograms.datasets[i].reserve(paths.size());
190  for (auto const &path : paths) {
191  auto const triggerIdx = histograms.hltConfig.triggerIndex(path);
192  if (triggerIdx < nTriggers)
193  histograms.datasets[i].push_back(triggerIdx);
194  else
195  LogDebug("TriggerRatesMonitor")
196  << "The rates of the HLT path \"" << path << "\" (dataset: \"" << histograms.hltConfig.datasetName(i)
197  << "\") will not be monitored for this run.\nThis HLT path is not available in the process \""
198  << labels.process << "\", but it is listed in its \"datasets\" PSet.";
199  }
200  }
201  histograms.dataset_counts.clear();
202  histograms.dataset_counts.resize(nDatasets);
203 
204  unsigned int const nStreams = histograms.hltConfig.streamNames().size();
205  histograms.streams.clear();
206  histograms.streams.resize(nStreams);
207  for (unsigned int i = 0; i < nStreams; ++i) {
208  for (auto const &dataset : histograms.hltConfig.streamContent(i)) {
209  for (auto const &path : histograms.hltConfig.datasetContent(dataset)) {
210  auto const triggerIdx = histograms.hltConfig.triggerIndex(path);
211  if (triggerIdx < nTriggers)
212  histograms.streams[i].push_back(triggerIdx);
213  else
214  LogDebug("TriggerRatesMonitor")
215  << "The rates of the HLT path \"" << path << "\" (stream: \"" << histograms.hltConfig.streamName(i)
216  << "\", dataset: \"" << dataset << "\") will not be monitored for this run.\n"
217  << "This HLT path is not available in the process \"" << labels.process
218  << "\", but it is listed in its \"datasets\" PSet.";
219  }
220  }
221  std::sort(histograms.streams[i].begin(), histograms.streams[i].end());
222  auto unique_end = std::unique(histograms.streams[i].begin(), histograms.streams[i].end());
223  histograms.streams[i].resize(unique_end - histograms.streams[i].begin());
224  histograms.streams[i].shrink_to_fit();
225  }
226  histograms.stream_counts.clear();
227  histograms.stream_counts.resize(nStreams);
228  } else {
229  // HLTConfigProvider not initialised, skip the the HLT monitoring
230  edm::LogError("TriggerRatesMonitor") << "Failed to initialise HLTConfigProvider: the rates of HLT triggers, "
231  "datasets and streams will not be monitored for this run.";
232  }
233 }
234 
236  edm::Run const &run,
237  edm::EventSetup const &setup,
238  RunBasedHistograms &histograms) const {
239  // book histograms for the overall event count, and trigger types
241  histograms.events_processed = booker.book1D(
242  "events", "Processed events vs. lumisection", m_lumisections_range + 1, -0.5, m_lumisections_range + 0.5);
243  booker.setCurrentFolder(m_dqm_path + "/TCDS");
244  unsigned int const sizeof_tcds_trigger_types = sizeof(s_tcds_trigger_types) / sizeof(const char *);
245  if (sizeof_tcds_trigger_types == histograms.tcds_counts.size()) {
246  for (unsigned int i = 0; i < sizeof_tcds_trigger_types; ++i)
247  if (s_tcds_trigger_types[i]) {
248  std::string const &title = fmt::sprintf("%s events vs. lumisection", s_tcds_trigger_types[i]);
249  histograms.tcds_counts[i] =
251  }
252  } else
253  edm::LogError("TriggerRatesMonitor")
254  << "This should never happen: size of \"s_tcds_trigger_types\" array (" << sizeof_tcds_trigger_types
255  << ") differs from size of \"histograms.tcds_counts\" vector (size=" << histograms.tcds_counts.size()
256  << ").\nRate histograms of TCDS trigger types will not be booked for this run.";
257 
258  // book the rate histograms for the L1T triggers that are included in the L1T menu
259  booker.setCurrentFolder(m_dqm_path + "/L1T");
260  auto const &l1tMenu = setup.getData(m_l1tMenuToken);
261  for (auto const &keyval : l1tMenu.getAlgorithmMap()) {
262  unsigned int const bit = keyval.second.getIndex();
263  if (bit >= histograms.l1t_counts.size()) {
264  edm::LogError("TriggerRatesMonitor")
265  << "This should never happen: bit of L1T algorithm (bit=" << bit << ", name=\"" << keyval.first
266  << "\") is not smaller than size of \"histograms.l1t_counts\" vector (size=" << histograms.l1t_counts.size()
267  << ").\nRate histogram of this L1T algorithm will not be booked for this run.";
268  continue;
269  }
270  bool masked = false; // FIXME read L1T masks once they will be avaiable in the EventSetup
271  std::string const &name = fmt::sprintf("%s (bit %d)", keyval.first, bit);
272  std::string const &title =
273  fmt::sprintf("%s (bit %d)%s vs. lumisection", keyval.first, bit, (masked ? " (masked)" : ""));
274  histograms.l1t_counts[bit] = booker.book1D(name, title, m_lumisections_range + 1, -0.5, m_lumisections_range + 0.5);
275  }
276 
277  if (histograms.hltConfig.inited()) {
278  auto const &datasetNames = histograms.hltConfig.datasetNames();
279 
280  // book the rate histograms for the HLT triggers
281  for (unsigned int d = 0; d < datasetNames.size(); ++d) {
282  booker.setCurrentFolder(m_dqm_path + "/HLT/" + datasetNames[d]);
283  for (unsigned int i = 0; i < histograms.datasets[d].size(); ++i) {
284  unsigned int index = histograms.datasets[d][i];
285  std::string const &name = histograms.hltConfig.triggerName(index);
286  histograms.hlt_by_dataset_counts[d][i].pass_l1_seed = booker.book1D(name + "_pass_L1_seed",
287  name + " pass L1 seed, vs. lumisection",
289  -0.5,
290  m_lumisections_range + 0.5);
291  histograms.hlt_by_dataset_counts[d][i].pass_prescale = booker.book1D(name + "_pass_prescaler",
292  name + " pass prescaler, vs. lumisection",
294  -0.5,
295  m_lumisections_range + 0.5);
296  histograms.hlt_by_dataset_counts[d][i].accept = booker.book1D(name + "_accept",
297  name + " accept, vs. lumisection",
299  -0.5,
300  m_lumisections_range + 0.5);
301  histograms.hlt_by_dataset_counts[d][i].reject = booker.book1D(name + "_reject",
302  name + " reject, vs. lumisection",
304  -0.5,
305  m_lumisections_range + 0.5);
306  histograms.hlt_by_dataset_counts[d][i].error = booker.book1D(name + "_error",
307  name + " error, vs. lumisection",
309  -0.5,
310  m_lumisections_range + 0.5);
311  }
312 
313  for (unsigned int i : histograms.datasets[d]) {
314  // look for the index of the (last) L1T seed and prescale module in each path
315  histograms.hltIndices[i].index_l1_seed = histograms.hltConfig.size(i);
316  histograms.hltIndices[i].index_prescale = histograms.hltConfig.size(i);
317  for (unsigned int j = 0; j < histograms.hltConfig.size(i); ++j) {
318  std::string const &label = histograms.hltConfig.moduleLabel(i, j);
319  std::string const &type = histograms.hltConfig.moduleType(label);
320  if (type == "HLTL1TSeed" or type == "HLTLevel1GTSeed" or type == "HLTLevel1Activity" or
321  type == "HLTLevel1Pattern") {
322  // there might be more L1T seed filters in sequence
323  // keep looking and store the index of the last one
324  histograms.hltIndices[i].index_l1_seed = j;
325  } else if (type == "HLTPrescaler") {
326  // there should be only one prescaler in a path, and it should follow all L1T seed filters
327  histograms.hltIndices[i].index_prescale = j;
328  break;
329  }
330  }
331  }
332  }
333 
334  // book the rate histograms for the HLT datasets
335  booker.setCurrentFolder(m_dqm_path + "/Datasets");
336  for (unsigned int i = 0; i < datasetNames.size(); ++i)
337  histograms.dataset_counts[i] =
339 
340  // book the rate histograms for the HLT streams
341  booker.setCurrentFolder(m_dqm_path + "/Streams");
342  auto const &streamNames = histograms.hltConfig.streamNames();
343  for (unsigned int i = 0; i < streamNames.size(); ++i)
344  histograms.stream_counts[i] =
345  booker.book1D(streamNames[i], streamNames[i], m_lumisections_range + 1, -0.5, m_lumisections_range + 0.5);
346  }
347 }
348 
350  edm::EventSetup const &setup,
351  RunBasedHistograms const &histograms) const {
352  unsigned int lumisection = event.luminosityBlock();
353 
354  // monitor the overall event count and event types rates
355  histograms.events_processed->Fill(lumisection);
356  if (histograms.tcds_counts[event.experimentType()])
357  histograms.tcds_counts[event.experimentType()]->Fill(lumisection);
358 
359  // monitor the rates of L1T triggers
360  auto const &bxvector = event.get(m_l1t_results);
361  if (not bxvector.isEmpty(0)) {
362  auto const &results = bxvector.at(0, 0);
363  for (unsigned int i = 0; i < GlobalAlgBlk::maxPhysicsTriggers; ++i)
364  if (results.getAlgoDecisionFinal(i))
365  if (histograms.l1t_counts[i])
366  histograms.l1t_counts[i]->Fill(lumisection);
367  }
368 
369  // monitor the rates of HLT triggers, datasets and streams
370  if (histograms.hltConfig.inited()) {
371  auto const &hltResults = event.get(m_hlt_results);
372  if (hltResults.size() != histograms.hltIndices.size()) {
373  edm::LogError("TriggerRatesMonitor")
374  << "This should never happen: the number of HLT paths has changed since the beginning of the run"
375  << " (from " << histograms.hltIndices.size() << " to " << hltResults.size() << ").\n"
376  << "Histograms for rates of HLT paths, datasets and streams will not be filled for this event.";
377  return;
378  }
379 
380  for (unsigned int d = 0; d < histograms.datasets.size(); ++d) {
381  for (unsigned int i : histograms.datasets[d])
382  if (hltResults[i].accept()) {
383  histograms.dataset_counts[d]->Fill(lumisection);
384  // ensure each dataset is incremented only once per event
385  break;
386  }
387  for (unsigned int i = 0; i < histograms.datasets[d].size(); ++i) {
388  unsigned int const index = histograms.datasets[d][i];
390 
391  if (path.index() > histograms.hltIndices[index].index_l1_seed)
392  histograms.hlt_by_dataset_counts[d][i].pass_l1_seed->Fill(lumisection);
393  if (path.index() > histograms.hltIndices[index].index_prescale)
394  histograms.hlt_by_dataset_counts[d][i].pass_prescale->Fill(lumisection);
395  if (path.accept())
396  histograms.hlt_by_dataset_counts[d][i].accept->Fill(lumisection);
397  else if (path.error())
398  histograms.hlt_by_dataset_counts[d][i].error->Fill(lumisection);
399  else
400  histograms.hlt_by_dataset_counts[d][i].reject->Fill(lumisection);
401  }
402  }
403 
404  for (unsigned int i = 0; i < histograms.streams.size(); ++i)
405  for (unsigned int j : histograms.streams[i])
406  if (hltResults[j].accept()) {
407  histograms.stream_counts[i]->Fill(lumisection);
408  // ensure each stream is incremented only once per event
409  break;
410  }
411  }
412 }
413 
414 // define this as a plugin
void dqmBeginRun(edm::Run const &, edm::EventSetup const &, RunBasedHistograms &) const override
const std::string m_dqm_path
const edm::EDGetTokenT< GlobalAlgBlkBxCollection > m_l1t_results
dqm::impl::MonitorElement MonitorElement
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:36
const edm::EDGetTokenT< edm::TriggerResults > m_hlt_results
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: config.py:1
Log< level::Error, false > LogError
const uint32_t m_lumisections_range
bool accept(const edm::Event &event, const edm::TriggerResults &triggerTable, const std::string &triggerPath)
Definition: TopDQMHelpers.h:31
void bookHistograms(DQMStore::IBooker &, edm::Run const &, edm::EventSetup const &, RunBasedHistograms &) const override
static constexpr const char *const s_tcds_trigger_types[]
char const * label
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
def unique(seq, keepstr=True)
Definition: tier0.py:24
const edm::ESGetToken< L1TUtmTriggerMenu, L1TUtmTriggerMenuRcd > m_l1tMenuToken
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
d
Definition: ztail.py:151
void dqmAnalyze(edm::Event const &, edm::EventSetup const &, RunBasedHistograms const &) const override
void add(std::string const &label, ParameterSetDescription const &psetDescription)
TriggerRatesMonitor(edm::ParameterSet const &)
results
Definition: mysort.py:8
static constexpr unsigned int maxPhysicsTriggers
Definition: GlobalAlgBlk.h:52
MonitorElement * book1D(TString const &name, TString const &title, int const nchX, double const lowX, double const highX, FUNC onbooking=NOOP())
Definition: DQMStore.h:98
~TriggerRatesMonitor() override=default
Definition: event.py:1
Definition: Run.h:45
void labelsForToken(EDGetToken iToken, Labels &oLabels) const
#define LogDebug(id)