artdaq  v3_09_00
FragmentWatcher_module.cc
1 // Class: FragmentWatcher
3 // Module Type: analyzer
4 // File: FragmentWatcher_module.cc
5 // Description: Collects and reports statistics on missing and empty fragments
7 
8 #define TRACE_NAME (app_name + "_FragmentWatcher").c_str()
9 #include "artdaq/DAQdata/Globals.hh"
10 
11 #include "art/Framework/Core/EDAnalyzer.h"
12 #include "art/Framework/Core/ModuleMacros.h"
13 #include "art/Framework/Principal/Event.h"
14 #include "art/Framework/Principal/Handle.h"
15 
16 #include "artdaq-core/Data/ContainerFragment.hh"
17 #include "artdaq-core/Data/Fragment.hh"
18 
19 #include <bitset>
20 #include <iostream>
21 #include <map>
22 
23 namespace artdaq {
24 class FragmentWatcher;
25 }
26 
30 class artdaq::FragmentWatcher : public art::EDAnalyzer
31 {
32 public:
42  explicit FragmentWatcher(fhicl::ParameterSet const& pset);
46  ~FragmentWatcher() override;
47 
52  void analyze(art::Event const& evt) override;
53 
54 private:
55  FragmentWatcher(FragmentWatcher const&) = delete;
56  FragmentWatcher(FragmentWatcher&&) = delete;
57  FragmentWatcher& operator=(FragmentWatcher const&) = delete;
58  FragmentWatcher& operator=(FragmentWatcher&&) = delete;
59 
60  std::bitset<3> mode_bitset_;
61  int metrics_reporting_level_;
62 
63  int events_processed_;
64  int expected_number_of_fragments_;
65 
66  int events_with_missing_fragments_;
67  int events_with_empty_fragments_;
68 
69  int events_with_10pct_missing_fragments_;
70  int events_with_10pct_empty_fragments_;
71  int events_with_50pct_missing_fragments_;
72  int events_with_50pct_empty_fragments_;
73 
74  std::map<int, int> empty_fragments_by_fragmentID_;
75 
76  const int BASIC_COUNTS_MODE = 0;
77  const int FRACTIONAL_COUNTS_MODE = 1;
78  const int DETAILED_COUNTS_MODE = 2;
79 };
80 
81 artdaq::FragmentWatcher::FragmentWatcher(fhicl::ParameterSet const& pset)
82  : EDAnalyzer(pset), mode_bitset_(std::bitset<3>(pset.get<int>("mode_bitmask", 0x1))), metrics_reporting_level_(pset.get<int>("metrics_reporting_level", 1)), events_processed_(0), expected_number_of_fragments_(0), events_with_missing_fragments_(0), events_with_empty_fragments_(0), events_with_10pct_missing_fragments_(0), events_with_10pct_empty_fragments_(0), events_with_50pct_missing_fragments_(0), events_with_50pct_empty_fragments_(0)
83 {
84  fhicl::ParameterSet metric_pset;
85  try
86  {
87  metric_pset = pset.get<fhicl::ParameterSet>("metrics");
88  if (metricMan != nullptr)
89  {
90  metricMan->initialize(metric_pset, "FragmentWatcher.");
91  metricMan->do_start();
92  }
93  }
94  catch (...)
95  {
96  TLOG(TLVL_INFO) << "Unable to find the metrics parameters in the metrics "
97  << "ParameterSet: \"" + pset.to_string() + "\".";
98  }
99 }
100 
102 {
103  if (metricMan != nullptr)
104  {
105  metricMan->do_stop();
106  metricMan->shutdown();
107  }
108 }
109 
110 void artdaq::FragmentWatcher::analyze(art::Event const& evt)
111 {
112  events_processed_++;
113 
114  // get all the artdaq fragment collections in the event.
115  std::vector<art::Handle<std::vector<artdaq::Fragment> > > fragmentHandles;
116  evt.getManyByType(fragmentHandles);
117 
118  // count total fragments
119  int total_fragments_this_event = 0;
120  for (auto const& hndl : fragmentHandles)
121  {
122  total_fragments_this_event += hndl->size();
123  }
124 
125  // update the expected number of fragments, if needed
126  if (total_fragments_this_event > expected_number_of_fragments_) { expected_number_of_fragments_ = total_fragments_this_event; }
127 
128  // check if this event has fewer fragments than expected
129  int missing_fragments = expected_number_of_fragments_ - total_fragments_this_event;
130 
131  // check if this event has any Empty fragments
132  int empty_fragment_count_this_event = 0;
133  std::set<int> empty_fragmentID_list_this_event;
134  for (auto const& hndl : fragmentHandles)
135  {
136  std::string instance_name = hndl.provenance()->productInstanceName();
137  std::size_t found = instance_name.find("Empty");
138  if (found != std::string::npos)
139  {
140  empty_fragment_count_this_event += hndl->size();
141 
142  // track the number of empty fragments by fragment ID
143  for (auto const& fragment : *hndl)
144  {
145  int fragID = fragment.fragmentID();
146  if (empty_fragments_by_fragmentID_.count(fragID) == 0)
147  {
148  empty_fragments_by_fragmentID_[fragID] = 1;
149  }
150  else
151  {
152  empty_fragments_by_fragmentID_[fragID] += 1;
153  }
154  empty_fragmentID_list_this_event.insert(fragID);
155  }
156  }
157  }
158 
159  // provide diagnostic TRACE message(s) about this event
160  TLOG(TLVL_TRACE) << "Event " << evt.event() << ": total_fragments=" << total_fragments_this_event << ", missing_fragments="
161  << missing_fragments << ", empty_fragments=" << empty_fragment_count_this_event << " (" << events_processed_
162  << " events processed)";
163  if (!empty_fragmentID_list_this_event.empty())
164  {
165  std::ostringstream oss;
166  bool firstLoop = true;
167  for (auto const& fragID : empty_fragmentID_list_this_event)
168  {
169  if (!firstLoop) { oss << ", "; }
170  oss << fragID;
171  firstLoop = false;
172  }
173  TLOG(TLVL_WARNING) << "Event " << evt.event() << ": total_fragments=" << total_fragments_this_event
174  << ", fragmentIDs for empty_fragments: " << oss.str();
175  }
176 
177  // common metric reporting for multiple modes
178  if (metricMan != nullptr && (mode_bitset_.test(BASIC_COUNTS_MODE) || mode_bitset_.test(FRACTIONAL_COUNTS_MODE)))
179  {
180  metricMan->sendMetric("EventsProcessed", events_processed_, "events", metrics_reporting_level_,
181  artdaq::MetricMode::LastPoint);
182  }
183 
184  // metric reporting for the BASIC_COUNTS_MODE
185  if (metricMan != nullptr && mode_bitset_.test(BASIC_COUNTS_MODE))
186  {
187  if (missing_fragments > 0) { ++events_with_missing_fragments_; }
188  if (empty_fragment_count_this_event > 0) { ++events_with_empty_fragments_; }
189 
190  metricMan->sendMetric("EventsWithMissingFragments", events_with_missing_fragments_, "events",
191  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
192  metricMan->sendMetric("EventsWithEmptyFragments", events_with_empty_fragments_, "events",
193  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
194 
195  TLOG(TLVL_TRACE) << "Event " << evt.event() << ": events_with_missing_fragments=" << events_with_missing_fragments_
196  << ", events_with_empty_fragments=" << events_with_empty_fragments_;
197  }
198 
199  // metric reporting for the FRACTIONAL_COUNTS_MODE
200  if (metricMan != nullptr && mode_bitset_.test(FRACTIONAL_COUNTS_MODE))
201  {
202  if (((static_cast<double>(missing_fragments) * 100.0) / static_cast<double>(expected_number_of_fragments_)) >= 10.0)
203  {
204  ++events_with_10pct_missing_fragments_;
205  }
206  if (((static_cast<double>(missing_fragments) * 100.0) / static_cast<double>(expected_number_of_fragments_)) >= 50.0)
207  {
208  ++events_with_50pct_missing_fragments_;
209  }
210 
211  if (((static_cast<double>(empty_fragment_count_this_event) * 100.0) / static_cast<double>(expected_number_of_fragments_)) >= 10.0)
212  {
213  ++events_with_10pct_empty_fragments_;
214  }
215  if (((static_cast<double>(empty_fragment_count_this_event) * 100.0) / static_cast<double>(expected_number_of_fragments_)) >= 50.0)
216  {
217  ++events_with_50pct_empty_fragments_;
218  }
219 
220  metricMan->sendMetric("EventsWith10PctMissingFragments", events_with_10pct_missing_fragments_, "events",
221  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
222  metricMan->sendMetric("EventsWith50PctMissingFragments", events_with_50pct_missing_fragments_, "events",
223  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
224 
225  metricMan->sendMetric("EventsWith10PctEmptyFragments", events_with_10pct_empty_fragments_, "events",
226  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
227  metricMan->sendMetric("EventsWith50PctEmptyFragments", events_with_50pct_empty_fragments_, "events",
228  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
229 
230  TLOG(TLVL_TRACE) << "Event " << evt.event() << ": events_with_10pct_missing_fragments=" << events_with_10pct_missing_fragments_
231  << ", events_with_10pct_empty_fragments=" << events_with_10pct_empty_fragments_;
232  TLOG(TLVL_TRACE) << "Event " << evt.event() << ": events_with_50pct_missing_fragments=" << events_with_50pct_missing_fragments_
233  << ", events_with_50pct_empty_fragments=" << events_with_50pct_empty_fragments_;
234  }
235 
236  // initial reporting for the DETAILED_COUNTS_MODE
237  if (metricMan != nullptr && mode_bitset_.test(DETAILED_COUNTS_MODE))
238  {
239  // only send an update when the empty fragment count, by FragmentID, changed,
240  // as indicated by a non-zero number of empty fragments in this event
241  if (empty_fragment_count_this_event > 0)
242  {
243  std::ostringstream oss;
244  oss << "<eventbuilder_snapshot app_name=\"" << app_name << "\"><events_processed>" << events_processed_
245  << "</events_processed><empty_fragment_counts>";
246  for (auto const& mapIter : empty_fragments_by_fragmentID_)
247  {
248  oss << "<count fragment_id=" << mapIter.first << ">" << mapIter.second << "</count>";
249  }
250  oss << "</empty_fragment_counts></eventbuilder_snapshot>";
251 
252  metricMan->sendMetric("EmptyFragmentSnapshot", oss.str(), "xml_string",
253  metrics_reporting_level_, artdaq::MetricMode::LastPoint);
254  }
255  }
256 
257 #if 0
258 =====================================================
259 
260 event_builder_snapshot : {
261  name: "EventBuilder5"
262  timestamp: "20190408T124433"
263  events_built: 105
264 
265  sender_list: [ "felix501", "felix501", "ssp101", "ssp102" ]
266  valid_fragment_counts: [ 105, 105, 102, 104 ]
267  empty_fragment_counts: [ 0, 0, 2, 0 ]
268  missing_fragment_counts: [ 0, 0, 1, 1 ]
269 }
270 
271 =====================================================
272 
273 <event_builder_snapshot name="EventBuilder5">
274  <timestamp>20190408T124433</timestamp>
275  <events_built>105</events_built
276 
277  <sender_list>
278  <sender index=0>felix501</sender>
279  <sender index=1>felix502</sender>
280  <sender index=2>ssp101</sender>
281  <sender index=3>ssp102</sender>
282  </sender_list>
283 
284  <valid_fragment_counts>
285  <count index=0>105</count>
286  <count index=1>105</count>
287  <count index=2>102</count>
288  <count index=3>104</count>
289  </valid_fragment_counts>
290 
291  <empty_fragment_counts>
292  <count index=2>2</count>
293  </empty_fragment_counts>
294 
295  <missing_fragment_counts>
296  <count index=2>1</count>
297  <count index=3>1</count>
298  </missing_fragment_counts>
299 </event_builder_snapshot>
300 
301 =====================================================
302 #endif
303 }
304 
305 DEFINE_ART_MODULE(artdaq::FragmentWatcher)// NOLINT(performance-unnecessary-value-param)
FragmentWatcher(fhicl::ParameterSet const &pset)
FragmentWatcher Constructor.
An art::EDAnalyzer module which checks events for certain error conditions (missing fragments...
void analyze(art::Event const &evt) override
Analyze each event, using the configured mode bitmask.
~FragmentWatcher() override
Virtual Destructor. Shuts down MetricManager if one is present.