artdaq  v2_02_03
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
EventBuilderCore.cc
1 #include "canvas/Utilities/Exception.h"
2 #include "art/Framework/Art/artapp.h"
3 
4 #include "artdaq-core/Core/SimpleQueueReader.hh"
5 #include "artdaq-core/Utilities/ExceptionHandler.hh"
6 
7 #include "artdaq/Application/EventBuilderCore.hh"
8 #include "artdaq/TransferPlugins/TransferInterface.hh"
9 #include "artdaq/DAQdata/Globals.hh"
10 #include "artdaq/DAQrate/EventStore.hh"
11 #define TRACE_NAME "EventBuilderCore"
12 
13 #include <iomanip>
14 
15 const std::string artdaq::EventBuilderCore::INPUT_FRAGMENTS_STAT_KEY("EventBuilderCoreInputFragments");
16 const std::string artdaq::EventBuilderCore::INPUT_WAIT_STAT_KEY("EventBuilderCoreInputWaitTime");
17 const std::string artdaq::EventBuilderCore::STORE_EVENT_WAIT_STAT_KEY("EventBuilderCoreStoreEventWaitTime");
18 
19 artdaq::EventBuilderCore::EventBuilderCore(int rank, std::string name)
20  : name_(name)
21  , art_initialized_(false)
22  , stop_requested_(false)
23  , pause_requested_(false)
24  , run_is_paused_(false)
25  , processing_fragments_(false)
26 {
27  TLOG_DEBUG(name_) << "Constructor" << TLOG_ENDL;
31  my_rank = rank;
32  metricMan = &metricMan_;
33 }
34 
36 {
37  TLOG_DEBUG(name_) << "Destructor" << TLOG_ENDL;
38 }
39 
40 void artdaq::EventBuilderCore::initializeEventStore(fhicl::ParameterSet pset)
41 {
42  if (use_art_)
43  {
44  artdaq::EventStore::ART_CFGSTRING_FCN* reader = &artapp_string_config;
45  TRACE(36, "Creating EventStore and Starting art thread");
46  event_store_ptr_.reset(new artdaq::EventStore(pset, expected_fragments_per_event_, 1,
47  init_string_, reader));
48  TRACE(36, "Done Creating EventStore");
49  art_initialized_ = true;
50  }
51  else
52  {
53  const char* dummyArgs[1]{ "SimpleQueueReader" };
54  artdaq::EventStore::ART_CMDLINE_FCN* reader = &artdaq::simpleQueueReaderApp;
55  event_store_ptr_.reset(new artdaq::EventStore(pset, expected_fragments_per_event_, 1,
56  1, const_cast<char**>(dummyArgs), reader));
57  }
58 }
59 
60 bool artdaq::EventBuilderCore::initialize(fhicl::ParameterSet const& pset)
61 {
62  init_string_ = pset.to_string();
63  TLOG_DEBUG(name_) << "initialize method called with DAQ "
64  << "ParameterSet = \"" << init_string_ << "\"." << TLOG_ENDL;
65 
66  // pull out the relevant parts of the ParameterSet
67  fhicl::ParameterSet daq_pset;
68  try
69  {
70  daq_pset = pset.get<fhicl::ParameterSet>("daq");
71  }
72  catch (...)
73  {
74  TLOG_ERROR(name_)
75  << "Unable to find the DAQ parameters in the initialization "
76  << "ParameterSet: \"" + pset.to_string() + "\"." << TLOG_ENDL;
77  return false;
78  }
79  fhicl::ParameterSet evb_pset;
80  try
81  {
82  evb_pset = daq_pset.get<fhicl::ParameterSet>("event_builder");
83  data_pset_ = evb_pset;
84  }
85  catch (...)
86  {
87  TLOG_ERROR(name_)
88  << "Unable to find the event_builder parameters in the DAQ "
89  << "initialization ParameterSet: \"" + daq_pset.to_string() + "\"." << TLOG_ENDL;
90  return false;
91  }
92  try
93  {
94  expected_fragments_per_event_ =
95  evb_pset.get<size_t>("expected_fragments_per_event");
96  }
97  catch (...)
98  {
99  TLOG_ERROR(name_)
100  << "The expected_fragments_per_event parameter was not specified "
101  << "in the event_builder initialization PSet: \"" << pset.to_string()
102  << "\"." << TLOG_ENDL;
103  return false;
104  }
105 
106  // other parameters
107  try { use_art_ = evb_pset.get<bool>("use_art"); }
108  catch (...)
109  {
110  TLOG_ERROR(name_)
111  << "The use_art parameter was not specified "
112  << "in the event_builder initialization PSet: \""
113  << evb_pset.to_string() << "\"." << TLOG_ENDL;
114  return false;
115  }
116  inrun_recv_timeout_usec_ = evb_pset.get<size_t>("inrun_recv_timeout_usec", 100000);
117  endrun_recv_timeout_usec_ = evb_pset.get<size_t>("endrun_recv_timeout_usec", 20000000);
118  pause_recv_timeout_usec_ = evb_pset.get<size_t>("pause_recv_timeout_usec", 3000000);
119  verbose_ = evb_pset.get<bool>("verbose", false);
120 
121  // fetch the monitoring parameters and create the MonitoredQuantity instances
122  statsHelper_.createCollectors(evb_pset, 100, 20.0, 60.0, INPUT_FRAGMENTS_STAT_KEY);
123 
124  // initialize the MetricManager and the names of our metrics
125  std::string metricsReportingInstanceName = "EventBuilder." +
126  boost::lexical_cast<std::string>(my_rank);
127  fhicl::ParameterSet metric_pset;
128  try
129  {
130  metric_pset = daq_pset.get<fhicl::ParameterSet>("metrics");
131  }
132  catch (...) {} // OK if there's no metrics table defined in the FHiCL
133 
134  if (metric_pset.is_empty())
135  {
136  TLOG_INFO(name_) << "No metric plugins appear to be defined" << TLOG_ENDL;
137  }
138  try
139  {
140  metricMan_.initialize(metric_pset, metricsReportingInstanceName);
141  }
142  catch (...)
143  {
144  ExceptionHandler(ExceptionHandlerRethrow::no,
145  "Error loading metrics in EventBuilderCore::initialize()");
146  }
147 
148  /* Once art has been initialized we can't tear it down or change it's
149  configuration. We'll keep track of when we have initialized it. Once it
150  has been initialized we need to verify that the configuration is the same
151  every subsequent time we transition through the init state. If the
152  config changes we have to throw up our hands and bail out.
153  */
154  if (art_initialized_ == false)
155  {
156  this->initializeEventStore(evb_pset);
157  fhicl::ParameterSet tmp = pset;
158  tmp.erase("daq");
159  previous_pset_ = tmp;
160  }
161  else
162  {
163  fhicl::ParameterSet tmp = pset;
164  tmp.erase("daq");
165  if (tmp != previous_pset_)
166  {
167  TLOG_ERROR(name_)
168  << "The art configuration can not be altered after art "
169  << "has been configured." << TLOG_ENDL;
170  return false;
171  }
172  }
173 
174  return true;
175 }
176 
178 {
179  stop_requested_.store(false);
180  pause_requested_.store(false);
181  run_is_paused_.store(false);
182  run_id_ = id;
183  eod_fragments_received_ = 0;
184  fragment_count_in_run_ = 0;
185  statsHelper_.resetStatistics();
186  flush_mutex_.lock();
187  metricMan_.do_start();
188  event_store_ptr_->startRun(id.run());
189 
190  logMessage_("Started run " + boost::lexical_cast<std::string>(run_id_.run()));
191  return true;
192 }
193 
195 {
196  logMessage_("Stopping run " + boost::lexical_cast<std::string>(run_id_.run()) +
197  ", subrun " + boost::lexical_cast<std::string>(event_store_ptr_->subrunID()));
198  bool endSucceeded;
199  int attemptsToEnd;
200 
201  // 21-Jun-2013, KAB - the stop_requested_ variable must be set
202  // before the flush lock so that the processFragments loop will
203  // exit (after the timeout), the lock will be released (in the
204  // processFragments method), and this method can continue.
205  stop_requested_.store(true);
206 
207  flush_mutex_.lock();
208  if (!run_is_paused_.load())
209  {
210  endSucceeded = false;
211  attemptsToEnd = 1;
212  endSucceeded = event_store_ptr_->endSubrun();
213  while (!endSucceeded && attemptsToEnd < 3)
214  {
215  ++attemptsToEnd;
216  TLOG_DEBUG(name_) << "Retrying EventStore::endSubrun()" << TLOG_ENDL;
217  endSucceeded = event_store_ptr_->endSubrun();
218  }
219  if (!endSucceeded)
220  {
221  TLOG_ERROR(name_)
222  << "EventStore::endSubrun in stop method failed after three tries." << TLOG_ENDL;
223  }
224  }
225 
226  endSucceeded = false;
227  attemptsToEnd = 1;
228  endSucceeded = event_store_ptr_->endRun();
229  while (!endSucceeded && attemptsToEnd < 3)
230  {
231  ++attemptsToEnd;
232  TLOG_DEBUG(name_) << "Retrying EventStore::endRun()" << TLOG_ENDL;
233  endSucceeded = event_store_ptr_->endRun();
234  }
235  if (!endSucceeded)
236  {
237  TLOG_ERROR(name_)
238  << "EventStore::endRun in stop method failed after three tries." << TLOG_ENDL;
239  }
240 
241  flush_mutex_.unlock();
242  run_is_paused_.store(false);
243  return true;
244 }
245 
247 {
248  logMessage_("Pausing run " + boost::lexical_cast<std::string>(run_id_.run()) +
249  ", subrun " + boost::lexical_cast<std::string>(event_store_ptr_->subrunID()));
250  pause_requested_.store(true);
251  flush_mutex_.lock();
252 
253  bool endSucceeded = false;
254  int attemptsToEnd = 1;
255  endSucceeded = event_store_ptr_->endSubrun();
256  while (!endSucceeded && attemptsToEnd < 3)
257  {
258  ++attemptsToEnd;
259  TLOG_DEBUG(name_) << "Retrying EventStore::endSubrun()" << TLOG_ENDL;
260  endSucceeded = event_store_ptr_->endSubrun();
261  }
262  if (!endSucceeded)
263  {
264  TLOG_ERROR(name_)
265  << "EventStore::endSubrun in pause method failed after three tries." << TLOG_ENDL;
266  }
267 
268  flush_mutex_.unlock();
269  run_is_paused_.store(true);
270  return true;
271 }
272 
274 {
275  logMessage_("Resuming run " + boost::lexical_cast<std::string>(run_id_.run()));
276  eod_fragments_received_ = 0;
277  pause_requested_.store(false);
278  flush_mutex_.lock();
279  metricMan_.do_start();
280  event_store_ptr_->startSubrun();
281  run_is_paused_.store(false);
282  return true;
283 }
284 
286 {
287  /* We don't care about flushing data here. The only way to transition to the
288  shutdown state is from a state where there is no data taking. All we have
289  to do is signal the art input module that we're done taking data so that
290  it can wrap up whatever it needs to do. */
291  int readerReturnValue;
292  bool endSucceeded = false;
293  int attemptsToEnd = 1;
294  TRACE(4, "EventBuilderCore::shutdown: Calling EventStore::endOfData");
295  endSucceeded = event_store_ptr_->endOfData(readerReturnValue);
296  while (!endSucceeded && attemptsToEnd < 3)
297  {
298  ++attemptsToEnd;
299  TRACE(4, "EventBuilderCore::shutdown: Retrying endOfData call");
300  TLOG_DEBUG(name_) << "Retrying EventStore::endOfData()" << TLOG_ENDL;
301  endSucceeded = event_store_ptr_->endOfData(readerReturnValue);
302  }
303  TRACE(4, "EventBuilderCore::shutdown: Shutting down MetricManager");
304  metricMan_.shutdown();
305  TRACE(4, "EventBuilderCore::shutdown: Complete");
306  return endSucceeded;
307 }
308 
309 bool artdaq::EventBuilderCore::soft_initialize(fhicl::ParameterSet const& pset)
310 {
311  TLOG_DEBUG(name_) << "soft_initialize method called with DAQ "
312  << "ParameterSet = \"" << pset.to_string()
313  << "\"." << TLOG_ENDL;
314  return true;
315 }
316 
317 bool artdaq::EventBuilderCore::reinitialize(fhicl::ParameterSet const& pset)
318 {
319  TLOG_DEBUG(name_) << "reinitialize method called with DAQ "
320  << "ParameterSet = \"" << pset.to_string()
321  << "\"." << TLOG_ENDL;
322  event_store_ptr_.reset(nullptr);
323  art_initialized_ = false;
324  return initialize(pset);
325 }
326 
328 {
329  processing_fragments_.store(true);
330  bool process_fragments = true;
331  int senderSlot;
332  detail::FragCounter fragments_received;
333  detail::FragCounter fragments_sent;
334 
335  receiver_ptr_.reset(new artdaq::DataReceiverManager(data_pset_));
336  receiver_ptr_->start_threads();
337 
338  //MPI_Barrier(local_group_comm_);
339 
340  TLOG_DEBUG(name_) << "Waiting for first fragment." << TLOG_ENDL;
341  artdaq::MonitoredQuantityStats::TIME_POINT_T startTime;
342  while (process_fragments)
343  {
344  size_t recvTimeout = inrun_recv_timeout_usec_;
345  if (stop_requested_.load()) { recvTimeout = endrun_recv_timeout_usec_; }
346  else if (pause_requested_.load()) { recvTimeout = pause_recv_timeout_usec_; }
347  startTime = artdaq::MonitoredQuantity::getCurrentTime();
348  artdaq::FragmentPtr pfragment = receiver_ptr_->recvFragment(senderSlot, recvTimeout);
349  statsHelper_.addSample(INPUT_WAIT_STAT_KEY,
350  (artdaq::MonitoredQuantity::getCurrentTime() - startTime));
351  if (senderSlot == artdaq::TransferInterface::RECV_TIMEOUT)
352  {
353  if (stop_requested_.load() &&
354  recvTimeout == endrun_recv_timeout_usec_)
355  {
356  TLOG_WARNING(name_)
357  << "Timeout occurred in attempt to receive data, but as a stop has been requested, will forcibly end the run." << TLOG_ENDL;
358  event_store_ptr_->flushData();
359  flush_mutex_.unlock();
360  process_fragments = false;
361  }
362  else if (pause_requested_.load() &&
363  recvTimeout == pause_recv_timeout_usec_)
364  {
365  TLOG_WARNING(name_)
366  << "Timeout occurred in attempt to receive data, but as a pause has been requested, will forcibly pause the run." << TLOG_ENDL;
367  event_store_ptr_->flushData();
368  flush_mutex_.unlock();
369  process_fragments = false;
370  }
371  continue;
372  }
373  else if (!pfragment)
374  {
375  TLOG_ERROR(name_) << "Received invalid fragment from " << senderSlot << ". This is usually the case when a timeout has occurred, but sender was not set to RECV_TIMEOUT as expected." << TLOG_ENDL;
376  continue;
377  }
378  if (!receiver_ptr_->enabled_sources().count(senderSlot))
379  {
380  TLOG_ERROR(name_)
381  << "Invalid senderSlot received from recvFragment: "
382  << senderSlot << TLOG_ENDL;
383  continue;
384  }
385  fragments_received.incSlot(senderSlot);
386  if (artdaq::Fragment::isSystemFragmentType(pfragment->type()))
387  {
388  TLOG_DEBUG(name_)
389  << "Sender slot = " << senderSlot
390  << ", fragment type = " << ((int)pfragment->type())
391  << ", sequence ID = " << pfragment->sequenceID() << TLOG_ENDL;
392  }
393 
394  ++fragment_count_in_run_;
395  TRACE(18, "process_fragments %lu=fragment_count_in_run_ %lu=pfragment->size()"
396  , fragment_count_in_run_, pfragment->size());
397  statsHelper_.addSample(INPUT_FRAGMENTS_STAT_KEY, pfragment->size());
398  if (statsHelper_.readyToReport(fragment_count_in_run_))
399  {
400  std::string statString = buildStatisticsString_();
401  logMessage_(statString);
402  logMessage_("Received fragment " +
403  boost::lexical_cast<std::string>(fragment_count_in_run_) +
404  " with sequence ID " +
405  boost::lexical_cast<std::string>(pfragment->sequenceID()) +
406  " (run " +
407  boost::lexical_cast<std::string>(run_id_.run()) +
408  ", subrun " +
409  boost::lexical_cast<std::string>(event_store_ptr_->subrunID()) +
410  ").");
411  }
412  if (statsHelper_.statsRollingWindowHasMoved())
413  {
414  sendMetrics_();
415  event_store_ptr_->sendMetrics();
416  }
417 
418  startTime = artdaq::MonitoredQuantity::getCurrentTime();
419  if (pfragment->type() != artdaq::Fragment::EndOfDataFragmentType)
420  {
421  artdaq::FragmentPtr rejectedFragment;
422  auto seqId = pfragment->sequenceID();
423  auto fragId = pfragment->fragmentID();
424  bool try_again = true;
425  while (try_again)
426  {
427  auto ret = event_store_ptr_->insert(std::move(pfragment), rejectedFragment);
429  {
430  receiver_ptr_->unsuppressAll();
431  try_again = false;
432  }
434  {
435  try_again = false;
436  }
437  else if (stop_requested_.load())
438  {
439  try_again = false;
440  flush_mutex_.unlock();
441  process_fragments = false;
442  receiver_ptr_->reject_fragment(senderSlot, std::move(rejectedFragment));
443  TLOG_WARNING(name_)
444  << "Unable to process fragment " << fragId
445  << " in event " << seqId
446  << " because of back-pressure - forcibly ending the run." << TLOG_ENDL;
447  }
448  else if (pause_requested_.load())
449  {
450  try_again = false;
451  flush_mutex_.unlock();
452  process_fragments = false;
453  receiver_ptr_->reject_fragment(senderSlot, std::move(rejectedFragment));
454  TLOG_WARNING(name_)
455  << "Unable to process fragment " << fragId
456  << " in event " << seqId
457  << " because of back-pressure - forcibly pausing the run." << TLOG_ENDL;
458  }
460  {
461  pfragment = std::move(rejectedFragment);
462  TLOG_WARNING(name_)
463  << "Unable to process fragment " << fragId
464  << " in event " << seqId
465  << " because of back-pressure from art - retrying..." << TLOG_ENDL;
466  }
467  else
468  {
469  try_again = false;
470  receiver_ptr_->reject_fragment(senderSlot, std::move(rejectedFragment));
471  TLOG_WARNING(name_)
472  << "Unable to process fragment " << fragId
473  << " in event " << seqId
474  << " because the EventStore has reached the maximum number of incomplete events." << std::endl
475  << " Will retry when the EventStore is ready for new events." << TLOG_ENDL;
476  }
477  }
478  }
479  else
480  {
481  eod_fragments_received_++;
482  /* We count the EOD fragment as a fragment received but the SHandles class
483  does not count it as a fragment sent which means we need to add one to
484  the total expected fragments. */
485  fragments_sent.setSlot(senderSlot, *pfragment->dataBegin() + 1);
486  }
487  statsHelper_.addSample(STORE_EVENT_WAIT_STAT_KEY,
488  artdaq::MonitoredQuantity::getCurrentTime() - startTime);
489 
490  /* If we've received EOD fragments from all of the BoardReaders we can
491  verify that we've also received every fragment that they have sent. If
492  all fragments are accounted for we can flush the EventStore, unlock the
493  mutex and exit out of this thread.*/
494  if (eod_fragments_received_ == receiver_ptr_->enabled_sources().size())
495  {
496  bool fragmentsOutstanding = false;
497  for (auto& i : receiver_ptr_->enabled_sources())
498  {
499  if (fragments_received[i] != fragments_sent[i])
500  {
501  fragmentsOutstanding = true;
502  break;
503  }
504  }
505 
506  if (!fragmentsOutstanding)
507  {
508  event_store_ptr_->flushData();
509  flush_mutex_.unlock();
510  process_fragments = false;
511  }
512  else
513  {
514  TLOG_WARNING(name_) << "All EndOfData fragments received but more data expected" << TLOG_ENDL;
515  }
516  }
517  }
518 
519  // 11-May-2015, KAB: call MetricManager::do_stop whenever we exit the
520  // processing fragments loop so that metrics correctly go to zero when
521  // there is no data flowing
522  metricMan_.do_stop();
523 
524  receiver_ptr_.reset(nullptr);
525  processing_fragments_.store(false);
526  return 0;
527 }
528 
529 std::string artdaq::EventBuilderCore::report(std::string const& which) const
530 {
531  if (which == "incomplete_event_count")
532  {
533  if (event_store_ptr_ != nullptr)
534  {
535  return boost::lexical_cast<std::string>(event_store_ptr_->incompleteEventCount());
536  }
537  else
538  {
539  return "-1";
540  }
541  }
542  if (which == "event_count")
543  {
544  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
545  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
546  if (mqPtr.get() != 0)
547  {
548  return boost::lexical_cast<std::string>(mqPtr->getFullSampleCount());
549  }
550  else
551  {
552  return "-1";
553  }
554  }
555 
556  if (which == "run_duration")
557  {
558  // 03-Feb-2017, ELF: if we are not processing fragments, return 0 (not adding data members)
559  double duration = 0;
560  if (processing_fragments_.load())
561  {
562  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
563  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
564  if (mqPtr.get() != 0)
565  {
566  duration = mqPtr->getFullDuration();
567  }
568  }
569  std::ostringstream oss;
570  oss << std::fixed << std::setprecision(1) << duration;
571  return oss.str();
572  }
573 
574  // lots of cool stuff that we can do here
575  // - report on the number of fragments received and the number
576  // of events built (in the current or previous run
577  // - report on the number of incomplete events in the EventStore
578  // (if running)
579  std::string tmpString = name_ + " run number = ";
580  tmpString.append(boost::lexical_cast<std::string>(run_id_.run()));
581  tmpString.append(". Command \"" + which + "\" is not currently supported.");
582  return tmpString;
583 }
584 
585 
586 std::string artdaq::EventBuilderCore::buildStatisticsString_()
587 {
588  std::ostringstream oss;
589  double eventCount = 1.0;
590  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
591  getMonitoredQuantity(INPUT_FRAGMENTS_STAT_KEY);
592  if (mqPtr.get() != 0)
593  {
594  //mqPtr->waitUntilAccumulatorsHaveBeenFlushed(3.0);
595  artdaq::MonitoredQuantityStats stats;
596  mqPtr->getStats(stats);
597  oss << "Input statistics: "
598  << stats.recentSampleCount << " fragments received at "
599  << stats.recentSampleRate << " fragments/sec, data rate = "
600  << (stats.recentValueRate * sizeof(artdaq::RawDataType)
601  / 1024.0 / 1024.0) << " MB/sec, monitor window = "
602  << stats.recentDuration << " sec, min::max fragment size = "
603  << (stats.recentValueMin * sizeof(artdaq::RawDataType)
604  / 1024.0 / 1024.0)
605  << "::"
606  << (stats.recentValueMax * sizeof(artdaq::RawDataType)
607  / 1024.0 / 1024.0)
608  << " MB" << std::endl;
609  eventCount = std::max(double(stats.recentSampleCount), 1.0);
610  oss << "Average times per fragment: ";
611  if (stats.recentSampleRate > 0.0)
612  {
613  oss << " elapsed time = "
614  << (1.0 / stats.recentSampleRate) << " sec";
615  }
616  }
617 
618  // 13-Jan-2015, KAB - Just a reminder that using "fragmentCount" in the
619  // denominator of the calculations below is important so that the sum
620  // of the different "average" times adds up to the overall average time
621  // per fragment. In some (but not all) cases, using recentValueAverage()
622  // would be equivalent.
623 
624  mqPtr = artdaq::StatisticsCollection::getInstance().
625  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
626  if (mqPtr.get() != 0)
627  {
628  oss << ", input wait time = "
629  << (mqPtr->getRecentValueSum() / eventCount) << " sec";
630  }
631 
632  mqPtr = artdaq::StatisticsCollection::getInstance().
633  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
634  if (mqPtr.get() != 0)
635  {
636  oss << ", event store wait time = "
637  << (mqPtr->getRecentValueSum() / eventCount) << " sec";
638  }
639 
640  return oss.str();
641 }
642 
643 void artdaq::EventBuilderCore::sendMetrics_()
644 {
645  //TLOG_DEBUG("EventBuilderCore") << "Sending metrics " << TLOG_ENDL;
646  double fragmentCount = 1.0;
647  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
648  getMonitoredQuantity(INPUT_FRAGMENTS_STAT_KEY);
649  if (mqPtr.get() != 0)
650  {
651  artdaq::MonitoredQuantityStats stats;
652  mqPtr->getStats(stats);
653  fragmentCount = std::max(double(stats.recentSampleCount), 1.0);
654  metricMan_.sendMetric("Fragment Count",
655  static_cast<unsigned long>(stats.fullSampleCount),
656  "fragments", 1);
657  metricMan_.sendMetric("Fragment Rate",
658  stats.recentSampleRate, "fragments/sec", 1);
659  metricMan_.sendMetric("Average Fragment Size",
660  (stats.recentValueAverage * sizeof(artdaq::RawDataType)
661  ), "bytes/fragment", 2);
662  metricMan_.sendMetric("Data Rate",
663  (stats.recentValueRate * sizeof(artdaq::RawDataType)
664  ), "bytes/sec", 2);
665  }
666 
667  // 13-Jan-2015, KAB - Just a reminder that using "fragmentCount" in the
668  // denominator of the calculations below is important so that the sum
669  // of the different "average" times adds up to the overall average time
670  // per fragment. In some (but not all) cases, using recentValueAverage()
671  // would be equivalent.
672 
673  mqPtr = artdaq::StatisticsCollection::getInstance().
674  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
675  if (mqPtr.get() != 0)
676  {
677  metricMan_.sendMetric("Average Input Wait Time",
678  (mqPtr->getRecentValueSum() / fragmentCount),
679  "seconds/fragment", 3);
680  }
681 
682  mqPtr = artdaq::StatisticsCollection::getInstance().
683  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
684  if (mqPtr.get() != 0)
685  {
686  metricMan_.sendMetric("Avg Event Store Wait Time",
687  (mqPtr->getRecentValueSum() / fragmentCount),
688  "seconds/fragment", 3);
689  }
690 }
691 
692 void artdaq::EventBuilderCore::logMessage_(std::string const& text)
693 {
694  if (verbose_)
695  {
696  TLOG_INFO(name_) << text << TLOG_ENDL;
697  }
698  else
699  {
700  TLOG_DEBUG(name_) << text << TLOG_ENDL;
701  }
702 }
std::string report(std::string const &which) const
Send a report on a given run-time quantity.
void addMonitoredQuantityName(std::string const &statKey)
Add a MonitoredQuantity name to the list.
static const std::string INPUT_FRAGMENTS_STAT_KEY
Key for the Input Fragments MonitoredQuantity.
bool resume()
Resumes the EventBuilderCore.
Keep track of the count of Fragments received from a set of sources.
Definition: FragCounter.hh:20
The Fragment was successfully inserted.
static const int RECV_TIMEOUT
Value to be returned upon receive timeout. Because receivers otherwise return rank, this is also the limit on the number of ranks that artdaq currently supports.
bool initialize(fhicl::ParameterSet const &pset)
Processes the initialize request.
static const std::string STORE_EVENT_WAIT_STAT_KEY
Key for the Store Event Wait MonitoredQuantity.
static const std::string INPUT_WAIT_STAT_KEY
Key for the Input Wait MonitoredQuantity.
void setSlot(size_t slot, size_t val)
Set the given slot to the given value.
Definition: FragCounter.hh:110
EventBuilderCore(int rank, std::string name)
EventBuilderCore Constructor.
size_t process_fragments()
The main loop of the EventBuilderCore. Receives Fragment objects from DataReceiverManager and enqueue...
The EventStore class collects Fragment objects, until it receives a complete event, at which point the event is handed over to the art thread.
Definition: EventStore.hh:48
void incSlot(size_t slot)
Increment the given slot by one.
Definition: FragCounter.hh:93
int( ART_CMDLINE_FCN)(int, char **)
An art function that accepts standard C main arguments.
Definition: EventStore.hh:55
Receives Fragment objects from one or more DataSenderManager instances using TransferInterface plugin...
The EventStore is full, but the Fragment was accepted as it is for an already-open event...
bool start(art::RunID id)
Start the EventBuilderCore.
bool stop()
Stops the EventBuilderCore.
bool pause()
Pauses the EventBuilderCore.
int( ART_CFGSTRING_FCN)(const std::string &)
An art function that accepts a fhicl::ParameterSet as a string.
Definition: EventStore.hh:61
bool reinitialize(fhicl::ParameterSet const &pset)
Reinitializes the EventBuilderCore.
bool shutdown()
Shuts Down the EventBuilderCore.
bool soft_initialize(fhicl::ParameterSet const &pset)
Soft-Initializes the EventBuilderCore. No-Op.
The Fragment was rejected, because the RawEventQueue is full.