artdaq  v2_03_02
 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  event_store_ptr_->setRequestMode(detail::RequestMessageMode::EndOfRun);
483  /* We count the EOD fragment as a fragment received but the SHandles class
484  does not count it as a fragment sent which means we need to add one to
485  the total expected fragments. */
486  fragments_sent.setSlot(senderSlot, *pfragment->dataBegin() + 1);
487  }
488  statsHelper_.addSample(STORE_EVENT_WAIT_STAT_KEY,
489  artdaq::MonitoredQuantity::getCurrentTime() - startTime);
490 
491  /* If we've received EOD fragments from all of the BoardReaders we can
492  verify that we've also received every fragment that they have sent. If
493  all fragments are accounted for we can flush the EventStore, unlock the
494  mutex and exit out of this thread.*/
495  if (eod_fragments_received_ == receiver_ptr_->enabled_sources().size())
496  {
497  bool fragmentsOutstanding = false;
498  for (auto& i : receiver_ptr_->enabled_sources())
499  {
500  if (fragments_received[i] != fragments_sent[i])
501  {
502  fragmentsOutstanding = true;
503  break;
504  }
505  }
506 
507  if (!fragmentsOutstanding)
508  {
509  event_store_ptr_->flushData();
510  flush_mutex_.unlock();
511  process_fragments = false;
512  }
513  else
514  {
515  TLOG_WARNING(name_) << "All EndOfData fragments received but more data expected" << TLOG_ENDL;
516  }
517  }
518  }
519 
520  // 11-May-2015, KAB: call MetricManager::do_stop whenever we exit the
521  // processing fragments loop so that metrics correctly go to zero when
522  // there is no data flowing
523  metricMan_.do_stop();
524 
525  receiver_ptr_.reset(nullptr);
526  processing_fragments_.store(false);
527  return 0;
528 }
529 
530 std::string artdaq::EventBuilderCore::report(std::string const& which) const
531 {
532  if (which == "incomplete_event_count")
533  {
534  if (event_store_ptr_ != nullptr)
535  {
536  return boost::lexical_cast<std::string>(event_store_ptr_->incompleteEventCount());
537  }
538  else
539  {
540  return "-1";
541  }
542  }
543  if (which == "event_count")
544  {
545  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
546  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
547  if (mqPtr.get() != 0)
548  {
549  return boost::lexical_cast<std::string>(mqPtr->getFullSampleCount());
550  }
551  else
552  {
553  return "-1";
554  }
555  }
556 
557  if (which == "run_duration")
558  {
559  // 03-Feb-2017, ELF: if we are not processing fragments, return 0 (not adding data members)
560  double duration = 0;
561  if (processing_fragments_.load())
562  {
563  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
564  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
565  if (mqPtr.get() != 0)
566  {
567  duration = mqPtr->getFullDuration();
568  }
569  }
570  std::ostringstream oss;
571  oss << std::fixed << std::setprecision(1) << duration;
572  return oss.str();
573  }
574 
575  // lots of cool stuff that we can do here
576  // - report on the number of fragments received and the number
577  // of events built (in the current or previous run
578  // - report on the number of incomplete events in the EventStore
579  // (if running)
580  std::string tmpString = name_ + " run number = ";
581  tmpString.append(boost::lexical_cast<std::string>(run_id_.run()));
582  tmpString.append(". Command \"" + which + "\" is not currently supported.");
583  return tmpString;
584 }
585 
586 
587 std::string artdaq::EventBuilderCore::buildStatisticsString_()
588 {
589  std::ostringstream oss;
590  double eventCount = 1.0;
591  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
592  getMonitoredQuantity(INPUT_FRAGMENTS_STAT_KEY);
593  if (mqPtr.get() != 0)
594  {
595  //mqPtr->waitUntilAccumulatorsHaveBeenFlushed(3.0);
596  artdaq::MonitoredQuantityStats stats;
597  mqPtr->getStats(stats);
598  oss << "Input statistics: "
599  << stats.recentSampleCount << " fragments received at "
600  << stats.recentSampleRate << " fragments/sec, data rate = "
601  << (stats.recentValueRate * sizeof(artdaq::RawDataType)
602  / 1024.0 / 1024.0) << " MB/sec, monitor window = "
603  << stats.recentDuration << " sec, min::max fragment size = "
604  << (stats.recentValueMin * sizeof(artdaq::RawDataType)
605  / 1024.0 / 1024.0)
606  << "::"
607  << (stats.recentValueMax * sizeof(artdaq::RawDataType)
608  / 1024.0 / 1024.0)
609  << " MB" << std::endl;
610  eventCount = std::max(double(stats.recentSampleCount), 1.0);
611  oss << "Average times per fragment: ";
612  if (stats.recentSampleRate > 0.0)
613  {
614  oss << " elapsed time = "
615  << (1.0 / stats.recentSampleRate) << " sec";
616  }
617  }
618 
619  // 13-Jan-2015, KAB - Just a reminder that using "fragmentCount" in the
620  // denominator of the calculations below is important so that the sum
621  // of the different "average" times adds up to the overall average time
622  // per fragment. In some (but not all) cases, using recentValueAverage()
623  // would be equivalent.
624 
625  mqPtr = artdaq::StatisticsCollection::getInstance().
626  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
627  if (mqPtr.get() != 0)
628  {
629  oss << ", input wait time = "
630  << (mqPtr->getRecentValueSum() / eventCount) << " sec";
631  }
632 
633  mqPtr = artdaq::StatisticsCollection::getInstance().
634  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
635  if (mqPtr.get() != 0)
636  {
637  oss << ", event store wait time = "
638  << (mqPtr->getRecentValueSum() / eventCount) << " sec";
639  }
640 
641  return oss.str();
642 }
643 
644 void artdaq::EventBuilderCore::sendMetrics_()
645 {
646  //TLOG_DEBUG("EventBuilderCore") << "Sending metrics " << TLOG_ENDL;
647  double fragmentCount = 1.0;
648  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
649  getMonitoredQuantity(INPUT_FRAGMENTS_STAT_KEY);
650  if (mqPtr.get() != 0)
651  {
652  artdaq::MonitoredQuantityStats stats;
653  mqPtr->getStats(stats);
654  fragmentCount = std::max(double(stats.recentSampleCount), 1.0);
655  metricMan_.sendMetric("Fragment Count",
656  static_cast<unsigned long>(stats.fullSampleCount),
657  "fragments", 1);
658  metricMan_.sendMetric("Fragment Rate",
659  stats.recentSampleRate, "fragments/sec", 1);
660  metricMan_.sendMetric("Average Fragment Size",
661  (stats.recentValueAverage * sizeof(artdaq::RawDataType)
662  ), "bytes/fragment", 2);
663  metricMan_.sendMetric("Data Rate",
664  (stats.recentValueRate * sizeof(artdaq::RawDataType)
665  ), "bytes/sec", 2);
666  }
667 
668  // 13-Jan-2015, KAB - Just a reminder that using "fragmentCount" in the
669  // denominator of the calculations below is important so that the sum
670  // of the different "average" times adds up to the overall average time
671  // per fragment. In some (but not all) cases, using recentValueAverage()
672  // would be equivalent.
673 
674  mqPtr = artdaq::StatisticsCollection::getInstance().
675  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
676  if (mqPtr.get() != 0)
677  {
678  metricMan_.sendMetric("Average Input Wait Time",
679  (mqPtr->getRecentValueSum() / fragmentCount),
680  "seconds/fragment", 3);
681  }
682 
683  mqPtr = artdaq::StatisticsCollection::getInstance().
684  getMonitoredQuantity(STORE_EVENT_WAIT_STAT_KEY);
685  if (mqPtr.get() != 0)
686  {
687  metricMan_.sendMetric("Avg Event Store Wait Time",
688  (mqPtr->getRecentValueSum() / fragmentCount),
689  "seconds/fragment", 3);
690  }
691 }
692 
693 void artdaq::EventBuilderCore::logMessage_(std::string const& text)
694 {
695  if (verbose_)
696  {
697  TLOG_INFO(name_) << text << TLOG_ENDL;
698  }
699  else
700  {
701  TLOG_DEBUG(name_) << text << TLOG_ENDL;
702  }
703 }
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:49
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:56
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:62
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.