artdaq  v3_00_03
BoardReaderCore.cc
1 #define TRACE_NAME "BoardReaderCore"
2 #include "tracemf.h"
3 #include "artdaq/Application/TaskType.hh"
4 #include "artdaq/Application/BoardReaderCore.hh"
5 #include "artdaq-core/Data/Fragment.hh"
6 #include "artdaq-core/Utilities/ExceptionHandler.hh"
7 #include "artdaq/Application/makeCommandableFragmentGenerator.hh"
8 #include "canvas/Utilities/Exception.h"
9 #include "cetlib/exception.h"
10 #include <pthread.h>
11 #include <sched.h>
12 #include <algorithm>
13 
14 const std::string artdaq::BoardReaderCore::
15 FRAGMENTS_PROCESSED_STAT_KEY("BoardReaderCoreFragmentsProcessed");
16 const std::string artdaq::BoardReaderCore::
17 INPUT_WAIT_STAT_KEY("BoardReaderCoreInputWaitTime");
18 const std::string artdaq::BoardReaderCore::
19 BRSYNC_WAIT_STAT_KEY("BoardReaderCoreBRSyncWaitTime");
20 const std::string artdaq::BoardReaderCore::
21 OUTPUT_WAIT_STAT_KEY("BoardReaderCoreOutputWaitTime");
22 const std::string artdaq::BoardReaderCore::
23 FRAGMENTS_PER_READ_STAT_KEY("BoardReaderCoreFragmentsPerRead");
24 
25 std::unique_ptr<artdaq::DataSenderManager> artdaq::BoardReaderCore::sender_ptr_ = nullptr;
26 
28  parent_application_(parent_application)
29  /*, local_group_comm_(local_group_comm)*/
30  , generator_ptr_(nullptr)
31  , stop_requested_(false)
32  , pause_requested_(false)
33 {
34  TLOG_DEBUG(app_name) << "Constructor" << TLOG_ENDL;
40  metricMan = &metricMan_;
41 }
42 
44 {
45  TLOG_DEBUG(app_name) << "Destructor" << TLOG_ENDL;
46 }
47 
48 bool artdaq::BoardReaderCore::initialize(fhicl::ParameterSet const& pset, uint64_t, uint64_t)
49 {
50  TLOG_DEBUG(app_name) << "initialize method called with " << "ParameterSet = \"" << pset.to_string() << "\"." << TLOG_ENDL;
51 
52  // pull out the relevant parts of the ParameterSet
53  fhicl::ParameterSet daq_pset;
54  try
55  {
56  daq_pset = pset.get<fhicl::ParameterSet>("daq");
57  }
58  catch (...)
59  {
60  TLOG_ERROR(app_name)
61  << "Unable to find the DAQ parameters in the initialization "
62  << "ParameterSet: \"" + pset.to_string() + "\"." << TLOG_ENDL;
63  return false;
64  }
65  fhicl::ParameterSet fr_pset;
66  try
67  {
68  fr_pset = daq_pset.get<fhicl::ParameterSet>("fragment_receiver");
69  data_pset_ = fr_pset;
70  }
71  catch (...)
72  {
73  TLOG_ERROR(app_name)
74  << "Unable to find the fragment_receiver parameters in the DAQ "
75  << "initialization ParameterSet: \"" + daq_pset.to_string() + "\"." << TLOG_ENDL;
76  return false;
77  }
78 
79  // pull out the Metric part of the ParameterSet
80  fhicl::ParameterSet metric_pset;
81  try
82  {
83  metric_pset = daq_pset.get<fhicl::ParameterSet>("metrics");
84  }
85  catch (...) {} // OK if there's no metrics table defined in the FHiCL
86 
87  if (metric_pset.is_empty())
88  {
89  TLOG_INFO(app_name) << "No metric plugins appear to be defined" << TLOG_ENDL;
90  }
91  try
92  {
93  metricMan_.initialize(metric_pset, app_name);
94  }
95  catch (...)
96  {
97  ExceptionHandler(ExceptionHandlerRethrow::no,
98  "Error loading metrics in BoardReaderCore::initialize()");
99  }
100 
101  // create the requested CommandableFragmentGenerator
102  std::string frag_gen_name = fr_pset.get<std::string>("generator", "");
103  if (frag_gen_name.length() == 0)
104  {
105  TLOG_ERROR(app_name)
106  << "No fragment generator (parameter name = \"generator\") was "
107  << "specified in the fragment_receiver ParameterSet. The "
108  << "DAQ initialization PSet was \"" << daq_pset.to_string() << "\"." << TLOG_ENDL;
109  return false;
110  }
111 
112  try
113  {
114  generator_ptr_ = artdaq::makeCommandableFragmentGenerator(frag_gen_name, fr_pset);
115  }
116  catch (...)
117  {
118  std::stringstream exception_string;
119  exception_string << "Exception thrown during initialization of fragment generator of type \""
120  << frag_gen_name << "\"";
121 
122  ExceptionHandler(ExceptionHandlerRethrow::no, exception_string.str());
123 
124  TLOG_DEBUG(app_name) << "FHiCL parameter set used to initialize the fragment generator which threw an exception: " << fr_pset.to_string() << TLOG_ENDL;
125 
126  return false;
127  }
128  metricMan_.setPrefix(generator_ptr_->metricsReportingInstanceName());
129 
130  rt_priority_ = fr_pset.get<int>("rt_priority", 0);
131  /* ELF 5/10/2017 Removing in favor of DataReceiverManager source suppression logic
132  mpi_sync_fragment_interval_ = fr_pset.get<int>("mpi_sync_interval", 0);
133  if (mpi_sync_fragment_interval_ > 0)
134  {
135  mpi_sync_wait_threshold_fraction_ = fr_pset.get<double>("mpi_sync_wait_threshold", 0.5);
136  mpi_sync_wait_threshold_count_ = mpi_sync_fragment_interval_ * mpi_sync_wait_threshold_fraction_;
137  if (mpi_sync_wait_threshold_count_ >= mpi_sync_fragment_interval_)
138  {
139  TLOG_WARNING(app_name) << "The calculated mpi_sync wait threshold "
140  << "(" << mpi_sync_wait_threshold_count_ << " fragments) "
141  << "is too large, setting it to "
142  << (mpi_sync_fragment_interval_ - 1) << "." << TLOG_ENDL;
143  mpi_sync_wait_threshold_count_ = mpi_sync_fragment_interval_ - 1;
144  }
145  if (mpi_sync_wait_threshold_count_ < 0)
146  {
147  TLOG_WARNING(app_name) << "The calculated mpi_sync wait threshold "
148  << "(" << mpi_sync_wait_threshold_count_ << " fragments) "
149  << "is too small, setting it to zero." << TLOG_ENDL;
150  mpi_sync_wait_threshold_count_ = 0;
151  }
152  mpi_sync_wait_interval_usec_ = fr_pset.get<size_t>("mpi_sync_wait_interval_usec", 100);
153  mpi_sync_wait_log_level_ = fr_pset.get<int>("mpi_sync_wait_log_level", 2);
154  mpi_sync_wait_log_interval_sec_ = fr_pset.get<int>("mpi_sync_wait_log_interval_sec", 10);
155  }
156  else
157  {
158  mpi_sync_wait_threshold_fraction_ = 0.0;
159  mpi_sync_wait_threshold_count_ = 0;
160  mpi_sync_wait_interval_usec_ = 1000000;
161  mpi_sync_wait_log_level_ = 0;
162  mpi_sync_wait_log_interval_sec_ = 10;
163  }
164  TLOG_DEBUG(app_name)
165  << "mpi_sync_fragment_interval is " << mpi_sync_fragment_interval_
166  << ", mpi_sync_wait_threshold_fraction is " << mpi_sync_wait_threshold_fraction_
167  << ", mpi_sync_wait_threshold_count is " << mpi_sync_wait_threshold_count_
168  << ", mpi_sync_wait_interval_usec is " << mpi_sync_wait_interval_usec_
169  << ", mpi_sync_wait_log_level is " << mpi_sync_wait_log_level_
170  << ", mpi_sync_wait_log_interval_sec is " << mpi_sync_wait_log_interval_sec_ << TLOG_ENDL;
171  */
172  // fetch the monitoring parameters and create the MonitoredQuantity instances
173  statsHelper_.createCollectors(fr_pset, 100, 30.0, 60.0, FRAGMENTS_PROCESSED_STAT_KEY);
174 
175  // check if we should skip the sequence ID test...
176  skip_seqId_test_ = (generator_ptr_->fragmentIDs().size() > 1);
177 
178  return true;
179 }
180 
181 bool artdaq::BoardReaderCore::start(art::RunID id, uint64_t timeout, uint64_t timestamp)
182 {
183  stop_requested_.store(false);
184  pause_requested_.store(false);
185 
186  fragment_count_ = 0;
187  prev_seq_id_ = 0;
188  statsHelper_.resetStatistics();
189 
190  metricMan_.do_start();
191  generator_ptr_->StartCmd(id.run(), timeout, timestamp);
192  run_id_ = id;
193 
194  TLOG_DEBUG(app_name) << "Started run " << run_id_.run() <<
195  ", timeout = " << timeout << ", timestamp = " << timestamp << TLOG_ENDL;
196  return true;
197 }
198 
199 bool artdaq::BoardReaderCore::stop(uint64_t timeout, uint64_t timestamp)
200 {
201  TLOG_DEBUG(app_name) << "Stopping run " << run_id_.run()
202  << " after " << fragment_count_
203  << " fragments." << TLOG_ENDL;
204  stop_requested_.store(true);
205  generator_ptr_->StopCmd(timeout, timestamp);
206  return true;
207 }
208 
209 bool artdaq::BoardReaderCore::pause(uint64_t timeout, uint64_t timestamp)
210 {
211  TLOG_DEBUG(app_name) << "Pausing run " << run_id_.run()
212  << " after " << fragment_count_
213  << " fragments." << TLOG_ENDL;
214  pause_requested_.store(true);
215  generator_ptr_->PauseCmd(timeout, timestamp);
216  return true;
217 }
218 
219 bool artdaq::BoardReaderCore::resume(uint64_t timeout, uint64_t timestamp)
220 {
221  TLOG_DEBUG(app_name) << "Resuming run " << run_id_.run() << TLOG_ENDL;
222  pause_requested_.store(false);
223  metricMan_.do_start();
224  generator_ptr_->ResumeCmd(timeout, timestamp);
225  return true;
226 }
227 
229 {
230  generator_ptr_->joinThreads(); // Cleanly shut down the CommandableFragmentGenerator
231  generator_ptr_.reset(nullptr);
232  metricMan_.shutdown();
233  return true;
234 }
235 
236 bool artdaq::BoardReaderCore::soft_initialize(fhicl::ParameterSet const& pset, uint64_t, uint64_t)
237 {
238  TLOG_DEBUG(app_name) << "soft_initialize method called with "
239  << "ParameterSet = \"" << pset.to_string()
240  << "\"." << TLOG_ENDL;
241  return true;
242 }
243 
244 bool artdaq::BoardReaderCore::reinitialize(fhicl::ParameterSet const& pset, uint64_t, uint64_t)
245 {
246  TLOG_DEBUG(app_name) << "reinitialize method called with "
247  << "ParameterSet = \"" << pset.to_string()
248  << "\"." << TLOG_ENDL;
249  return true;
250 }
251 
253 {
254  if (rt_priority_ > 0)
255  {
256 #pragma GCC diagnostic push
257 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
258  sched_param s_param = {};
259  s_param.sched_priority = rt_priority_;
260  if (pthread_setschedparam(pthread_self(), SCHED_RR, &s_param))
261  TLOG_WARNING(app_name) << "setting realtime priority failed" << TLOG_ENDL;
262 #pragma GCC diagnostic pop
263  }
264 
265  // try-catch block here?
266 
267  // how to turn RT PRI off?
268  if (rt_priority_ > 0)
269  {
270 #pragma GCC diagnostic push
271 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
272  sched_param s_param = {};
273  s_param.sched_priority = rt_priority_;
274  int status = pthread_setschedparam(pthread_self(), SCHED_RR, &s_param);
275  if (status != 0)
276  {
277  TLOG_ERROR(app_name)
278  << "Failed to set realtime priority to " << rt_priority_
279  << ", return code = " << status << TLOG_ENDL;
280  }
281 #pragma GCC diagnostic pop
282  }
283 
284  TLOG_DEBUG(app_name) << "Initializing DataSenderManager. my_rank=" << my_rank << TLOG_ENDL;
285  sender_ptr_.reset(new artdaq::DataSenderManager(data_pset_));
286 
287  TLOG_DEBUG(app_name) << "Waiting for first fragment." << TLOG_ENDL;
288  artdaq::MonitoredQuantityStats::TIME_POINT_T startTime;
289  double delta_time;
290  artdaq::FragmentPtrs frags;
291  bool active = true;
292 
293  while (active)
294  {
295  startTime = artdaq::MonitoredQuantity::getCurrentTime();
296 
297  TRACE(18, app_name + "::process_fragments getNext start");
298  active = generator_ptr_->getNext(frags);
299  TRACE(18, app_name + "::process_fragments getNext done (active=%i)", active);
300  // 08-May-2015, KAB & JCF: if the generator getNext() method returns false
301  // (which indicates that the data flow has stopped) *and* the reason that
302  // it has stopped is because there was an exception that wasn't handled by
303  // the experiment-specific FragmentGenerator class, we move to the
304  // InRunError state so that external observers (e.g. RunControl or
305  // DAQInterface) can see that there was a problem.
306  if (!active && generator_ptr_ && generator_ptr_->exception())
307  {
308  parent_application_.in_run_failure();
309  }
310 
311  delta_time = artdaq::MonitoredQuantity::getCurrentTime() - startTime;
312  statsHelper_.addSample(INPUT_WAIT_STAT_KEY, delta_time);
313 
314  TLOG_ARB(16,app_name) << "process_fragments INPUT_WAIT="<<std::to_string( delta_time) << TLOG_ENDL;
315 
316  if (!active) { break; }
317  statsHelper_.addSample(FRAGMENTS_PER_READ_STAT_KEY, frags.size());
318 
319  for (auto& fragPtr : frags)
320  {
321  if (!fragPtr.get())
322  {
323  TLOG_WARNING(app_name) << "Encountered a bad fragment pointer in fragment " << fragment_count_ << ". "
324  << "This is most likely caused by a problem with the Fragment Generator!" << TLOG_ENDL;
325  continue;
326  }
327  artdaq::Fragment::sequence_id_t sequence_id = fragPtr->sequenceID();
328  statsHelper_.addSample(FRAGMENTS_PROCESSED_STAT_KEY, fragPtr->size());
329 
330  if ((fragment_count_ % 250) == 0)
331  {
332  TLOG_DEBUG(app_name)
333  << "Sending fragment " << fragment_count_
334  << " (%250) with sequence id " << sequence_id << "." << TLOG_ENDL;
335  }
336 
337  // check for continous sequence IDs
338  if (!skip_seqId_test_ && abs(sequence_id - prev_seq_id_) > 1)
339  {
340  TLOG_WARNING(app_name)
341  << "Missing sequence IDs: current sequence ID = "
342  << sequence_id << ", previous sequence ID = "
343  << prev_seq_id_ << "." << TLOG_ENDL;
344  }
345  prev_seq_id_ = sequence_id;
346 
347  startTime = artdaq::MonitoredQuantity::getCurrentTime();
348  TLOG_ARB(17,app_name) << "process_fragments seq="<< std::to_string(sequence_id) << " sendFragment start" << TLOG_ENDL;
349  auto res = sender_ptr_->sendFragment(std::move(*fragPtr));
350  TLOG_ARB(17, app_name) << "process_fragments seq=" << std::to_string(sequence_id) << " sendFragment done (res="<< res<<")"<<TLOG_ENDL;
351  ++fragment_count_;
352  statsHelper_.addSample(OUTPUT_WAIT_STAT_KEY,
353  artdaq::MonitoredQuantity::getCurrentTime() - startTime);
354 
355  bool readyToReport = statsHelper_.readyToReport(fragment_count_);
356  if (readyToReport)
357  {
358  std::string statString = buildStatisticsString_();
359  TLOG_DEBUG(app_name) << statString << TLOG_ENDL;
360  }
361  if (fragment_count_ == 1 || readyToReport)
362  {
363  TLOG_DEBUG(app_name)
364  << "Sending fragment " << fragment_count_
365  << " with sequence id " << sequence_id << "." << TLOG_ENDL;
366  }
367  }
368  if (statsHelper_.statsRollingWindowHasMoved()) { sendMetrics_(); }
369  frags.clear();
370  }
371 
372  // 11-May-2015, KAB: call MetricManager::do_stop whenever we exit the
373  // processing fragments loop so that metrics correctly go to zero when
374  // there is no data flowing
375  metricMan_.do_stop();
376 
377  sender_ptr_.reset(nullptr);
378 }
379 
380 std::string artdaq::BoardReaderCore::report(std::string const& which) const
381 {
382  std::string resultString;
383 
384  // pass the request to the FragmentGenerator instance, if it's available
385  if (generator_ptr_.get() != 0)
386  {
387  resultString = generator_ptr_->ReportCmd(which);
388  if (resultString.length() > 0) { return resultString; }
389  }
390 
391  // handle the request at this level, if we can
392  // --> nothing here yet
393 
394  // if we haven't been able to come up with any report so far, say so
395  std::string tmpString = app_name + " run number = ";
396  tmpString.append(boost::lexical_cast<std::string>(run_id_.run()));
397  tmpString.append(". Command=\"" + which + "\" is not currently supported.");
398  return tmpString;
399 }
400 
401 bool artdaq::BoardReaderCore::metaCommand(std::string const& command, std::string const& arg)
402 {
403  TLOG_DEBUG(app_name) << "metaCommand method called with "
404  << "command = \"" << command << "\""
405  << ", arg = \"" << arg << "\""
406  << "." << TLOG_ENDL;
407 
408  if (generator_ptr_) return generator_ptr_->metaCommand(command, arg);
409 
410  return true;
411 }
412 
413 std::string artdaq::BoardReaderCore::buildStatisticsString_()
414 {
415  std::ostringstream oss;
416  oss << app_name << " statistics:" << std::endl;
417 
418  double fragmentCount = 1.0;
419  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
420  getMonitoredQuantity(FRAGMENTS_PROCESSED_STAT_KEY);
421  if (mqPtr.get() != 0)
422  {
423  artdaq::MonitoredQuantityStats stats;
424  mqPtr->getStats(stats);
425  oss << " Fragment statistics: "
426  << stats.recentSampleCount << " fragments received at "
427  << stats.recentSampleRate << " fragments/sec, effective data rate = "
428  << (stats.recentValueRate * sizeof(artdaq::RawDataType)
429  / 1024.0 / 1024.0) << " MB/sec, monitor window = "
430  << stats.recentDuration << " sec, min::max event size = "
431  << (stats.recentValueMin * sizeof(artdaq::RawDataType)
432  / 1024.0 / 1024.0)
433  << "::"
434  << (stats.recentValueMax * sizeof(artdaq::RawDataType)
435  / 1024.0 / 1024.0)
436  << " MB" << std::endl;
437  fragmentCount = std::max(double(stats.recentSampleCount), 1.0);
438  oss << " Average times per fragment: ";
439  if (stats.recentSampleRate > 0.0)
440  {
441  oss << " elapsed time = "
442  << (1.0 / stats.recentSampleRate) << " sec";
443  }
444  }
445 
446  // 31-Dec-2014, KAB - Just a reminder that using "fragmentCount" in the
447  // denominator of the calculations below is important because the way that
448  // the accumulation of these statistics is done is not fragment-by-fragment
449  // but read-by-read (where each read can contain multiple fragments).
450  // 29-Aug-2016, KAB - BRSYNC_WAIT and OUTPUT_WAIT are now done fragment-by-
451  // fragment, but we'll leave the calculation the same. (The alternative
452  // would be to use recentValueAverage().)
453 
454  mqPtr = artdaq::StatisticsCollection::getInstance().
455  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
456  if (mqPtr.get() != 0)
457  {
458  oss << ", input wait time = "
459  << (mqPtr->getRecentValueSum() / fragmentCount) << " sec";
460  }
461 
462  mqPtr = artdaq::StatisticsCollection::getInstance().
463  getMonitoredQuantity(BRSYNC_WAIT_STAT_KEY);
464  if (mqPtr.get() != 0)
465  {
466  oss << ", BRsync wait time = "
467  << (mqPtr->getRecentValueSum() / fragmentCount) << " sec";
468  }
469 
470  mqPtr = artdaq::StatisticsCollection::getInstance().
471  getMonitoredQuantity(OUTPUT_WAIT_STAT_KEY);
472  if (mqPtr.get() != 0)
473  {
474  oss << ", output wait time = "
475  << (mqPtr->getRecentValueSum() / fragmentCount) << " sec";
476  }
477 
478  oss << std::endl << " Fragments per read: ";
479  mqPtr = artdaq::StatisticsCollection::getInstance().
480  getMonitoredQuantity(FRAGMENTS_PER_READ_STAT_KEY);
481  if (mqPtr.get() != 0)
482  {
483  artdaq::MonitoredQuantityStats stats;
484  mqPtr->getStats(stats);
485  oss << "average = "
486  << stats.recentValueAverage
487  << ", min::max = "
488  << stats.recentValueMin
489  << "::"
490  << stats.recentValueMax;
491  }
492 
493  return oss.str();
494 }
495 
496 void artdaq::BoardReaderCore::sendMetrics_()
497 {
498  //TLOG_DEBUG("BoardReaderCore") << "Sending metrics " << __LINE__ << TLOG_ENDL;
499  double fragmentCount = 1.0;
500  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
501  getMonitoredQuantity(FRAGMENTS_PROCESSED_STAT_KEY);
502  if (mqPtr.get() != 0)
503  {
504  artdaq::MonitoredQuantityStats stats;
505  mqPtr->getStats(stats);
506  fragmentCount = std::max(double(stats.recentSampleCount), 1.0);
507  metricMan_.sendMetric("Fragment Count", static_cast<unsigned long>(stats.fullSampleCount), "fragments", 1, MetricMode::Accumulate);
508  metricMan_.sendMetric("Fragment Rate", stats.recentSampleRate, "fragments/sec", 1, MetricMode::Average);
509  metricMan_.sendMetric("Average Fragment Size", (stats.recentValueAverage * sizeof(artdaq::RawDataType)), "bytes/fragment", 2, MetricMode::Average);
510  metricMan_.sendMetric("Data Rate", (stats.recentValueRate * sizeof(artdaq::RawDataType)), "bytes/sec", 2, MetricMode::Average);
511  }
512 
513  // 31-Dec-2014, KAB - Just a reminder that using "fragmentCount" in the
514  // denominator of the calculations below is important because the way that
515  // the accumulation of these statistics is done is not fragment-by-fragment
516  // but read-by-read (where each read can contain multiple fragments).
517  // 29-Aug-2016, KAB - BRSYNC_WAIT and OUTPUT_WAIT are now done fragment-by-
518  // fragment, but we'll leave the calculation the same. (The alternative
519  // would be to use recentValueAverage().)
520 
521  mqPtr = artdaq::StatisticsCollection::getInstance().
522  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
523  if (mqPtr.get() != 0)
524  {
525  metricMan_.sendMetric("Avg Input Wait Time", (mqPtr->getRecentValueSum() / fragmentCount), "seconds/fragment", 3, MetricMode::Average);
526  }
527 
528  mqPtr = artdaq::StatisticsCollection::getInstance().
529  getMonitoredQuantity(BRSYNC_WAIT_STAT_KEY);
530  if (mqPtr.get() != 0)
531  {
532  metricMan_.sendMetric("Avg BoardReader Sync Wait Time", (mqPtr->getRecentValueSum() / fragmentCount), "seconds/fragment", 3, MetricMode::Average);
533  }
534 
535  mqPtr = artdaq::StatisticsCollection::getInstance().
536  getMonitoredQuantity(OUTPUT_WAIT_STAT_KEY);
537  if (mqPtr.get() != 0)
538  {
539  metricMan_.sendMetric("Avg Output Wait Time", (mqPtr->getRecentValueSum() / fragmentCount), "seconds/fragment", 3, MetricMode::Average);
540  }
541 
542  mqPtr = artdaq::StatisticsCollection::getInstance().
543  getMonitoredQuantity(FRAGMENTS_PER_READ_STAT_KEY);
544  if (mqPtr.get() != 0)
545  {
546  metricMan_.sendMetric("Avg Frags Per Read", mqPtr->getRecentValueAverage(), "fragments/read", 4, MetricMode::Average);
547  }
548 }
void addMonitoredQuantityName(std::string const &statKey)
Add a MonitoredQuantity name to the list.
Commandable is the base class for all artdaq components which implement the artdaq state machine...
Definition: Commandable.hh:20
Sends Fragment objects using TransferInterface plugins. Uses Routing Tables if confgiured, otherwise will Round-Robin Fragments to the destinations.
static const std::string FRAGMENTS_PROCESSED_STAT_KEY
Key for the Fragments Processed MonitoredQuantity.
static const std::string INPUT_WAIT_STAT_KEY
Key for the Input Wait MonitoredQuantity.
bool stop(uint64_t timeout, uint64_t timestamp)
Stop the BoardReader, and the CommandableFragmentGenerator.
virtual ~BoardReaderCore()
BoardReaderCore Destructor.
BoardReaderCore(Commandable &parent_application)
BoardReaderCore Constructor.
std::unique_ptr< CommandableFragmentGenerator > makeCommandableFragmentGenerator(std::string const &generator_plugin_spec, fhicl::ParameterSet const &ps)
Load a CommandableFragmentGenerator plugin.
bool reinitialize(fhicl::ParameterSet const &pset, uint64_t, uint64_t)
Reinitialize the BoardReader. No-Op.
bool soft_initialize(fhicl::ParameterSet const &pset, uint64_t, uint64_t)
Soft-Initialize the BoardReader. No-Op.
static const std::string BRSYNC_WAIT_STAT_KEY
Key for the Sync Wait MonitoredQuantity.
static const std::string FRAGMENTS_PER_READ_STAT_KEY
Key for the Fragments Per Read MonitoredQuantity.
static const std::string OUTPUT_WAIT_STAT_KEY
Key for the Output Wait MonitoredQuantity.
bool initialize(fhicl::ParameterSet const &pset, uint64_t, uint64_t)
Initialize the BoardReaderCore.
std::string report(std::string const &which) const
Send a report on a given run-time quantity.
void process_fragments()
Main working loop of the BoardReaderCore.
bool start(art::RunID id, uint64_t timeout, uint64_t timestamp)
Start the BoardReader, and the CommandableFragmentGenerator.
bool resume(uint64_t timeout, uint64_t timestamp)
Resume the BoardReader, and the CommandableFragmentGenerator.
bool pause(uint64_t timeout, uint64_t timestamp)
Pause the BoardReader, and the CommandableFragmentGenerator.
bool shutdown(uint64_t)
Shutdown the BoardReader, and the CommandableFragmentGenerator.
bool metaCommand(std::string const &command, std::string const &arg)
Run a user-defined command on the CommandableFragmentGenerator.