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"
92 fhicl::Atom<std::string>
generator_type { fhicl::Name{
"generator" }, fhicl::Comment{
"Name of the CommandableFragmentGenerator plugin to load"} };
94 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 };
96 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 };
98 fhicl::Atom<Fragment::timestamp_t>
stale_request_timeout { fhicl::Name{
"stale_request_timeout" }, fhicl::Comment{
"How long should request messages be retained"}, 0xFFFFFFFF };
100 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) };
102 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 };
104 fhicl::Atom<size_t>
missing_request_window_timeout_us { fhicl::Name{
"missing_request_window_timeout_us"}, fhicl::Comment{
"How long to track missing requests in the \"out - of - order Windows\" list"}, 5000000 };
106 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 time the request was received)"}, 2000000 };
108 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 };
110 fhicl::Atom<bool>
circular_buffer_mode { fhicl::Name{
"circular_buffer_mode" }, fhicl::Comment{
"Whether the data buffer should be treated as a circular buffer on the input side (i.e. old fragments are automatically discarded when the buffer is full to always call getNext_)."},
false };
112 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 };
114 fhicl::Atom<int>
data_buffer_depth_fragments { fhicl::Name{
"data_buffer_depth_fragments" }, fhicl::Comment{
"How many Fragments to store in the buffer"}, 1000 };
116 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 };
118 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 };
120 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 };
122 fhicl::Atom<int>
board_id { fhicl::Name{
"board_id" }, fhicl::Comment{
"The identification number for this CommandableFragmentGenerator"} };
125 fhicl::Sequence<Fragment::fragment_id_t>
fragment_ids { fhicl::Name(
"fragment_ids" ), fhicl::Comment(
"A list of Fragment IDs created by this CommandableFragmentGenerator") };
128 fhicl::Atom<int>
fragment_id { fhicl::Name{
"fragment_id" }, fhicl::Comment{
"The Fragment ID created by this CommandableFragmentGenerator"}, -99 };
130 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 };
138 fhicl::Atom<std::string>
request_mode { fhicl::Name{
"request_mode" }, fhicl::Comment{
"The mode by which the CommandableFragmentGenerator will process reqeusts"},
"ignored" };
141 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);
244 return windows_sent_ooo_;
298 return fragment_ids_;
375 std::string
ReportCmd(std::string
const& which =
"");
383 return instance_name_for_metrics_;
415 virtual bool metaCommand(std::string
const& command, std::string
const& arg);
493 instance_name_for_metrics_ = name;
517 std::unique_ptr<RequestReceiver> requestReceiver_;
520 Fragment::timestamp_t windowOffset_;
521 Fragment::timestamp_t windowWidth_;
522 Fragment::timestamp_t staleTimeout_;
523 Fragment::type_t expectedType_;
524 size_t maxFragmentCount_;
526 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> windows_sent_ooo_;
527 size_t missing_request_window_timeout_us_;
528 size_t window_close_timeout_us_;
531 bool circularDataBufferMode_;
532 size_t sleep_on_no_data_us_;
533 std::atomic<bool> data_thread_running_;
534 boost::thread dataThread_;
536 std::condition_variable dataCondition_;
537 std::atomic<int> dataBufferDepthFragments_;
538 std::atomic<size_t> dataBufferDepthBytes_;
539 int maxDataBufferDepthFragments_;
540 size_t maxDataBufferDepthBytes_;
542 bool useMonitoringThread_;
543 boost::thread monitoringThread_;
544 int64_t monitoringInterval_;
545 std::chrono::steady_clock::time_point lastMonitoringCall_;
546 std::atomic<bool> isHardwareOK_;
548 FragmentPtrs dataBuffer_;
549 FragmentPtrs newDataBuffer_;
550 std::mutex dataBufferMutex_;
552 std::vector<artdaq::Fragment::fragment_id_t> fragment_ids_;
557 int run_number_, subrun_number_;
572 std::atomic<bool> should_stop_, exception_, force_stop_;
573 std::string latest_exception_report_;
574 std::atomic<size_t> ev_counter_;
577 std::string instance_name_for_metrics_;
582 int sleep_on_stop_us_;
593 virtual bool getNext_(FragmentPtrs& output) = 0;
618 virtual void start() = 0;
636 virtual void stop() = 0;
649 virtual void pause();
667 virtual std::string
report();
fhicl::Atom< Fragment::type_t > expected_fragment_type
"expected_fragment_type" (Default: 231, EmptyFragmentType) : The type of Fragments this CFG will be g...
int fragment_id() const
Get the current Fragment ID, if there is only one.
fhicl::Atom< int > board_id
"board_id" (REQUIRED) : The identification number for this CommandableFragmentGenerator ...
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 void start()=0
If a CommandableFragmentGenerator subclass is reading from a file, and start() is called...
fhicl::Atom< int64_t > hardware_poll_interval_us
"hardware_poll_interval_us" (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.
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())
fhicl::TableFragment< artdaq::RequestReceiver::Config > receiverConfig
Configuration for the Request Receiver. See artdaq::RequestReceiver::Config.
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.
fhicl::Atom< int > fragment_id
fhicl::Atom< Fragment::timestamp_t > stale_request_timeout
"stale_request_timeout" (Default: -1) : How long should request messages be retained ...
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.
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.
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.
fhicl::Atom< int > data_buffer_depth_fragments
"data_buffer_depth_fragments" (Default: 1000) : How many Fragments to store in the buffer ...
fhicl::Atom< size_t > data_buffer_depth_mb
"data_buffer_depth_mb" (Default: 1000) : The maximum size of the data buffer in MB ...
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
"sleep_on_stop_us" (Default: 0) : How long to sleep before returning when stop transition is called ...
void applyRequestsIgnoredMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Ignored. Precondition: dataBufferMutex_ and reque...
fhicl::Atom< size_t > missing_request_window_timeout_us
"missing_request_window_timeout_us" (Default: 5000000) : How long to track missing requests in the "o...
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...
fhicl::Sequence< Fragment::fragment_id_t > fragment_ids
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...
virtual bool getNext_(FragmentPtrs &output)=0
Obtain the next group of Fragments, if any are available. Return false if readout cannot continue...
fhicl::Atom< std::string > request_mode
"request_mode" (Deafult: Ignored) : The mode by which the CommandableFragmentGenerator will process r...
void startMonitoringThread()
Function that launches the monitoring thread (getMonitoringDataLoop())
fhicl::Atom< Fragment::timestamp_t > request_window_offset
"request_window_offset" (Default: 0) : Request messages contain a timestamp.For Window request mode...
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.
void checkDataBuffer()
Perform data buffer pruning operations. If the RequestMode is Single, removes all but the latest Frag...
fhicl::Atom< bool > request_windows_are_unique
"request_windows_are_unique" (Default: true) : Whether Fragments should be removed from the buffer wh...
std::map< Fragment::sequence_id_t, std::chrono::steady_clock::time_point > getOutOfOrderWindowList() const
Access the windows_sent_ooo_ map.
fhicl::Atom< size_t > window_close_timeout_us
"window_close_timeout_us" (Default: 2000000) : How long to wait for the end of the data buffer to pas...
fhicl::Atom< size_t > sleep_on_no_data_us
"sleep_on_no_data_us" (Default: 0 (no sleep)) : How long to sleep after calling getNext_ if no data i...
fhicl::Atom< Fragment::timestamp_t > request_window_width
"request_window_width" (Default: 0) : For Window request mode, the window will be timestamp - offset ...
virtual std::string report()
Let'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
fhicl::Atom< bool > separate_data_thread
"separate_data_thread" (Default: false) : Whether data collection should proceed on its own thread...
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.
RequestMode request_mode() const
Get the current request mode of the CommandableFragmentGenerator
uint64_t timestamp() const
Timestamp of last command.
fhicl::Atom< bool > circular_buffer_mode
"circular_buffer_mode" (Default: false) : Whether the data buffer should be treated as a circular buf...
Configuration of the CommandableFragmentGenerator. May be used for parameter validation ...
fhicl::Atom< std::string > generator_type
"generator" (REQUIRED) Name of the CommandableFragmentGenerator plugin to load
void checkOutOfOrderWindows(Fragment::sequence_id_t seq)
Check the windows_sent_ooo_ map for sequence IDs that may be removed.
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
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.
fhicl::Atom< bool > separate_monitoring_thread
"separate_monitoring_thread" (Default: false) : Whether a thread that calls the checkHWStatus_ method...
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.