00001
00002
00003
00004
00005
00006
00007
00009
00010 #define TRACE_NAME "RandomDelayFilter"
00011
00012 #include "art/Framework/Core/EDFilter.h"
00013 #include "art/Framework/Core/ModuleMacros.h"
00014 #include "art/Framework/Principal/Event.h"
00015 #include "art/Framework/Principal/Handle.h"
00016 #include "art/Framework/Principal/Run.h"
00017 #include "art/Framework/Principal/SubRun.h"
00018 #include "canvas/Utilities/InputTag.h"
00019 #include "fhiclcpp/ParameterSet.h"
00020
00021 #include "artdaq/DAQdata/Globals.hh"
00022
00023 #include <memory>
00024 #include <random>
00025 #include <chrono>
00026
00027 namespace artdaq
00028 {
00029 class RandomDelayFilter;
00030 }
00031
00039 class artdaq::RandomDelayFilter : public art::EDFilter
00040 {
00041 public:
00056 explicit RandomDelayFilter(fhicl::ParameterSet const& p);
00057
00061 RandomDelayFilter(RandomDelayFilter const&) = delete;
00062
00066 RandomDelayFilter(RandomDelayFilter&&) = delete;
00067
00072 RandomDelayFilter& operator=(RandomDelayFilter const&) = delete;
00073
00078 RandomDelayFilter& operator=(RandomDelayFilter&&) = delete;
00079
00089 bool filter(art::Event& e) override;
00090
00091 private:
00092
00093 double min_ms_;
00094 double max_ms_;
00095 double mean_ms_;
00096 double sigma_ms_;
00097
00098 int pass_factor_;
00099 double load_factor_;
00100
00101
00102 std::mt19937 engine_;
00103 std::unique_ptr<std::uniform_real_distribution<double>> uniform_distn_;
00104 std::unique_ptr<std::normal_distribution<double>> normal_distn_;
00105 std::unique_ptr<std::exponential_distribution<double>> exponential_distn_;
00106 std::unique_ptr<std::uniform_int_distribution<int>> pass_distn_;
00107
00108 enum class DistType {
00109 Fixed,
00110 Uniform,
00111 Normal,
00112 Exponential
00113 };
00114 DistType distribution_type_;
00115 };
00116
00117
00118 artdaq::RandomDelayFilter::RandomDelayFilter(fhicl::ParameterSet const& p)
00119 : min_ms_(p.get<double>("minimum_delay_ms", 0))
00120 , max_ms_(p.get<double>("maximum_delay_ms", 1000))
00121 , mean_ms_(p.get<double>("mean_delay_ms", 500))
00122 , sigma_ms_(p.get<double>("sigma_delay_ms", 100))
00123 , pass_factor_(p.get<int>("pass_filter_percentage", 100))
00124 , load_factor_(p.get<double>("cpu_load_ratio", 0.5))
00125 , engine_(p.get<int64_t>("random_seed", time(0)))
00126 , pass_distn_(new std::uniform_int_distribution<int>(0, 100))
00127 {
00128
00129 if (pass_factor_ > 100) pass_factor_ = 100;
00130 if (pass_factor_ < 0) pass_factor_ = 0;
00131 if (load_factor_ < 0.0) load_factor_ = 0.0;
00132 if (load_factor_ > 1.0) load_factor_ = 1.0;
00133
00134 if (min_ms_ < 0) min_ms_ = 0;
00135 if (min_ms_ > max_ms_) max_ms_ = min_ms_;
00136 if (mean_ms_ < 0) mean_ms_ = 0;
00137 if (sigma_ms_ < 0) sigma_ms_ = 0;
00138
00139 auto type = p.get<std::string>("distribution_type", "Uniform");
00140 assert(type.size() >= 1);
00141 switch (type[0])
00142 {
00143 case 'n':
00144 case 'N':
00145 TLOG(TLVL_INFO) << "Generating delay times using Normal distribution with mean " << mean_ms_ << " ms, std. dev. " << sigma_ms_ << " ms, min " << min_ms_ << " ms and max " << max_ms_ << "ms.";
00146 distribution_type_ = DistType::Normal;
00147 if(mean_ms_ < min_ms_) {
00148 TLOG(TLVL_WARNING) << "Mean is smaller than min, setting to min";
00149 mean_ms_ = min_ms_;
00150 }
00151 mean_ms_ -= min_ms_;
00152 normal_distn_.reset(new std::normal_distribution<double>(mean_ms_, sigma_ms_));
00153 break;
00154 case 'e':
00155 case 'E':
00156 TLOG(TLVL_INFO) << "Generating delay times using Exponential distribution with mean " << mean_ms_ << " ms, min " << min_ms_ << " ms and max " << max_ms_ << " ms.";
00157 distribution_type_ = DistType::Exponential;
00158 if(mean_ms_ < min_ms_) {
00159 TLOG(TLVL_WARNING) << "Mean is smaller than min, setting to min";
00160 mean_ms_ = min_ms_;
00161 }
00162 mean_ms_ -= min_ms_;
00163 if (mean_ms_ == 0) mean_ms_ = 1;
00164 exponential_distn_.reset(new std::exponential_distribution<double>(1/mean_ms_));
00165 break;
00166 case 'U':
00167 case 'u':
00168 TLOG(TLVL_INFO) << "Generating delay times using Uniform distribution with min " << min_ms_ << " ms and max " << max_ms_ << " ms.";
00169 distribution_type_ = DistType::Uniform;
00170 uniform_distn_.reset(new std::uniform_real_distribution<double>(min_ms_, max_ms_));
00171 break;
00172 case 'f':
00173 case 'F':
00174 default:
00175 TLOG(TLVL_INFO) << "Delay time set to " << min_ms_ << " ms.";
00176 distribution_type_ = DistType::Fixed;
00177 break;
00178 }
00179 }
00180
00181 bool artdaq::RandomDelayFilter::filter(art::Event& e)
00182 {
00183 double delay = min_ms_;
00184 do {
00185 switch (distribution_type_)
00186 {
00187 case DistType::Normal:
00188 delay += (*normal_distn_)(engine_);
00189 break;
00190 case DistType::Exponential:
00191 delay += (*exponential_distn_)(engine_);
00192 break;
00193 case DistType::Uniform:
00194 delay = (*uniform_distn_)(engine_);
00195 break;
00196 case DistType::Fixed:
00197 break;
00198 }
00199 } while(delay > max_ms_ && delay < min_ms_);
00200 TLOG(TLVL_DEBUG) << "Simulating processing of event " << e.event() << " by delaying " << delay << "ms." ;
00201
00202 usleep(1000 * (1 - load_factor_) * delay);
00203
00204 auto i = 0;
00205 auto now = std::chrono::steady_clock::now();
00206 while (TimeUtils::GetElapsedTimeMilliseconds(now) < static_cast<size_t>(delay * load_factor_))
00207 {
00208 i = i + 1 % std::numeric_limits<int>::max();
00209 }
00210
00211 return (*pass_distn_)(engine_) < pass_factor_;
00212 }
00213
00214 DEFINE_ART_MODULE(artdaq::RandomDelayFilter)