00001 #ifndef artdaq_Application_CommandableFragmentGenerator_hh
00002 #define artdaq_Application_CommandableFragmentGenerator_hh
00003
00004
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{"How long should request messages be retained"}, 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<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 };
00112 fhicl::Atom<int> data_buffer_depth_fragments { fhicl::Name{"data_buffer_depth_fragments" }, fhicl::Comment{"How many Fragments to store in the buffer"}, 1000 };
00114 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 };
00116 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 };
00118 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 };
00120 fhicl::Atom<int> board_id { fhicl::Name{"board_id" }, fhicl::Comment{"The identification number for this CommandableFragmentGenerator"} };
00123 fhicl::Sequence<Fragment::fragment_id_t> fragment_ids { fhicl::Name("fragment_ids" ), fhicl::Comment("A list of Fragment IDs created by this CommandableFragmentGenerator") };
00126 fhicl::Atom<int> fragment_id { fhicl::Name{"fragment_id" }, fhicl::Comment{"The Fragment ID created by this CommandableFragmentGenerator"}, -99 };
00128 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 };
00136 fhicl::Atom<std::string> request_mode { fhicl::Name{"request_mode" }, fhicl::Comment{"The mode by which the CommandableFragmentGenerator will process reqeusts"}, "ignored" };
00137 fhicl::TableFragment<artdaq::RequestReceiver::Config> receiverConfig;
00138 };
00139 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
00140 using Parameters = fhicl::WrappedTable<Config>;
00141 #endif
00142
00147 CommandableFragmentGenerator();
00148
00153 explicit CommandableFragmentGenerator(const fhicl::ParameterSet& ps);
00154
00160 virtual ~CommandableFragmentGenerator();
00161
00162
00169 void joinThreads();
00170
00176 bool getNext(FragmentPtrs& output) override final;
00177
00178
00184 void applyRequestsIgnoredMode(artdaq::FragmentPtrs& frags);
00185
00191 void applyRequestsSingleMode(artdaq::FragmentPtrs& frags);
00192
00198 void applyRequestsBufferMode(artdaq::FragmentPtrs& frags);
00199
00205 void applyRequestsWindowMode(artdaq::FragmentPtrs& frags);
00206
00212 bool applyRequests(FragmentPtrs& output);
00213
00221 bool sendEmptyFragment(FragmentPtrs& frags, size_t sequenceId, std::string desc);
00222
00229 void sendEmptyFragments(FragmentPtrs& frags, std::map<Fragment::sequence_id_t, Fragment::timestamp_t>& requests);
00230
00235 void checkOutOfOrderWindows(Fragment::sequence_id_t seq);
00236
00241 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> getOutOfOrderWindowList() const
00242 {
00243 return windows_sent_ooo_;
00244 }
00245
00249 void startDataThread();
00250
00254 void startMonitoringThread();
00255
00260 void getDataLoop();
00261
00266 bool waitForDataBufferReady();
00267
00272 bool dataBufferIsTooLarge();
00273
00277 void getDataBufferStats();
00278
00284 void checkDataBuffer();
00285
00289 void getMonitoringDataLoop();
00290
00295 std::vector<Fragment::fragment_id_t> fragmentIDs() override
00296 {
00297 return fragment_ids_;
00298 }
00299
00304 size_t ev_counter() const { return ev_counter_.load(); }
00305
00310 RequestMode request_mode() const { return mode_; }
00311
00312
00313
00314
00315
00330 void StartCmd(int run, uint64_t timeout, uint64_t timestamp);
00331
00341 void StopCmd(uint64_t timeout, uint64_t timestamp);
00342
00352 void PauseCmd(uint64_t timeout, uint64_t timestamp);
00353
00362 void ResumeCmd(uint64_t timeout, uint64_t timestamp);
00363
00374 std::string ReportCmd(std::string const& which = "");
00375
00380 virtual std::string metricsReportingInstanceName() const
00381 {
00382 return instance_name_for_metrics_;
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00405 bool exception() const { return exception_.load(); }
00406
00407
00414 virtual bool metaCommand(std::string const& command, std::string const& arg);
00415
00416 protected:
00417
00418
00419
00420
00421
00422
00423
00424
00425
00430 int run_number() const { return run_number_; }
00435 int subrun_number() const { return subrun_number_; }
00440 uint64_t timeout() const { return timeout_; }
00445 uint64_t timestamp() const { return timestamp_; }
00446
00451 bool should_stop() const { return should_stop_.load(); }
00452
00457 bool check_stop();
00458
00463 int board_id() const { return board_id_; }
00464
00470 int fragment_id() const;
00471
00478 size_t ev_counter_inc(size_t step = 1, bool force = false);
00479
00484 void set_exception(bool exception) { exception_.store(exception); }
00485
00490 void metricsReportingInstanceName(std::string const& name)
00491 {
00492 instance_name_for_metrics_ = name;
00493 }
00494
00499 std::string printMode_();
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 std::mutex mutex_;
00510
00511 private:
00512
00513
00514
00515
00516 std::unique_ptr<RequestReceiver> requestReceiver_;
00517
00518 RequestMode mode_;
00519 Fragment::timestamp_t windowOffset_;
00520 Fragment::timestamp_t windowWidth_;
00521 Fragment::timestamp_t staleTimeout_;
00522 Fragment::type_t expectedType_;
00523 size_t maxFragmentCount_;
00524 bool uniqueWindows_;
00525 std::map<Fragment::sequence_id_t, std::chrono::steady_clock::time_point> windows_sent_ooo_;
00526 size_t missing_request_window_timeout_us_;
00527 size_t window_close_timeout_us_;
00528
00529 bool useDataThread_;
00530 size_t sleep_on_no_data_us_;
00531 std::atomic<bool> data_thread_running_;
00532 boost::thread dataThread_;
00533
00534 std::condition_variable dataCondition_;
00535 std::atomic<int> dataBufferDepthFragments_;
00536 std::atomic<size_t> dataBufferDepthBytes_;
00537 int maxDataBufferDepthFragments_;
00538 size_t maxDataBufferDepthBytes_;
00539
00540 bool useMonitoringThread_;
00541 boost::thread monitoringThread_;
00542 int64_t monitoringInterval_;
00543 std::chrono::steady_clock::time_point lastMonitoringCall_;
00544 bool isHardwareOK_;
00545
00546 FragmentPtrs dataBuffer_;
00547 FragmentPtrs newDataBuffer_;
00548 std::mutex dataBufferMutex_;
00549
00550 std::vector<artdaq::Fragment::fragment_id_t> fragment_ids_;
00551
00552
00553
00554
00555 int run_number_, subrun_number_;
00556
00557
00558
00559
00560 uint64_t timeout_;
00561
00562
00563
00564
00565
00566
00567
00568 uint64_t timestamp_;
00569
00570 std::atomic<bool> should_stop_, exception_, force_stop_;
00571 std::string latest_exception_report_;
00572 std::atomic<size_t> ev_counter_;
00573
00574 int board_id_;
00575 std::string instance_name_for_metrics_;
00576
00577
00578
00579
00580 int sleep_on_stop_us_;
00581
00582 protected:
00583
00591 virtual bool getNext_(FragmentPtrs& output) = 0;
00592
00593
00600 virtual bool checkHWStatus_();
00601
00602
00603
00604
00605
00616 virtual void start() = 0;
00617
00624 virtual void stopNoMutex() = 0;
00625
00634 virtual void stop() = 0;
00635
00640 virtual void pauseNoMutex();
00641
00647 virtual void pause();
00648
00652 virtual void resume();
00653
00665 virtual std::string report();
00666
00672 virtual std::string reportSpecific(std::string const& what);
00673
00674 };
00675 }
00676
00677 #endif