A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
windowed-filter.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016 The Chromium Authors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * Note: This code is modified to work under ns-3's environment.
33 * Modified by: Vivek Jain <jain.vivek.anand@gmail.com>
34 * Viyom Mittal <viyommittal@gmail.com>
35 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
36 */
37
38// Implements Kathleen Nichols' algorithm for tracking the minimum (or maximum)
39// estimate of a stream of samples over some fixed time interval. (E.g.,
40// the minimum RTT over the past five minutes.) The algorithm keeps track of
41// the best, second best, and third best min (or max) estimates, maintaining an
42// invariant that the measurement time of the n'th best >= n-1'th best.
43// The algorithm works as follows. On a reset, all three estimates are set to
44// the same sample. The second best estimate is then recorded in the second
45// quarter of the window, and a third best estimate is recorded in the second
46// half of the window, bounding the worst case error when the true min is
47// monotonically increasing (or true max is monotonically decreasing) over the
48// window.
49//
50// A new best sample replaces all three estimates, since the new best is lower
51// (or higher) than everything else in the window and it is the most recent.
52// The window thus effectively gets reset on every new min. The same property
53// holds true for second best and third best estimates. Specifically, when a
54// sample arrives that is better than the second best but not better than the
55// best, it replaces the second and third best estimates but not the best
56// estimate. Similarly, a sample that is better than the third best estimate
57// but not the other estimates replaces only the third best estimate.
58//
59// Finally, when the best expires, it is replaced by the second best, which in
60// turn is replaced by the third best. The newest sample replaces the third
61// best.
62
63#ifndef WINDOWED_FILTER_H_
64#define WINDOWED_FILTER_H_
65
66namespace ns3
67{
68/**
69 * \brief Compares two values
70 * \param T type of the measurement that is being filtered.
71 */
72template <class T>
74{
75 public:
76 /**
77 * \brief Compares two values
78 *
79 * \param lhs left hand value
80 * \param rhs right hand value
81 * \return returns true if the first is less than or equal to the second.
82 */
83 bool operator()(const T& lhs, const T& rhs) const
84 {
85 if (rhs == 0 || lhs == 0)
86 {
87 return false;
88 }
89 return lhs <= rhs;
90 }
91};
92
93/**
94 * \brief Compares two values
95 * \param T type of the measurement that is being filtered.
96 */
97template <class T>
99{
100 public:
101 /**
102 * \brief Compares two values
103 *
104 * \param lhs left hand value
105 * \param rhs right hand value
106 * \return returns true if the first is greater than or equal to the second.
107 */
108 bool operator()(const T& lhs, const T& rhs) const
109 {
110 if (rhs == 0 || lhs == 0)
111 {
112 return false;
113 }
114 return lhs >= rhs;
115 }
116};
117
118/**
119 * \brief Construct a windowed filter
120 *
121 * Use the following to construct a windowed filter object of type T.
122 * For example, a min filter using QuicTime as the time type:
123 * WindowedFilter<T, MinFilter<T>, QuicTime, QuicTime::Delta> ObjectName;
124 * max filter using 64-bit integers as the time type:
125 * WindowedFilter<T, MaxFilter<T>, uint64_t, int64_t> ObjectName;
126 *
127 * \param T -- type of the measurement that is being filtered.
128 * \param Compare -- MinFilter<T> or MaxFilter<T>, depending on the type of filter desired.
129 * \param TimeT -- the type used to represent timestamps.
130 * \param TimeDeltaT -- the type used to represent continuous time intervals between
131 * two timestamps. Has to be the type of (a - b) if both |a| and |b| are
132 * of type TimeT.
133 */
134template <class T, class Compare, typename TimeT, typename TimeDeltaT>
136{
137 public:
138 /**
139 * \brief constructor
140 */
142 {
143 }
144
145 /**
146 * \brief constructor
147 * \param windowLength is the period after which a best estimate expires.
148 * \param zeroValue is used as the uninitialized value for objects of T. Importantly,
149 * zeroValue should be an invalid value for a true sample.
150 * \param zeroTime is the time of instance record time.
151 */
152 WindowedFilter(TimeDeltaT windowLength, T zeroValue, TimeT zeroTime)
153 : m_windowLength(windowLength),
154 m_zeroValue(zeroValue),
155 m_samples{Sample(m_zeroValue, zeroTime),
156 Sample(m_zeroValue, zeroTime),
157 Sample(m_zeroValue, zeroTime)}
158 {
159 }
160
161 /**
162 * \brief Changes the window length. Does not update any current samples.
163 * \param windowLength is the period after which a best estimate expires.
164 */
165 void SetWindowLength(TimeDeltaT windowLength)
166 {
167 m_windowLength = windowLength;
168 }
169
170 /**
171 * \brief Updates best estimates with |sample|, and expires and updates best
172 * estimates as necessary.
173 *
174 * \param new_sample update new sample.
175 * \param new_time record time of the new sample.
176 */
177 void Update(T new_sample, TimeT new_time)
178 {
179 // Reset all estimates if they have not yet been initialized, if new sample
180 // is a new best, or if the newest recorded estimate is too old.
181 if (m_samples[0].sample == m_zeroValue || Compare()(new_sample, m_samples[0].sample) ||
182 new_time - m_samples[2].time > m_windowLength)
183 {
184 Reset(new_sample, new_time);
185 return;
186 }
187 if (Compare()(new_sample, m_samples[1].sample))
188 {
189 m_samples[1] = Sample(new_sample, new_time);
190 m_samples[2] = m_samples[1];
191 }
192 else if (Compare()(new_sample, m_samples[2].sample))
193 {
194 m_samples[2] = Sample(new_sample, new_time);
195 }
196 // Expire and update estimates as necessary.
197 if (new_time - m_samples[0].time > m_windowLength)
198 {
199 // The best estimate hasn't been updated for an entire window, so promote
200 // second and third best estimates.
201 m_samples[0] = m_samples[1];
202 m_samples[1] = m_samples[2];
203 m_samples[2] = Sample(new_sample, new_time);
204 // Need to iterate one more time. Check if the new best estimate is
205 // outside the window as well, since it may also have been recorded a
206 // long time ago. Don't need to iterate once more since we cover that
207 // case at the beginning of the method.
208 if (new_time - m_samples[0].time > m_windowLength)
209 {
210 m_samples[0] = m_samples[1];
211 m_samples[1] = m_samples[2];
212 }
213 return;
214 }
215 if (m_samples[1].sample == m_samples[0].sample &&
216 new_time - m_samples[1].time > m_windowLength >> 2)
217 {
218 // A quarter of the window has passed without a better sample, so the
219 // second-best estimate is taken from the second quarter of the window.
220 m_samples[2] = m_samples[1] = Sample(new_sample, new_time);
221 return;
222 }
223 if (m_samples[2].sample == m_samples[1].sample &&
224 new_time - m_samples[2].time > m_windowLength >> 1)
225 {
226 // We've passed a half of the window without a better estimate, so take
227 // a third-best estimate from the second half of the window.
228 m_samples[2] = Sample(new_sample, new_time);
229 }
230 }
231
232 /**
233 * \brief Resets all estimates to new sample.
234 * \param new_sample update new sample.
235 * \param new_time record time of the new sample.
236 */
237 void Reset(T new_sample, TimeT new_time)
238 {
239 m_samples[0] = m_samples[1] = m_samples[2] = Sample(new_sample, new_time);
240 }
241
242 /**
243 * \brief Returns Max/Min value so far among the windowed samples.
244 * \return returns Best (max/min) value so far among the windowed samples.
245 */
246 T GetBest() const
247 {
248 return m_samples[0].sample;
249 }
250
251 /**
252 * \brief Returns second Max/Min value so far among the windowed samples.
253 * \return returns second Best (max/min) value so far among the windowed samples.
254 */
256 {
257 return m_samples[1].sample;
258 }
259
260 /**
261 * \brief Returns third Max/Min value so far among the windowed samples.
262 * \return returns third Best (max/min) value so far among the windowed samples.
263 */
264 T GetThirdBest() const
265 {
266 return m_samples[2].sample;
267 }
268
269 /**
270 * \brief sample.
271 */
272 struct Sample
273 {
274 T sample; //!< recorded sample.
275 TimeT time; //!< time when the sample was recorded.
276
277 /**
278 * \brief constructor
279 */
281 {
282 }
283
284 /**
285 * \brief constructor
286 * \param init_sample value of sample.
287 * \param init_time time when the sample was recorded..
288 */
289 Sample(T init_sample, TimeT init_time)
290 : sample(init_sample),
291 time(init_time)
292 {
293 }
294 };
295
296 TimeDeltaT m_windowLength; //!< Time length of window.
297 T m_zeroValue; //!< Uninitialized value of T.
298 Sample m_samples[3]; //!< Best estimate is element 0.
299};
300
301} // namespace ns3
302#endif // WINDOWED_FILTER_H_
Construct a windowed filter.
WindowedFilter(TimeDeltaT windowLength, T zeroValue, TimeT zeroTime)
constructor
void Update(T new_sample, TimeT new_time)
Updates best estimates with |sample|, and expires and updates best estimates as necessary.
T GetSecondBest() const
Returns second Max/Min value so far among the windowed samples.
WindowedFilter()
constructor
Sample m_samples[3]
Best estimate is element 0.
T m_zeroValue
Uninitialized value of T.
TimeDeltaT m_windowLength
Time length of window.
T GetBest() const
Returns Max/Min value so far among the windowed samples.
T GetThirdBest() const
Returns third Max/Min value so far among the windowed samples.
void SetWindowLength(TimeDeltaT windowLength)
Changes the window length.
void Reset(T new_sample, TimeT new_time)
Resets all estimates to new sample.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Compares two values.
bool operator()(const T &lhs, const T &rhs) const
Compares two values.
Compares two values.
bool operator()(const T &lhs, const T &rhs) const
Compares two values.
Sample(T init_sample, TimeT init_time)
constructor
TimeT time
time when the sample was recorded.