1 #ifndef artdaq_Application_CommandableFragmentGenerator_hh
2 #define artdaq_Application_CommandableFragmentGenerator_hh
6 #include <netinet/in.h>
8 #include <sys/socket.h>
12 #include <condition_variable>
19 #include "fhiclcpp/fwd.h"
20 #include "fhiclcpp/ParameterSet.h"
22 #include "artdaq/DAQdata/Globals.hh"
23 #include "artdaq-core/Data/Fragment.hh"
24 #include "artdaq-core/Generators/FragmentGenerator.hh"
25 #include "artdaq-utilities/Plugins/MetricManager.hh"
26 #include "artdaq/DAQrate/RequestReceiver.hh"
89 fhicl::Atom<std::string> generator_type { fhicl::Name{
"generator" }, fhicl::Comment{
"Name of the CommandableFragmentGenerator plugin to load"} };
90 fhicl::Atom<Fragment::timestamp_t> request_window_offset { fhicl::Name{
"request_window_offset" }, fhicl::Comment{
"Request messages contain a timestamp. For Window request mode, start the window this far before the timestamp in the request"}, 0 };
91 fhicl::Atom<Fragment::timestamp_t> request_window_width { fhicl::Name{
"request_window_width" }, fhicl::Comment{
"For Window request mode, the window will be timestamp - offset to timestamp - offset + width"}, 0 };
92 fhicl::Atom<Fragment::timestamp_t> stale_request_timeout { fhicl::Name{
"stale_request_timeout" }, fhicl::Comment{
"How long should request messages be retained"}, 0xFFFFFFFF };
93 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) };
94 fhicl::Atom<bool> request_windows_are_unique { fhicl::Name{
"request_windows_are_unique" }, fhicl::Comment{
"Whether Fragments should be removed from the buffer when matched to a request window"},
true };
95 fhicl::Atom<size_t> missing_request_window_timeout_us { fhicl::Name{
"missing_request_window_timeout_us"}, fhicl::Comment{
"How long to wait for a missing request in Window mode (measured from the last time data was sent)"}, 1000000 };
96 fhicl::Atom<size_t> window_close_timeout_us { fhicl::Name{
"window_close_timeout_us" }, fhicl::Comment{
"How long to wait for the end of the data buffer to pass the end of a request window (measured from the last time data was sent)"}, 2000000 };
97 fhicl::Atom<bool> separate_data_thread { fhicl::Name{
"separate_data_thread" }, fhicl::Comment{
"Whether data collection should proceed on its own thread. Required for all data request processing"},
false };
98 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 };
99 fhicl::Atom<int> data_buffer_depth_fragments { fhicl::Name{
"data_buffer_depth_fragments" }, fhicl::Comment{
"How many Fragments to store in the buffer"}, 1000 };
100 fhicl::Atom<size_t> data_buffer_depth_mb { fhicl::Name{
"data_buffer_depth_mb" }, fhicl::Comment{
"The maximum size of the data buffer in MB"}, 1000 };
101 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 };
102 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 };
103 fhicl::Atom<int> board_id { fhicl::Name{
"board_id" }, fhicl::Comment{
"The identification number for this CommandableFragmentGenerator"} };
104 fhicl::Sequence<Fragment::fragment_id_t> fragment_ids { fhicl::Name(
"fragment_ids" ), fhicl::Comment(
"A list of Fragment IDs created by this CommandableFragmentGenerator") };
105 fhicl::Atom<int> fragment_id { fhicl::Name{
"fragment_id" }, fhicl::Comment{
"The Fragment ID created by this CommandableFragmentGenerator"}, -99 };
106 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 };
107 fhicl::Atom<std::string> request_mode { fhicl::Name{
"request_mode" }, fhicl::Comment{
"The mode by which the CommandableFragmentGenerator will process reqeusts"},
"ignored" };
108 fhicl::TableFragment<artdaq::RequestReceiver::Config> receiverConfig;
110 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
111 using Parameters = fhicl::WrappedTable<Config>;
177 bool getNext(FragmentPtrs& output)
override final;
222 bool sendEmptyFragment(FragmentPtrs& frags,
size_t sequenceId, std::string desc);
230 void sendEmptyFragments(FragmentPtrs& frags, std::map<Fragment::sequence_id_t, Fragment::timestamp_t>& requests);
283 return fragment_ids_;
348 std::string
ReportCmd(std::string
const& which =
"");
356 return instance_name_for_metrics_;
388 virtual bool metaCommand(std::string
const& command, std::string
const& arg);
472 instance_name_for_metrics_ = name;
496 std::unique_ptr<RequestReceiver> requestReceiver_;
499 Fragment::timestamp_t windowOffset_;
500 Fragment::timestamp_t windowWidth_;
501 Fragment::timestamp_t staleTimeout_;
502 Fragment::type_t expectedType_;
503 size_t maxFragmentCount_;
505 bool missing_request_;
506 std::chrono::steady_clock::time_point missing_request_time_;
507 std::chrono::steady_clock::time_point last_window_send_time_;
508 bool last_window_send_time_set_;
509 std::set<Fragment::sequence_id_t> windows_sent_ooo_;
510 size_t missing_request_window_timeout_us_;
511 size_t window_close_timeout_us_;
514 size_t sleep_on_no_data_us_;
515 std::atomic<bool> data_thread_running_;
516 boost::thread dataThread_;
518 std::condition_variable dataCondition_;
519 std::atomic<int> dataBufferDepthFragments_;
520 std::atomic<size_t> dataBufferDepthBytes_;
521 int maxDataBufferDepthFragments_;
522 size_t maxDataBufferDepthBytes_;
524 bool useMonitoringThread_;
525 boost::thread monitoringThread_;
526 int64_t monitoringInterval_;
527 std::chrono::steady_clock::time_point lastMonitoringCall_;
530 FragmentPtrs dataBuffer_;
531 FragmentPtrs newDataBuffer_;
532 std::mutex dataBufferMutex_;
534 std::vector<artdaq::Fragment::fragment_id_t> fragment_ids_;
539 int run_number_, subrun_number_;
554 std::atomic<bool> should_stop_, exception_, force_stop_;
555 std::string latest_exception_report_;
556 std::atomic<size_t> ev_counter_;
559 std::string instance_name_for_metrics_;
564 int sleep_on_stop_us_;
572 virtual bool getNext_(FragmentPtrs& output) = 0;
578 virtual bool checkHWStatus_();
590 virtual void start() = 0;
594 virtual void stopNoMutex() = 0;
600 virtual void stop() = 0;
604 virtual void pauseNoMutex();
609 virtual void pause();
615 virtual void resume();
625 virtual std::string report();
627 virtual std::string reportSpecific(std::string
const&);
int fragment_id() const
Get the current Fragment ID, if there is only one.
void applyRequestsSingleMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Single. Precondition: dataBufferMutex_ and reques...
int subrun_number() const
Get the current Subrun number.
virtual ~CommandableFragmentGenerator()
CommandableFragmentGenerator Destructor.
RequestMode
The RequestMode enumeration contains the possible ways which CommandableFragmentGenerator responds to...
void applyRequestsBufferMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Buffer. Precondition: dataBufferMutex_ and reques...
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.
bool sendEmptyFragment(FragmentPtrs &frags, size_t sequenceId, std::string desc)
Send an EmptyFragmentType Fragment.
void getMonitoringDataLoop()
This function regularly calls checkHWStatus_(), and sets the isHardwareOK flag accordingly.
void startDataThread()
Function that launches the data thread (getDataLoop())
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.
bool dataBufferIsTooLarge()
Test the configured constraints on the data buffer.
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
uint64_t timeout() const
Timeout of last command.
void applyRequestsWindowMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Window. Precondition: dataBufferMutex_ and reques...
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
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.
CommandableFragmentGenerator()
CommandableFragmentGenerator default constructor.
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
bool waitForDataBufferReady()
Wait for the data buffer to drain (dataBufferIsTooLarge returns false), periodically reporting status...
size_t ev_counter_inc(size_t step=1, bool force=false)
Increment the event counter, if the current RequestMode allows it.
std::vector< Fragment::fragment_id_t > fragmentIDs() override
Get the list of Fragment IDs handled by this CommandableFragmentGenerator.
void applyRequestsIgnoredMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Ignored. Precondition: dataBufferMutex_ and reque...
void PauseCmd(uint64_t timeout, uint64_t timestamp)
Pause the CommandableFragmentGenerator.
void getDataLoop()
When separate_data_thread is set to true, this loop repeatedly calls getNext_ and adds returned Fragm...
virtual std::string metricsReportingInstanceName() const
Get the name used when reporting metrics.
void sendEmptyFragments(FragmentPtrs &frags, std::map< Fragment::sequence_id_t, Fragment::timestamp_t > &requests)
This function is for Buffered and Single request modes, as they can only respond to one data request ...
bool should_stop() const
Get the current value of the should_stop flag.
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
void startMonitoringThread()
Function that launches the monitoring thread (getMonitoringDataLoop())
size_t ev_counter() const
Get the current value of the event counter.
void checkDataBuffer()
Perform data buffer pruning operations. If the RequestMode is Single, removes all but the latest Frag...
int board_id() const
Gets the current board_id.
std::string printMode_()
Return the string representation of the current RequestMode.
void set_exception(bool exception)
Control the exception flag.
void getDataBufferStats()
Calculate the size of the dataBuffer and report appropriate metrics.
uint64_t timestamp() const
Timestamp of last command.
bool applyRequests(FragmentPtrs &output)
See if any requests have been received, and add the corresponding data Fragment objects to the output...
int run_number() const
Get the current Run number.
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.