$treeview $search $mathjax $extrastylesheet
artdaq
v3_04_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #ifndef artdaq_Application_CommandableFragmentGenerator_hh 00002 #define artdaq_Application_CommandableFragmentGenerator_hh 00003 00004 // Socket Includes 00005 #include <arpa/inet.h> 00006 #include <netinet/in.h> 00007 #include <sys/types.h> 00008 #include <sys/socket.h> 00009 #include <unistd.h> 00010 00011 #include <atomic> 00012 #include <condition_variable> 00013 #include <mutex> 00014 #include <queue> 00015 #include <chrono> 00016 #include <array> 00017 #include <list> 00018 00019 #include "fhiclcpp/fwd.h" 00020 #include "fhiclcpp/ParameterSet.h" 00021 00022 #include "artdaq/DAQdata/Globals.hh" 00023 #include "artdaq-core/Data/Fragment.hh" 00024 #include "artdaq-core/Generators/FragmentGenerator.hh" 00025 #include "artdaq-utilities/Plugins/MetricManager.hh" 00026 #include "artdaq/DAQrate/RequestReceiver.hh" 00027 00028 namespace artdaq 00029 { 00033 enum class RequestMode 00034 { 00035 Single, 00036 Buffer, 00037 Window, 00038 Ignored 00039 }; 00040 00083 class CommandableFragmentGenerator : public FragmentGenerator 00084 { 00085 public: 00089 struct Config 00090 { 00092 fhicl::Atom<std::string> generator_type { fhicl::Name{"generator" }, fhicl::Comment{"Name of the CommandableFragmentGenerator plugin to load"} }; 00094 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 }; 00096 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 }; 00098 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 }; 00100 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) }; 00102 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 }; 00104 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 }; 00106 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 }; 00108 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 }; 00110 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 }; 00112 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 }; 00114 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 }; 00116 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 }; 00118 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 }; 00120 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 }; 00122 fhicl::Atom<int> board_id { fhicl::Name{"board_id" }, fhicl::Comment{"The identification number for this CommandableFragmentGenerator"} }; 00125 fhicl::Sequence<Fragment::fragment_id_t> fragment_ids { fhicl::Name("fragment_ids" ), fhicl::Comment("A list of Fragment IDs created by this CommandableFragmentGenerator") }; 00128 fhicl::Atom<int> fragment_id { fhicl::Name{"fragment_id" }, fhicl::Comment{"The Fragment ID created by this CommandableFragmentGenerator"}, -99 }; 00130 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 }; 00138 fhicl::Atom<std::string> request_mode { fhicl::Name{"request_mode" }, fhicl::Comment{"The mode by which the CommandableFragmentGenerator will process reqeusts"}, "ignored" }; 00139 fhicl::TableFragment<artdaq::RequestReceiver::Config> receiverConfig; 00140 }; 00142 using Parameters = fhicl::WrappedTable<Config>; 00143 00149 CommandableFragmentGenerator(); 00150 00155 explicit CommandableFragmentGenerator(const fhicl::ParameterSet& ps); 00156 00162 virtual ~CommandableFragmentGenerator(); 00163 00164 00171 void joinThreads(); 00172 00178 bool getNext(FragmentPtrs& output) override final; 00179 00180 00186 void applyRequestsIgnoredMode(artdaq::FragmentPtrs& frags); 00187 00193 void applyRequestsSingleMode(artdaq::FragmentPtrs& frags); 00194 00200 void applyRequestsBufferMode(artdaq::FragmentPtrs& frags); 00201 00207 void applyRequestsWindowMode(artdaq::FragmentPtrs& frags); 00208 00214 bool applyRequests(FragmentPtrs& frags); 00215 00223 bool sendEmptyFragment(FragmentPtrs& frags, size_t sequenceId, std::string desc); 00224 00231 void sendEmptyFragments(FragmentPtrs& frags, std::map<Fragment::sequence_id_t, Fragment::timestamp_t>& requests); 00232 00237 void checkOutOfOrderWindows(Fragment::sequence_id_t seq); 00238 00243 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> getOutOfOrderWindowList() const 00244 { 00245 return windows_sent_ooo_; 00246 } 00247 00251 void startDataThread(); 00252 00256 void startMonitoringThread(); 00257 00262 void getDataLoop(); 00263 00268 bool waitForDataBufferReady(); 00269 00274 bool dataBufferIsTooLarge(); 00275 00279 void getDataBufferStats(); 00280 00286 void checkDataBuffer(); 00287 00291 void getMonitoringDataLoop(); 00292 00297 std::vector<Fragment::fragment_id_t> fragmentIDs() override 00298 { 00299 return fragment_ids_; 00300 } 00301 00306 size_t ev_counter() const { return ev_counter_.load(); } 00307 00312 RequestMode request_mode() const { return mode_; } 00313 00314 // 00315 // State-machine related interface below. 00316 // 00317 00332 void StartCmd(int run, uint64_t timeout, uint64_t timestamp); 00333 00343 void StopCmd(uint64_t timeout, uint64_t timestamp); 00344 00354 void PauseCmd(uint64_t timeout, uint64_t timestamp); 00355 00364 void ResumeCmd(uint64_t timeout, uint64_t timestamp); 00365 00376 std::string ReportCmd(std::string const& which = ""); 00377 00382 virtual std::string metricsReportingInstanceName() const 00383 { 00384 return instance_name_for_metrics_; 00385 } 00386 00387 // The following functions are not yet implemented, and their 00388 // signatures may be subject to change. 00389 00390 // John F., 12/6/13 -- do we want Reset and Shutdown commands? 00391 // Kurt B., 15-Feb-2014. For the moment, I suspect that we don't 00392 // want a Shutdown command. FragmentGenerator instances are 00393 // Constructed at Initialization time, and they are destructed 00394 // at Shutdown time. So, any shutdown operations that need to be 00395 // done should be put in the FragmentGenerator child class 00396 // destructors. If we find that want shutdown (or initialization) 00397 // operations that are different from destruction (construction), 00398 // then we'll have to add InitCmd and ShutdownCmd methods. 00399 00400 // virtual void ResetCmd() final {} 00401 // virtual void ShutdownCmd() final {} 00402 00407 bool exception() const { return exception_.load(); } 00408 00409 00416 virtual bool metaCommand(std::string const& command, std::string const& arg); 00417 00418 protected: 00419 00420 // John F., 12/6/13 -- need to figure out which of these getter 00421 // functions should be promoted to "public" 00422 00423 // John F., 1/21/15 -- after more than a year, there hasn't been a 00424 // single complaint that a CommandableFragmentGenerator-derived 00425 // class hasn't allowed its users to access these quantities, so 00426 // they're probably fine as is 00427 00432 int run_number() const { return run_number_; } 00437 int subrun_number() const { return subrun_number_; } 00442 uint64_t timeout() const { return timeout_; } 00447 uint64_t timestamp() const { return timestamp_; } 00448 00453 bool should_stop() const { return should_stop_.load(); } 00454 00459 bool check_stop(); 00460 00465 int board_id() const { return board_id_; } 00466 00472 int fragment_id() const; 00473 00480 size_t ev_counter_inc(size_t step = 1, bool force = false); // returns the prev value 00481 00486 void set_exception(bool exception) { exception_.store(exception); } 00487 00492 void metricsReportingInstanceName(std::string const& name) 00493 { 00494 instance_name_for_metrics_ = name; 00495 } 00496 00501 std::string printMode_(); 00502 00503 // John F., 12/10/13 00504 // Is there a better way to handle mutex_ than leaving it a protected variable? 00505 00506 // John F., 1/21/15 00507 // Translation above is "should mutex_ be a private variable, 00508 // accessible via a getter function". Probably, but at this point 00509 // it's not worth breaking code by implementing this. 00510 00511 std::mutex mutex_; 00512 00513 private: 00514 // FHiCL-configurable variables. Note that the C++ variable names 00515 // are the FHiCL variable names with a "_" appended 00516 00517 //Socket parameters 00518 std::unique_ptr<RequestReceiver> requestReceiver_; 00519 00520 RequestMode mode_; 00521 Fragment::timestamp_t windowOffset_; 00522 Fragment::timestamp_t windowWidth_; 00523 Fragment::timestamp_t staleTimeout_; 00524 Fragment::type_t expectedType_; 00525 size_t maxFragmentCount_; 00526 bool uniqueWindows_; 00527 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> windows_sent_ooo_; 00528 size_t missing_request_window_timeout_us_; 00529 size_t window_close_timeout_us_; 00530 00531 bool useDataThread_; 00532 bool circularDataBufferMode_; 00533 size_t sleep_on_no_data_us_; 00534 std::atomic<bool> data_thread_running_; 00535 boost::thread dataThread_; 00536 00537 std::condition_variable dataCondition_; 00538 std::atomic<int> dataBufferDepthFragments_; 00539 std::atomic<size_t> dataBufferDepthBytes_; 00540 int maxDataBufferDepthFragments_; 00541 size_t maxDataBufferDepthBytes_; 00542 00543 bool useMonitoringThread_; 00544 boost::thread monitoringThread_; 00545 int64_t monitoringInterval_; // Microseconds 00546 std::chrono::steady_clock::time_point lastMonitoringCall_; 00547 std::atomic<bool> isHardwareOK_; 00548 00549 FragmentPtrs dataBuffer_; 00550 FragmentPtrs newDataBuffer_; 00551 std::mutex dataBufferMutex_; 00552 00553 std::vector<artdaq::Fragment::fragment_id_t> fragment_ids_; 00554 00555 // In order to support the state-machine related behavior, all 00556 // CommandableFragmentGenerators must be able to remember a run number and a 00557 // subrun number. 00558 int run_number_, subrun_number_; 00559 00560 // JCF, 8/28/14 00561 00562 // Provide a user-adjustable timeout for the start transition 00563 uint64_t timeout_; 00564 00565 // JCF, 8/21/14 00566 00567 // In response to a need to synchronize various components using 00568 // different fragment generators in an experiment, keep a record 00569 // of a timestamp (see Redmine Issue #6783 for more) 00570 00571 uint64_t timestamp_; 00572 00573 std::atomic<bool> should_stop_, exception_, force_stop_; 00574 std::string latest_exception_report_; 00575 std::atomic<size_t> ev_counter_; 00576 00577 int board_id_; 00578 std::string instance_name_for_metrics_; 00579 00580 // Depending on what sleep_on_stop_us_ is set to, this gives the 00581 // stopping thread the chance to gather the required lock 00582 00583 int sleep_on_stop_us_; 00584 00585 protected: 00586 00594 virtual bool getNext_(FragmentPtrs& output) = 0; 00595 00596 00603 virtual bool checkHWStatus_(); 00604 00605 // 00606 // State-machine related implementor interface below. 00607 // 00608 00619 virtual void start() = 0; 00620 00627 virtual void stopNoMutex() = 0; 00628 00637 virtual void stop() = 0; 00638 00643 virtual void pauseNoMutex(); 00644 00650 virtual void pause(); 00651 00655 virtual void resume(); 00656 00668 virtual std::string report(); 00669 00675 virtual std::string reportSpecific(std::string const& what); 00676 00677 }; 00678 } 00679 00680 #endif /* artdaq_Application_CommandableFragmentGenerator_hh */