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