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