artdaq  v3_09_01
CommandableFragmentGenerator.hh
1 #ifndef artdaq_Application_CommandableFragmentGenerator_hh
2 #define artdaq_Application_CommandableFragmentGenerator_hh
3 
4 // Socket Includes
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 #include <sys/socket.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 
11 #include <array>
12 #include <atomic>
13 #include <chrono>
14 #include <condition_variable>
15 #include <list>
16 #include <mutex>
17 #include <queue>
18 
19 #include "fhiclcpp/ParameterSet.h"
20 #include "fhiclcpp/fwd.h"
21 
22 #include "artdaq-core/Data/Fragment.hh"
23 #include "artdaq-core/Generators/FragmentGenerator.hh"
24 #include "artdaq-utilities/Plugins/MetricManager.hh"
25 #include "artdaq/DAQrate/FragmentBuffer.hh"
26 #include "artdaq/DAQdata/Globals.hh"
27 
28 namespace artdaq {
29 
72 class CommandableFragmentGenerator : public FragmentGenerator
73 {
74 public:
78  struct Config
79  {
81  fhicl::Atom<std::string> generator_type{fhicl::Name{"generator"}, fhicl::Comment{"Name of the CommandableFragmentGenerator plugin to load"}};
83  fhicl::Atom<Fragment::type_t> expected_fragment_type{fhicl::Name{"expected_fragment_type"}, fhicl::Comment{"The type of Fragments this CFG will be generating. \"Empty\" will auto-detect type based on Fragments generated."}, Fragment::type_t(Fragment::EmptyFragmentType)};
85  fhicl::Atom<size_t> sleep_on_no_data_us{fhicl::Name{"sleep_on_no_data_us"}, fhicl::Comment{"How long to sleep after calling getNext_ if no data is returned"}, 0};
87  fhicl::Atom<bool> separate_monitoring_thread{fhicl::Name{"separate_monitoring_thread"}, fhicl::Comment{"Whether a thread that calls the checkHWStatus_ method should be created"}, false};
89  fhicl::Atom<int64_t> hardware_poll_interval_us{fhicl::Name{"hardware_poll_interval_us"}, fhicl::Comment{"If a separate monitoring thread is used, how often should it call checkHWStatus_"}, 0};
91  fhicl::Atom<int> board_id{fhicl::Name{"board_id"}, fhicl::Comment{"The identification number for this CommandableFragmentGenerator"}};
94  fhicl::Sequence<Fragment::fragment_id_t> fragment_ids{fhicl::Name("fragment_ids"), fhicl::Comment("A list of Fragment IDs created by this CommandableFragmentGenerator")};
97  fhicl::Atom<int> fragment_id{fhicl::Name{"fragment_id"}, fhicl::Comment{"The Fragment ID created by this CommandableFragmentGenerator"}, -99};
99  fhicl::Atom<int> sleep_on_stop_us{fhicl::Name{"sleep_on_stop_us"}, fhicl::Comment{"How long to sleep before returning when stop transition is called"}, 0};
100  };
102  using Parameters = fhicl::WrappedTable<Config>;
103 
108  explicit CommandableFragmentGenerator(const fhicl::ParameterSet& ps);
109 
116 
123  void joinThreads();
124 
130  bool getNext(FragmentPtrs& output) override final;
131 
132 
136  void startMonitoringThread();
137 
141  void getMonitoringDataLoop();
142 
147  std::vector<Fragment::fragment_id_t> fragmentIDs() override
148  {
149  std::vector<Fragment::fragment_id_t> output;
150 
151  for (auto& id : expectedTypes_)
152  {
153  output.push_back(id.first);
154  }
155 
156  return output;
157  }
158 
163  size_t ev_counter() const { return ev_counter_.load(); }
164 
165  //
166  // State-machine related interface below.
167  //
168 
183  void StartCmd(int run, uint64_t timeout, uint64_t timestamp);
184 
194  void StopCmd(uint64_t timeout, uint64_t timestamp);
195 
205  void PauseCmd(uint64_t timeout, uint64_t timestamp);
206 
215  void ResumeCmd(uint64_t timeout, uint64_t timestamp);
216 
227  std::string ReportCmd(std::string const& which = "");
228 
233  virtual std::string metricsReportingInstanceName() const
234  {
235  return instance_name_for_metrics_;
236  }
237 
238  // The following functions are not yet implemented, and their
239  // signatures may be subject to change.
240 
241  // John F., 12/6/13 -- do we want Reset and Shutdown commands?
242  // Kurt B., 15-Feb-2014. For the moment, I suspect that we don't
243  // want a Shutdown command. FragmentGenerator instances are
244  // Constructed at Initialization time, and they are destructed
245  // at Shutdown time. So, any shutdown operations that need to be
246  // done should be put in the FragmentGenerator child class
247  // destructors. If we find that want shutdown (or initialization)
248  // operations that are different from destruction (construction),
249  // then we'll have to add InitCmd and ShutdownCmd methods.
250 
251  // virtual void ResetCmd() final {}
252  // virtual void ShutdownCmd() final {}
253 
258  bool exception() const { return exception_.load(); }
259 
266  virtual bool metaCommand(std::string const& command, std::string const& arg);
267 
268  void SetRequestBuffer(std::shared_ptr<RequestBuffer> buffer) { requestBuffer_ = buffer; }
269 
270 protected:
271  // John F., 12/6/13 -- need to figure out which of these getter
272  // functions should be promoted to "public"
273 
274  // John F., 1/21/15 -- after more than a year, there hasn't been a
275  // single complaint that a CommandableFragmentGenerator-derived
276  // class hasn't allowed its users to access these quantities, so
277  // they're probably fine as is
278 
283  int run_number() const { return run_number_; }
288  int subrun_number() const { return subrun_number_; }
293  uint64_t timeout() const { return timeout_; }
298  uint64_t timestamp() const { return timestamp_; }
299 
305  artdaq::Fragment::fragment_id_t fragment_id() const
306  {
307  if (expectedTypes_.size() > 1) throw cet::exception("FragmentID") << "fragment_id() was called, indicating that Fragment Generator was expecting one and only one Fragment ID, but " << expectedTypes_.size() << " were declared!"; // NOLINT(cert-err60-cpp)
308  return (*expectedTypes_.begin()).first;
309  }
310 
315  bool should_stop() const { return should_stop_.load(); }
316 
321  bool check_stop();
322 
327  int board_id() const { return board_id_; }
328 
334  size_t ev_counter_inc(size_t step = 1); // returns the prev value
335 
340  void set_exception(bool exception) { exception_.store(exception); }
341 
346  void metricsReportingInstanceName(std::string const& name)
347  {
348  instance_name_for_metrics_ = name;
349  }
350 
351  // John F., 12/10/13
352  // Is there a better way to handle mutex_ than leaving it a protected variable?
353 
354  // John F., 1/21/15
355  // Translation above is "should mutex_ be a private variable,
356  // accessible via a getter function". Probably, but at this point
357  // it's not worth breaking code by implementing this.
358 
359  std::mutex mutex_;
360 
361  std::shared_ptr<RequestBuffer> GetRequestBuffer() { return requestBuffer_; }
362 
363 private:
368 
369  // FHiCL-configurable variables. Note that the C++ variable names
370  // are the FHiCL variable names with a "_" appended
371 
372  //Socket parameters
373 
374  std::map<Fragment::fragment_id_t, Fragment::type_t> expectedTypes_;
375 
376  bool useMonitoringThread_;
377  boost::thread monitoringThread_;
378  int64_t monitoringInterval_; // Microseconds
379  std::chrono::steady_clock::time_point lastMonitoringCall_;
380  std::atomic<bool> isHardwareOK_;
381 
382  // In order to support the state-machine related behavior, all
383  // CommandableFragmentGenerators must be able to remember a run number and a
384  // subrun number.
385  int run_number_, subrun_number_;
386 
387  // JCF, 8/28/14
388 
389  // Provide a user-adjustable timeout for the start transition
390  uint64_t timeout_;
391 
392  // JCF, 8/21/14
393 
394  // In response to a need to synchronize various components using
395  // different fragment generators in an experiment, keep a record
396  // of a timestamp (see Redmine Issue #6783 for more)
397 
398  uint64_t timestamp_;
399 
400  std::atomic<bool> should_stop_, exception_;
401  std::string latest_exception_report_;
402  std::atomic<size_t> ev_counter_;
403 
404  int board_id_;
405  std::string instance_name_for_metrics_;
406 
407  // Depending on what sleep_on_stop_us_ is set to, this gives the
408  // stopping thread the chance to gather the required lock
409 
410  int sleep_on_stop_us_;
411 
412  // So that derived classes can access information about requests
413  std::shared_ptr<RequestBuffer> requestBuffer_;
414 
415 protected:
423  virtual bool getNext_(FragmentPtrs& output) = 0;
424 
431  virtual bool checkHWStatus_();
432 
433  //
434  // State-machine related implementor interface below.
435  //
436 
447  virtual void start() = 0;
448 
455  virtual void stopNoMutex() = 0;
456 
465  virtual void stop() = 0;
466 
471  virtual void pauseNoMutex();
472 
478  virtual void pause();
479 
483  virtual void resume();
484 
496  virtual std::string report();
497 
503  virtual std::string reportSpecific(std::string const& what);
504 };
505 } // namespace artdaq
506 
507 #endif /* artdaq_Application_CommandableFragmentGenerator_hh */
fhicl::Atom< Fragment::type_t > expected_fragment_type
&quot;expected_fragment_type&quot; (Default: 231, EmptyFragmentType) : The type of Fragments this CFG will be g...
fhicl::Atom< int > board_id
&quot;board_id&quot; (REQUIRED) : The identification number for this CommandableFragmentGenerator ...
CommandableFragmentGenerator(const fhicl::ParameterSet &ps)
CommandableFragmentGenerator Constructor.
int subrun_number() const
Get the current Subrun number.
virtual void start()=0
If a CommandableFragmentGenerator subclass is reading from a file, and start() is called...
fhicl::Atom< int64_t > hardware_poll_interval_us
&quot;hardware_poll_interval_us&quot; (Default: 0) : If a separate monitoring thread is used, how often should it call checkHWStatus_
virtual bool checkHWStatus_()
Check any relavent hardware status registers. Return false if an error condition exists that should h...
virtual ~CommandableFragmentGenerator()
CommandableFragmentGenerator Destructor.
bool exception() const
Get the current value of the exception flag.
void metricsReportingInstanceName(std::string const &name)
Sets the name for metrics reporting.
std::mutex mutex_
Mutex used to ensure that multiple transition commands do not run at the same time.
void getMonitoringDataLoop()
This function regularly calls checkHWStatus_(), and sets the isHardwareOK flag accordingly.
artdaq::Fragment::fragment_id_t fragment_id() const
Get the Fragment ID of this Fragment generator.
std::string ReportCmd(std::string const &which="")
Get a report about a user-specified run-time quantity.
virtual bool metaCommand(std::string const &command, std::string const &arg)
The meta-command is used for implementing user-specific commands in a CommandableFragmentGenerator.
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
uint64_t timeout() const
Timeout of last command.
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
virtual void pauseNoMutex()
On call to PauseCmd, pauseNoMutex() is called prior to PauseCmd acquiring the mutex ...
bool check_stop()
Routine used by applyRequests to make sure that all outstanding requests have been fulfilled before r...
void ResumeCmd(uint64_t timeout, uint64_t timestamp)
Resume the CommandableFragmentGenerator.
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
std::vector< Fragment::fragment_id_t > fragmentIDs() override
Get the list of Fragment IDs handled by this CommandableFragmentGenerator.
fhicl::Atom< int > sleep_on_stop_us
&quot;sleep_on_stop_us&quot; (Default: 0) : How long to sleep before returning when stop transition is called ...
void PauseCmd(uint64_t timeout, uint64_t timestamp)
Pause the CommandableFragmentGenerator.
fhicl::Sequence< Fragment::fragment_id_t > fragment_ids
virtual std::string metricsReportingInstanceName() const
Get the name used when reporting metrics.
bool should_stop() const
Get the current value of the should_stop flag.
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
virtual bool getNext_(FragmentPtrs &output)=0
Obtain the next group of Fragments, if any are available. Return false if readout cannot continue...
void startMonitoringThread()
Function that launches the monitoring thread (getMonitoringDataLoop())
virtual void pause()
If a CommandableFragmentGenerator subclass is reading from hardware, the implementation of pause() sh...
virtual void resume()
The subrun number will be incremented before a call to resume.
size_t ev_counter() const
Get the current value of the event counter.
fhicl::Atom< size_t > sleep_on_no_data_us
&quot;sleep_on_no_data_us&quot; (Default: 0 (no sleep)) : How long to sleep after calling getNext_ if no data i...
virtual std::string report()
Let&#39;s say that the contract with the report() functions is that they return a non-empty string if the...
virtual void stopNoMutex()=0
On call to StopCmd, stopNoMutex() is called prior to StopCmd acquiring the mutex
int board_id() const
Gets the current board_id.
void set_exception(bool exception)
Control the exception flag.
uint64_t timestamp() const
Timestamp of last command.
Configuration of the CommandableFragmentGenerator. May be used for parameter validation ...
fhicl::Atom< std::string > generator_type
&quot;generator&quot; (REQUIRED) Name of the CommandableFragmentGenerator plugin to load
size_t ev_counter_inc(size_t step=1)
Increment the event counter.
virtual void stop()=0
If a CommandableFragmentGenerator subclass is reading from a file, calling stop() should arrange that...
virtual std::string reportSpecific(std::string const &what)
Report the status of a specific quantity
int run_number() const
Get the current Run number.
fhicl::Atom< bool > separate_monitoring_thread
&quot;separate_monitoring_thread&quot; (Default: false) : Whether a thread that calls the checkHWStatus_ method...
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.