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