Line data Source code
1 : ////////////////////////////////////////////////////////////////////////
2 : // Class: RandomDelayFilter
3 : // Module Type: filter
4 : // File: RandomDelayFilter_module.cc
5 : //
6 : // Generated at Fri Mar 4 10:45:30 2016 by Eric Flumerfelt using artmod
7 : // from cetpkgsupport v1_09_00.
8 : ////////////////////////////////////////////////////////////////////////
9 :
10 : #include "TRACE/tracemf.h"
11 : #define TRACE_NAME "RandomDelayFilter"
12 :
13 : #include "artdaq-core/Utilities/TimeUtils.hh"
14 :
15 : #include "art/Framework/Core/EDFilter.h"
16 : #include "art/Framework/Core/ModuleMacros.h"
17 : #include "art/Framework/Principal/Event.h"
18 : #include "art/Framework/Principal/Handle.h"
19 : #include "art/Framework/Principal/Run.h"
20 : #include "art/Framework/Principal/SubRun.h"
21 : #include "canvas/Utilities/InputTag.h"
22 : #include "fhiclcpp/ParameterSet.h"
23 :
24 : #include <chrono>
25 : #include <memory>
26 : #include <random>
27 :
28 : namespace artdaq {
29 : class RandomDelayFilter;
30 : }
31 :
32 : /**
33 : * \brief A filter which delays for a random amount of time, then
34 : * drops a random fraction of events. Used to simulate the delays
35 : * and efficiency of real filters.
36 : *
37 : * Multiple RandomDelayFilters in series can simulate the effect of multiple layers of filtering
38 : */
39 : class artdaq::RandomDelayFilter : public art::EDFilter
40 : {
41 : public:
42 : /**
43 : * \brief RandomDelayFilter Constructor
44 : * \param p ParameterSet used to confgure RandomDelayFilter
45 : *
46 : * RandomDelayFilter accepts the following Parametrs:
47 : * "minimum_delay_ms" (Default: 0): The minimum amount of time to delay, in ms
48 : * "maximum_delay_ms" (Default: 1000): The maximum amount of time to delay, in ms
49 : * "mean_delay_ms" (Default: 500): If using a non-uniform distribution for delay times, the mean of the distribution, in ms (This value will be used for Fixed delays)
50 : * "sigma_delay_ms" (Default: 100): If using a Normal distribution for delay times, the sigma of the distribution, in ms
51 : * "pass_filter_percentage" (Default: 100): The fraction of events which will pass the filter
52 : * "distribution_type" (Default: "Uniform"): The distribution to sample for delays (Uniform, Normal, Exponential, Fixed)
53 : * "cpu_load_ratio" (Default: 0.5): The fraction of the delay time which should be active (spinning) versis passive (sleeping)
54 : * "random_seed" (Default: time(0)): The seed for the ditribution
55 : */
56 : explicit RandomDelayFilter(fhicl::ParameterSet const& p);
57 :
58 0 : ~RandomDelayFilter() override = default;
59 :
60 : /**
61 : * \brief Copy Constructor is deleted
62 : */
63 : RandomDelayFilter(RandomDelayFilter const&) = delete;
64 :
65 : /**
66 : * \brief Move Constructor is deleted
67 : */
68 : RandomDelayFilter(RandomDelayFilter&&) = delete;
69 :
70 : /**
71 : * \brief Copy Assignment operator is deleted
72 : * \return RandomDelayFilter copy
73 : */
74 : RandomDelayFilter& operator=(RandomDelayFilter const&) = delete;
75 :
76 : /**
77 : * \brief Move Assignment operator is deleted
78 : * \return RandomDelayFilter instance
79 : */
80 : RandomDelayFilter& operator=(RandomDelayFilter&&) = delete;
81 :
82 : /**
83 : * \brief Filter is a required override of art::EDFilter, and is called for each event
84 : * \param e The art::Event to filter
85 : * \return Whether the event passes the filter
86 : *
87 : * This function is where RandomDelayFilter performs its work, using the delay distribution
88 : * to pick a delay time, spinning and/or sleeping for that amount of time, then picking
89 : * an integer from the pass distribution to determine if the event should pass or not.
90 : */
91 : bool filter(art::Event& e) override;
92 :
93 : private:
94 : // Random Delay Parameters (min/max for uniform, mean/sigma for normal)
95 : double min_ms_;
96 : double max_ms_;
97 : double mean_ms_;
98 : double sigma_ms_;
99 :
100 : int pass_factor_;
101 : double load_factor_;
102 :
103 : // Random Engine Setup
104 : std::mt19937 engine_;
105 : std::unique_ptr<std::uniform_real_distribution<double>> uniform_distn_;
106 : std::unique_ptr<std::normal_distribution<double>> normal_distn_;
107 : std::unique_ptr<std::exponential_distribution<double>> exponential_distn_;
108 : std::unique_ptr<std::uniform_int_distribution<int>> pass_distn_;
109 :
110 : enum class DistType
111 : {
112 : Fixed,
113 : Uniform,
114 : Normal,
115 : Exponential
116 : };
117 : DistType distribution_type_;
118 : };
119 :
120 0 : artdaq::RandomDelayFilter::RandomDelayFilter(fhicl::ParameterSet const& p)
121 : : art::EDFilter(p)
122 0 : , min_ms_(p.get<double>("minimum_delay_ms", 0))
123 0 : , max_ms_(p.get<double>("maximum_delay_ms", 1000))
124 0 : , mean_ms_(p.get<double>("mean_delay_ms", 500))
125 0 : , sigma_ms_(p.get<double>("sigma_delay_ms", 100))
126 0 : , pass_factor_(p.get<int>("pass_filter_percentage", 100))
127 0 : , load_factor_(p.get<double>("cpu_load_ratio", 0.5))
128 0 : , engine_(p.get<int64_t>("random_seed", time(nullptr)))
129 0 : , pass_distn_(new std::uniform_int_distribution<int>(0, 100))
130 : {
131 : // Set limits on parameters
132 0 : if (pass_factor_ > 100)
133 : {
134 0 : pass_factor_ = 100;
135 : }
136 0 : if (pass_factor_ < 0)
137 : {
138 0 : pass_factor_ = 0;
139 : }
140 0 : if (load_factor_ < 0.0)
141 : {
142 0 : load_factor_ = 0.0;
143 : }
144 0 : if (load_factor_ > 1.0)
145 : {
146 0 : load_factor_ = 1.0;
147 : }
148 :
149 0 : if (min_ms_ < 0)
150 : {
151 0 : min_ms_ = 0;
152 : }
153 0 : if (min_ms_ > max_ms_)
154 : {
155 0 : max_ms_ = min_ms_;
156 : }
157 0 : if (mean_ms_ < 0)
158 : {
159 0 : mean_ms_ = 0;
160 : }
161 0 : if (sigma_ms_ < 0)
162 : {
163 0 : sigma_ms_ = 0;
164 : }
165 :
166 0 : auto type = p.get<std::string>("distribution_type", "Uniform");
167 0 : assert(!type.empty());
168 0 : switch (type[0])
169 : {
170 0 : case 'n':
171 : case 'N':
172 0 : 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.";
173 0 : distribution_type_ = DistType::Normal;
174 0 : if (mean_ms_ < min_ms_)
175 : {
176 0 : TLOG(TLVL_WARNING) << "Mean is smaller than min, setting to min";
177 0 : mean_ms_ = min_ms_;
178 : }
179 0 : mean_ms_ -= min_ms_; // When we sample the distribution, we offset by min_ms_
180 0 : normal_distn_ = std::make_unique<std::normal_distribution<double>>(mean_ms_, sigma_ms_);
181 0 : break;
182 0 : case 'e':
183 : case 'E':
184 0 : TLOG(TLVL_INFO) << "Generating delay times using Exponential distribution with mean " << mean_ms_ << " ms, min " << min_ms_ << " ms and max " << max_ms_ << " ms.";
185 0 : distribution_type_ = DistType::Exponential;
186 0 : if (mean_ms_ < min_ms_)
187 : {
188 0 : TLOG(TLVL_WARNING) << "Mean is smaller than min, setting to min";
189 0 : mean_ms_ = min_ms_;
190 : }
191 0 : mean_ms_ -= min_ms_; // When we sample the distribution, we offset by min_ms_
192 0 : if (mean_ms_ == 0)
193 : {
194 0 : mean_ms_ = 1;
195 : }
196 0 : exponential_distn_ = std::make_unique<std::exponential_distribution<double>>(1 / mean_ms_);
197 0 : break;
198 0 : case 'U':
199 : case 'u':
200 0 : TLOG(TLVL_INFO) << "Generating delay times using Uniform distribution with min " << min_ms_ << " ms and max " << max_ms_ << " ms.";
201 0 : distribution_type_ = DistType::Uniform;
202 0 : uniform_distn_ = std::make_unique<std::uniform_real_distribution<double>>(min_ms_, max_ms_);
203 0 : break;
204 0 : case 'f':
205 : case 'F':
206 : default:
207 0 : TLOG(TLVL_INFO) << "Delay time set to " << min_ms_ << " ms.";
208 0 : distribution_type_ = DistType::Fixed;
209 0 : break;
210 : }
211 0 : }
212 :
213 0 : bool artdaq::RandomDelayFilter::filter(art::Event& e)
214 : {
215 0 : double delay = min_ms_;
216 : do
217 : {
218 0 : switch (distribution_type_)
219 : {
220 0 : case DistType::Normal:
221 0 : delay += (*normal_distn_)(engine_);
222 0 : break;
223 0 : case DistType::Exponential:
224 0 : delay += (*exponential_distn_)(engine_);
225 0 : break;
226 0 : case DistType::Uniform:
227 0 : delay = (*uniform_distn_)(engine_);
228 0 : break;
229 0 : case DistType::Fixed:
230 0 : break;
231 : }
232 :
233 : // Retry if we pulled over-max
234 0 : if (delay > max_ms_) delay = min_ms_ - 1;
235 0 : } while (delay < min_ms_);
236 0 : TLOG(TLVL_DEBUG) << "Simulating processing of event " << e.event() << " by delaying " << delay << "ms.";
237 :
238 0 : usleep(static_cast<unsigned>(1000 * (1 - load_factor_) * delay));
239 :
240 0 : auto i = 0;
241 0 : auto now = std::chrono::steady_clock::now();
242 0 : while (TimeUtils::GetElapsedTimeMilliseconds(now) < static_cast<size_t>(delay * load_factor_))
243 : {
244 0 : i = i + 1 % std::numeric_limits<int>::max();
245 : }
246 :
247 0 : return (*pass_distn_)(engine_) < pass_factor_;
248 : }
249 :
250 0 : DEFINE_ART_MODULE(artdaq::RandomDelayFilter) // NOLINT(performance-unnecessary-value-param)
|