1 #ifndef artdaq_Application_FragmentBuffer_hh
2 #define artdaq_Application_FragmentBuffer_hh
4 #include "fhiclcpp/types/Sequence.h"
6 #include "TRACE/tracemf.h"
7 #include "artdaq-core/Data/Fragment.hh"
9 #include "artdaq/DAQrate/RequestBuffer.hh"
14 #include "fhiclcpp/types/Atom.h"
15 #include "fhiclcpp/types/Comment.h"
16 #include "fhiclcpp/types/ConfigurationTable.h"
17 #include "fhiclcpp/types/Name.h"
20 #include <arpa/inet.h>
21 #include <netinet/in.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
29 #include <condition_variable>
98 fhicl::Atom<std::string>
generator_type{fhicl::Name{
"generator"}, fhicl::Comment{
"Name of the FragmentBuffer plugin to load"}};
100 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};
102 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};
104 fhicl::Atom<Fragment::timestamp_t>
stale_fragment_timeout{fhicl::Name{
"stale_fragment_timeout"}, fhicl::Comment{
"Fragments stored in the fragment generator which are older than the newest stored fragment by at least stale_fragment_timeout units of request timestamp ticks will get discarded"}, 0};
106 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};
108 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)};
110 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};
112 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};
114 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};
116 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};
118 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};
120 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};
122 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};
124 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};
126 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};
128 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};
130 fhicl::Atom<int>
board_id{fhicl::Name{
"board_id"}, fhicl::Comment{
"The identification number for this FragmentBuffer"}};
133 fhicl::Sequence<Fragment::fragment_id_t>
fragment_ids{fhicl::Name(
"fragment_ids"), fhicl::Comment(
"A list of Fragment IDs created by this FragmentBuffer")};
136 fhicl::Atom<int>
fragment_id{fhicl::Name{
"fragment_id"}, fhicl::Comment{
"The Fragment ID created by this FragmentBuffer"}, -99};
138 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};
147 fhicl::Atom<std::string>
request_mode{fhicl::Name{
"request_mode"}, fhicl::Comment{
"The mode by which the FragmentBuffer will process reqeusts"},
"ignored"};
174 void Stop() { should_stop_ =
true; }
180 void Reset(
bool stop);
240 bool sendEmptyFragment(FragmentPtrs& frags,
size_t sequenceId, Fragment::fragment_id_t fragmentId, std::string desc);
248 void sendEmptyFragments(FragmentPtrs& frags, std::map<Fragment::sequence_id_t, Fragment::timestamp_t>& requests);
312 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point>
GetSentWindowList(Fragment::fragment_id_t
id)
314 if (!dataBuffers_.count(
id))
316 throw cet::exception(
"DataBufferError") <<
"Error in FragmentBuffer: Cannot get Sent Windows for ID " <<
id <<
" because it does not exist!";
319 return dataBuffers_[id]->WindowsSent;
328 std::vector<Fragment::fragment_id_t> output;
330 for (
auto&
id : dataBuffers_)
332 output.push_back(
id.first);
388 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!";
389 return (*dataBuffers_.begin()).first;
415 Fragment::sequence_id_t next_sequence_id_;
416 std::shared_ptr<RequestBuffer> requestBuffer_;
419 bool bufferModeKeepLatest_;
420 Fragment::timestamp_t windowOffset_;
421 Fragment::timestamp_t windowWidth_;
422 Fragment::timestamp_t staleTimeout_;
423 Fragment::type_t expectedType_;
425 bool sendMissingFragments_;
426 size_t missing_request_window_timeout_us_;
427 size_t window_close_timeout_us_;
428 bool error_on_empty_;
430 bool circularDataBufferMode_;
432 std::mutex dataConditionMutex_;
433 std::condition_variable dataCondition_;
434 int maxDataBufferDepthFragments_;
435 size_t maxDataBufferDepthBytes_;
439 std::atomic<int> DataBufferDepthFragments;
440 std::atomic<size_t> DataBufferDepthBytes;
441 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> WindowsSent;
442 bool BufferFragmentKept;
443 Fragment::sequence_id_t HighestRequestSeen;
444 FragmentPtrs DataBuffer;
445 std::mutex DataBufferMutex;
448 std::mutex systemFragmentMutex_;
449 FragmentPtrs systemFragments_;
450 std::atomic<size_t> systemFragmentCount_;
452 std::unordered_map<artdaq::Fragment::fragment_id_t, std::shared_ptr<DataBuffer>> dataBuffers_;
454 std::atomic<bool> should_stop_;
void AddFragmentsToBuffer(FragmentPtrs frags)
Add Fragments to the FragmentBuffer.
void checkDataBuffers()
Perform data buffer pruning operations for all buffers.
void getDataBuffersStats()
Calculate the size of all dataBuffers and report appropriate metrics.
RequestMode
The RequestMode enumeration contains the possible ways which FragmentBuffer responds to data requests...
fhicl::Atom< size_t > data_buffer_depth_mb
"data_buffer_depth_mb" (Default: 1000) : The max cumulative size in megabytes of the fragments which ...
size_t dataBufferFragmentCount_()
Get the total number of Fragments in all data buffers.
std::string printMode_()
Return the string representation of the current RequestMode.
bool applyRequests(FragmentPtrs &frags)
See if any requests have been received, and add the corresponding data Fragment objects to the output...
void SetRequestBuffer(std::shared_ptr< RequestBuffer > buffer)
Set the pointer to the RequestBuffer used to retrieve requests.
FragmentBuffer(const fhicl::ParameterSet &ps)
FragmentBuffer Constructor.
bool waitForDataBufferReady(Fragment::fragment_id_t id)
Wait for the data buffer to drain (dataBufferIsTooLarge returns false), periodically reporting status...
std::vector< Fragment::fragment_id_t > fragmentIDs()
Get the list of Fragment IDs handled by this FragmentBuffer.
fhicl::Atom< Fragment::timestamp_t > request_window_offset
"request_window_offset" (Default: 0) : Request messages contain a timestamp. For Window request mode...
fhicl::Atom< std::string > generator_type
"generator" (REQUIRED) Name of the FragmentBuffer plugin to load
fhicl::Atom< int > sleep_on_stop_us
"sleep_on_stop_us" (Default: 0) : How long to sleep before returning when stop transition is called ...
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< bool > request_windows_are_unique
"request_windows_are_unique" (Default: true) : Whether Fragments should be removed from the buffer wh...
fhicl::Atom< bool > separate_data_thread
"separate_data_thread" (Default: false) : Whether data collection should proceed on its own thread...
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...
fhicl::Atom< Fragment::timestamp_t > request_window_width
"request_window_width" (Default: 0) : For Window request mode, the window will be timestamp - offset ...
void applyRequestsIgnoredMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Ignored. Precondition: dataBufferMutex_ and reque...
fhicl::Atom< bool > separate_monitoring_thread
"separate_monitoring_thread" (Default: false) : Whether a thread that calls the checkHWStatus_ method...
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 > missing_request_window_timeout_us
"missing_request_window_timeout_us" (Default: 5000000) : How long to track missing requests in the "o...
void applyRequestsWindowMode_CheckAndFillDataBuffer(artdaq::FragmentPtrs &frags, artdaq::Fragment::fragment_id_t id, artdaq::Fragment::sequence_id_t seq, artdaq::Fragment::timestamp_t ts)
bool check_stop()
Routine used by applyRequests to make sure that all outstanding requests have been fulfilled before r...
void Stop()
Inform the FragmentBuffer that it should stop.
void Reset(bool stop)
Reset the FragmentBuffer (flushes all Fragments from buffers)
fhicl::Atom< Fragment::type_t > expected_fragment_type
"expected_fragment_type" (Default: 231, EmptyFragmentType) : The type of Fragments this CFG will be g...
artdaq::Fragment::sequence_id_t GetNextSequenceID() const
Get the next sequence ID expected by this FragmentBuffer. This is used to track sent windows and miss...
FragmentBuffer is a FragmentGenerator-derived abstract class that defines the interface for a Fragmen...
fhicl::Atom< int > data_buffer_depth_fragments
"data_buffer_depth_fragments" (Default: 1000) : The max fragments which can be stored before dropping...
void checkSentWindows(Fragment::sequence_id_t seq)
Check the windows_sent_ooo_ map for sequence IDs that may be removed.
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_
Configuration of the FragmentBuffer. May be used for parameter validation
artdaq::Fragment::fragment_id_t fragment_id() const
Get the Fragment ID of this Fragment generator.
void checkDataBuffer(Fragment::fragment_id_t id)
Perform data buffer pruning operations for the given buffer. If the RequestMode is Single...
bool dataBufferIsTooLarge(Fragment::fragment_id_t id)
Test the configured constraints on the data buffer.
fhicl::Atom< std::string > request_mode
"request_mode" (Deafult: Ignored) : The mode by which the FragmentBuffer will process reqeusts Ignore...
bool sendEmptyFragment(FragmentPtrs &frags, size_t sequenceId, Fragment::fragment_id_t fragmentId, std::string desc)
Send an EmptyFragmentType Fragment.
void applyRequestsBufferMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Buffer. Precondition: dataBufferMutex_ and reques...
void applyRequestsWindowMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Window. Precondition: dataBufferMutex_ and reques...
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
virtual ~FragmentBuffer()
FragmentBuffer Destructor.
fhicl::Atom< int > fragment_id
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 ...
fhicl::Atom< bool > buffer_mode_keep_latest
"buffer_mode_keep_latest" (Default: false): Keep the latest Fragment when running in Buffer mode...
std::string getStatReport()
report statistics as a string
fhicl::Atom< int > board_id
"board_id" (REQUIRED) : The identification number for this FragmentBuffer
fhicl::Atom< Fragment::timestamp_t > stale_fragment_timeout
"stale_fragment_timeout" (Default: 0) : Fragments stored in the fragment generator which are older th...
fhicl::Sequence< Fragment::fragment_id_t > fragment_ids
RequestMode request_mode() const
Get the current request mode of the FragmentBuffer
void applyRequestsSequenceIDMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode SequenceID. Precondition: dataBufferMutex_ and re...
fhicl::Atom< bool > circular_buffer_mode
"circular_buffer_mode" (Default: false) : Whether the data buffer should be treated as a circular buf...
void applyRequestsSingleMode(artdaq::FragmentPtrs &frags)
Create fragments using data buffer for request mode Single. Precondition: dataBufferMutex_ and reques...
void getDataBufferStats(Fragment::fragment_id_t id)
Calculate the size of the dataBuffer and report appropriate metrics.