1 #ifndef artdaq_Application_CommandableFragmentGenerator_hh
2 #define artdaq_Application_CommandableFragmentGenerator_hh
6 #include <netinet/in.h>
7 #include <sys/socket.h>
14 #include <condition_variable>
19 #include "fhiclcpp/ParameterSet.h"
20 #include "fhiclcpp/fwd.h"
22 #include "artdaq-core/Data/Fragment.hh"
23 #include "artdaq-core/Generators/FragmentGenerator.hh"
24 #include "artdaq-utilities/Plugins/MetricManager.hh"
25 #include "artdaq/DAQdata/Globals.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{
"Fragments stored in the fragment generator which are older than the newest stored fragment by at least stale_request_timeout units of request timestamp ticks will get discarded"}, 0xFFFFFFFF};
100 fhicl::Atom<bool>
buffer_mode_keep_latest{fhicl::Name{
"buffer_mode_keep_latest"}, fhicl::Comment{
"Keep the latest Fragment when running in Buffer mode, so that each response has at least one Fragment (Fragment will be discarded if new data arrives before next request)"},
false};
102 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)};
104 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};
106 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};
108 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};
110 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};
112 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};
114 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};
116 fhicl::Atom<int>
data_buffer_depth_fragments{fhicl::Name{
"data_buffer_depth_fragments"}, fhicl::Comment{
"The max fragments which can be stored before dropping occurs"}, 1000};
118 fhicl::Atom<size_t>
data_buffer_depth_mb{fhicl::Name{
"data_buffer_depth_mb"}, fhicl::Comment{
"The max cumulative size in megabytes of the fragments which can be stored before dropping occurs"}, 1000};
120 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};
122 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};
124 fhicl::Atom<int>
board_id{fhicl::Name{
"board_id"}, fhicl::Comment{
"The identification number for this CommandableFragmentGenerator"}};
127 fhicl::Sequence<Fragment::fragment_id_t>
fragment_ids{fhicl::Name(
"fragment_ids"), fhicl::Comment(
"A list of Fragment IDs created by this CommandableFragmentGenerator")};
130 fhicl::Atom<int>
fragment_id{fhicl::Name{
"fragment_id"}, fhicl::Comment{
"The Fragment ID created by this CommandableFragmentGenerator"}, -99};
132 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};
141 fhicl::Atom<std::string>
request_mode{fhicl::Name{
"request_mode"}, fhicl::Comment{
"The mode by which the CommandableFragmentGenerator will process reqeusts"},
"ignored"};
173 bool getNext(FragmentPtrs& output)
override final;
233 bool sendEmptyFragment(FragmentPtrs& frags,
size_t sequenceId, Fragment::fragment_id_t fragmentId, std::string desc);
241 void sendEmptyFragments(FragmentPtrs& frags, std::map<Fragment::sequence_id_t, Fragment::timestamp_t>& requests);
316 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point>
GetSentWindowList(Fragment::fragment_id_t
id)
318 if (!dataBuffers_.count(
id))
320 throw cet::exception(
"DataBufferError") <<
"Error in CommandableFragmentGenerator: Cannot get Sent Windows for ID " <<
id <<
" because it does not exist!";
322 return dataBuffers_[id].WindowsSent;
336 std::vector<Fragment::fragment_id_t> output;
338 for (
auto&
id : dataBuffers_)
340 output.push_back(
id.first);
420 std::string
ReportCmd(std::string
const& which =
"");
428 return instance_name_for_metrics_;
459 virtual bool metaCommand(std::string
const& command, std::string
const& arg);
498 if (dataBuffers_.size() > 1)
throw cet::exception(
"FragmentID") <<
"fragment_id() was called, indicating that Fragment Generator was expecting one and only one Fragment ID, but " << dataBuffers_.size() <<
" were declared!";
499 return (*dataBuffers_.begin()).first;
540 instance_name_for_metrics_ = name;
566 for (
auto&
id : dataBuffers_) count +=
id.second.DataBufferDepthFragments;
574 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t>
GetRequests()
const
576 if (requestReceiver_ ==
nullptr)
return std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t>();
577 return requestReceiver_->GetRequests();
584 std::pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t>
GetNextRequest()
const
586 if (requestReceiver_ ==
nullptr)
return std::make_pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t>(0, 0);
587 return requestReceiver_->GetNextRequest();
596 if (requestReceiver_ ==
nullptr)
return 0;
597 return requestReceiver_->size();
605 std::unique_ptr<RequestReceiver> requestReceiver_;
608 bool bufferModeKeepLatest_;
609 Fragment::timestamp_t windowOffset_;
610 Fragment::timestamp_t windowWidth_;
611 Fragment::timestamp_t staleTimeout_;
612 Fragment::type_t expectedType_;
614 size_t missing_request_window_timeout_us_;
615 size_t window_close_timeout_us_;
618 bool circularDataBufferMode_;
619 size_t sleep_on_no_data_us_;
620 std::atomic<bool> data_thread_running_;
621 boost::thread dataThread_;
623 std::condition_variable dataCondition_;
624 int maxDataBufferDepthFragments_;
625 size_t maxDataBufferDepthBytes_;
627 bool useMonitoringThread_;
628 boost::thread monitoringThread_;
629 int64_t monitoringInterval_;
630 std::chrono::steady_clock::time_point lastMonitoringCall_;
631 std::atomic<bool> isHardwareOK_;
635 std::atomic<int> DataBufferDepthFragments;
636 std::atomic<size_t> DataBufferDepthBytes;
637 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> WindowsSent;
638 bool BufferFragmentKept;
639 Fragment::sequence_id_t HighestRequestSeen;
640 FragmentPtrs DataBuffer;
643 std::mutex dataBuffersMutex_;
644 std::unordered_map<artdaq::Fragment::fragment_id_t, DataBuffer> dataBuffers_;
649 int run_number_, subrun_number_;
664 std::atomic<bool> should_stop_, exception_, force_stop_;
665 std::string latest_exception_report_;
666 std::atomic<size_t> ev_counter_;
669 std::string instance_name_for_metrics_;
674 int sleep_on_stop_us_;
684 virtual bool getNext_(FragmentPtrs& output) = 0;
708 virtual void start() = 0;
726 virtual void stop() = 0;
739 virtual void pause();
757 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...
fhicl::Atom< int > board_id
"board_id" (REQUIRED) : The identification number for this CommandableFragmentGenerator ...
CommandableFragmentGenerator(const fhicl::ParameterSet &ps)
CommandableFragmentGenerator Constructor.
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.
size_t GetCurrentRequestCount() const
Get the number of requests currently stored in the Request Recevier
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.
void getDataBufferStats(Fragment::fragment_id_t id)
Calculate the size of the dataBuffer and report appropriate metrics.
void getMonitoringDataLoop()
This function regularly calls checkHWStatus_(), and sets the isHardwareOK flag accordingly.
void startDataThread()
Function that launches the data thread (getDataLoop())
artdaq::Fragment::fragment_id_t fragment_id() const
Get the Fragment ID of this Fragment generator.
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) : Fragments stored in the fragment generator which are older th...
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
void getDataBuffersStats()
Calculate the size of all dataBuffers and report appropriate metrics.
void applyRequestsWindowMode_CheckAndFillDataBuffer(artdaq::FragmentPtrs &frags, artdaq::Fragment::fragment_id_t id, artdaq::Fragment::sequence_id_t seq, artdaq::Fragment::timestamp_t ts)
void checkSentWindows(Fragment::sequence_id_t seq)
Check the windows_sent_ooo_ map for sequence IDs that may be removed.
bool sendEmptyFragment(FragmentPtrs &frags, size_t sequenceId, Fragment::fragment_id_t fragmentId, std::string desc)
Send an EmptyFragmentType Fragment.
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.
fhicl::Atom< bool > buffer_mode_keep_latest
"buffer_mode_keep_latest" (Default: false): Keep the latest Fragment when running in Buffer mode...
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
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) : The max fragments which can be stored before dropping...
fhicl::Atom< size_t > data_buffer_depth_mb
"data_buffer_depth_mb" (Default: 1000) : The max cumulative size in megabytes of the fragments which ...
std::map< Fragment::sequence_id_t, std::chrono::steady_clock::time_point > GetSentWindowList(Fragment::fragment_id_t id)
Get the map of Window-mode requests fulfilled by this Fragment Geneerator for the given Fragment ID...
bool applyRequests(FragmentPtrs &frags)
See if any requests have been received, and add the corresponding data Fragment objects to the output...
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.
size_t dataBufferFragmentCount_()
Get the total number of Fragments in all data buffers.
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
void checkDataBuffers()
Perform data buffer pruning operations for all buffers.
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...
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.
void applyRequestsSequenceIDMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode SequenceID. Precondition: dataBufferMutex_ and re...
size_t ev_counter() const
Get the current value of the event counter.
fhicl::Atom< bool > request_windows_are_unique
"request_windows_are_unique" (Default: true) : Whether Fragments should be removed from the buffer wh...
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...
bool waitForDataBufferReady(Fragment::fragment_id_t id)
Wait for the data buffer to drain (dataBufferIsTooLarge returns false), periodically reporting status...
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.
RequestMode request_mode() const
Get the current request mode of the CommandableFragmentGenerator
uint64_t timestamp() const
Timestamp of last command.
void checkDataBuffer(Fragment::fragment_id_t id)
Perform data buffer pruning operations for the given buffer. If the RequestMode is Single...
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
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 dataBufferIsTooLarge(Fragment::fragment_id_t id)
Test the configured constraints on the data buffer.
std::pair< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetNextRequest() const
Get the next request (i.e. the request with the lowest sequence ID) to be handled by this Commandable...
int run_number() const
Get the current Run number.
std::map< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetRequests() const
Get the current requests being handled by this CommandableFragmentGenerator
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.