1use std::ops::Deref;
56
57use std::time::Duration;
58use std::time::Instant;
59
60#[derive(Copy, Clone)]
61struct MinmaxSample<T> {
62 time: Instant,
63 value: T,
64}
65
66pub struct Minmax<T> {
67 estimate: [MinmaxSample<T>; 3],
68}
69
70impl<T> Deref for Minmax<T> {
71 type Target = T;
72
73 fn deref(&self) -> &Self::Target {
74 &self.estimate[0].value
75 }
76}
77
78impl<T: PartialOrd + Copy> Minmax<T> {
79 pub fn new(val: T) -> Self {
80 Minmax {
81 estimate: [MinmaxSample {
82 time: Instant::now(),
83 value: val,
84 }; 3],
85 }
86 }
87
88 pub fn reset(&mut self, time: Instant, meas: T) -> T {
90 let val = MinmaxSample { time, value: meas };
91
92 for i in self.estimate.iter_mut() {
93 *i = val;
94 }
95
96 self.estimate[0].value
97 }
98
99 pub fn running_min(&mut self, win: Duration, time: Instant, meas: T) -> T {
101 let val = MinmaxSample { time, value: meas };
102
103 let delta_time = time.duration_since(self.estimate[2].time);
104
105 if val.value <= self.estimate[0].value || delta_time > win {
107 return self.reset(time, meas);
108 }
109
110 if val.value <= self.estimate[1].value {
111 self.estimate[2] = val;
112 self.estimate[1] = val;
113 } else if val.value <= self.estimate[2].value {
114 self.estimate[2] = val;
115 }
116
117 self.subwin_update(win, time, meas)
118 }
119
120 #[cfg(test)]
122 pub fn running_max(&mut self, win: Duration, time: Instant, meas: T) -> T {
123 let val = MinmaxSample { time, value: meas };
124
125 let delta_time = time.duration_since(self.estimate[2].time);
126
127 if val.value >= self.estimate[0].value || delta_time > win {
129 return self.reset(time, meas);
130 }
131
132 if val.value >= self.estimate[1].value {
133 self.estimate[2] = val;
134 self.estimate[1] = val;
135 } else if val.value >= self.estimate[2].value {
136 self.estimate[2] = val
137 }
138
139 self.subwin_update(win, time, meas)
140 }
141
142 fn subwin_update(&mut self, win: Duration, time: Instant, meas: T) -> T {
144 let val = MinmaxSample { time, value: meas };
145
146 let delta_time = time.duration_since(self.estimate[0].time);
147
148 if delta_time > win {
149 self.estimate[0] = self.estimate[1];
154 self.estimate[1] = self.estimate[2];
155 self.estimate[2] = val;
156
157 if time.duration_since(self.estimate[0].time) > win {
158 self.estimate[0] = self.estimate[1];
159 self.estimate[1] = self.estimate[2];
160 self.estimate[2] = val;
161 }
162 } else if self.estimate[1].time == self.estimate[0].time &&
163 delta_time > win.div_f32(4.0)
164 {
165 self.estimate[2] = val;
168 self.estimate[1] = val;
169 } else if self.estimate[2].time == self.estimate[1].time &&
170 delta_time > win.div_f32(2.0)
171 {
172 self.estimate[2] = val;
175 }
176
177 self.estimate[0].value
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn reset_filter_rtt() {
187 let mut f = Minmax::new(Duration::ZERO);
188 let now = Instant::now();
189 let rtt = Duration::from_millis(50);
190
191 let rtt_min = f.reset(now, rtt);
192 assert_eq!(rtt_min, rtt);
193
194 assert_eq!(f.estimate[0].time, now);
195 assert_eq!(f.estimate[0].value, rtt);
196
197 assert_eq!(f.estimate[1].time, now);
198 assert_eq!(f.estimate[1].value, rtt);
199
200 assert_eq!(f.estimate[2].time, now);
201 assert_eq!(f.estimate[2].value, rtt);
202 }
203
204 #[test]
205 fn reset_filter_bandwidth() {
206 let mut f = Minmax::new(0);
207 let now = Instant::now();
208 let bw = 2000;
209
210 let bw_min = f.reset(now, bw);
211 assert_eq!(bw_min, bw);
212
213 assert_eq!(f.estimate[0].time, now);
214 assert_eq!(f.estimate[0].value, bw);
215
216 assert_eq!(f.estimate[1].time, now);
217 assert_eq!(f.estimate[1].value, bw);
218
219 assert_eq!(f.estimate[2].time, now);
220 assert_eq!(f.estimate[2].value, bw);
221 }
222
223 #[test]
224 fn get_windowed_min_rtt() {
225 let mut f = Minmax::new(Duration::ZERO);
226 let rtt_25 = Duration::from_millis(25);
227 let rtt_24 = Duration::from_millis(24);
228 let win = Duration::from_millis(500);
229 let mut time = Instant::now();
230
231 let mut rtt_min = f.reset(time, rtt_25);
232 assert_eq!(rtt_min, rtt_25);
233
234 time += Duration::from_millis(250);
235 rtt_min = f.running_min(win, time, rtt_24);
236 assert_eq!(rtt_min, rtt_24);
237 assert_eq!(f.estimate[1].value, rtt_24);
238 assert_eq!(f.estimate[2].value, rtt_24);
239
240 time += Duration::from_millis(600);
241 rtt_min = f.running_min(win, time, rtt_25);
242 assert_eq!(rtt_min, rtt_25);
243 assert_eq!(f.estimate[1].value, rtt_25);
244 assert_eq!(f.estimate[2].value, rtt_25);
245 }
246
247 #[test]
248 fn get_windowed_min_bandwidth() {
249 let mut f = Minmax::new(0);
250 let bw_200 = 200;
251 let bw_500 = 500;
252 let win = Duration::from_millis(500);
253 let mut time = Instant::now();
254
255 let mut bw_min = f.reset(time, bw_500);
256 assert_eq!(bw_min, bw_500);
257
258 time += Duration::from_millis(250);
259 bw_min = f.running_min(win, time, bw_200);
260 assert_eq!(bw_min, bw_200);
261 assert_eq!(f.estimate[1].value, bw_200);
262 assert_eq!(f.estimate[2].value, bw_200);
263
264 time += Duration::from_millis(600);
265 bw_min = f.running_min(win, time, bw_500);
266 assert_eq!(bw_min, bw_500);
267 assert_eq!(f.estimate[1].value, bw_500);
268 assert_eq!(f.estimate[2].value, bw_500);
269 }
270
271 #[test]
272 fn get_windowed_max_rtt() {
273 let mut f = Minmax::new(Duration::ZERO);
274 let rtt_25 = Duration::from_millis(25);
275 let rtt_24 = Duration::from_millis(24);
276 let win = Duration::from_millis(500);
277 let mut time = Instant::now();
278
279 let mut rtt_max = f.reset(time, rtt_24);
280 assert_eq!(rtt_max, rtt_24);
281
282 time += Duration::from_millis(250);
283 rtt_max = f.running_max(win, time, rtt_25);
284 assert_eq!(rtt_max, rtt_25);
285 assert_eq!(f.estimate[1].value, rtt_25);
286 assert_eq!(f.estimate[2].value, rtt_25);
287
288 time += Duration::from_millis(600);
289 rtt_max = f.running_max(win, time, rtt_24);
290 assert_eq!(rtt_max, rtt_24);
291 assert_eq!(f.estimate[1].value, rtt_24);
292 assert_eq!(f.estimate[2].value, rtt_24);
293 }
294
295 #[test]
296 fn get_windowed_max_bandwidth() {
297 let mut f = Minmax::new(0);
298 let bw_200 = 200;
299 let bw_500 = 500;
300 let win = Duration::from_millis(500);
301 let mut time = Instant::now();
302
303 let mut bw_max = f.reset(time, bw_200);
304 assert_eq!(bw_max, bw_200);
305
306 time += Duration::from_millis(5000);
307 bw_max = f.running_max(win, time, bw_500);
308 assert_eq!(bw_max, bw_500);
309 assert_eq!(f.estimate[1].value, bw_500);
310 assert_eq!(f.estimate[2].value, bw_500);
311
312 time += Duration::from_millis(600);
313 bw_max = f.running_max(win, time, bw_200);
314 assert_eq!(bw_max, bw_200);
315 assert_eq!(f.estimate[1].value, bw_200);
316 assert_eq!(f.estimate[2].value, bw_200);
317 }
318
319 #[test]
320 fn get_windowed_min_estimates_rtt() {
321 let mut f = Minmax::new(Duration::ZERO);
322 let rtt_25 = Duration::from_millis(25);
323 let rtt_24 = Duration::from_millis(24);
324 let rtt_23 = Duration::from_millis(23);
325 let rtt_22 = Duration::from_millis(22);
326 let win = Duration::from_secs(1);
327 let mut time = Instant::now();
328
329 let mut rtt_min = f.reset(time, rtt_23);
330 assert_eq!(rtt_min, rtt_23);
331
332 time += Duration::from_millis(300);
333 rtt_min = f.running_min(win, time, rtt_24);
334 assert_eq!(rtt_min, rtt_23);
335 assert_eq!(f.estimate[1].value, rtt_24);
336 assert_eq!(f.estimate[2].value, rtt_24);
337
338 time += Duration::from_millis(300);
339 rtt_min = f.running_min(win, time, rtt_25);
340 assert_eq!(rtt_min, rtt_23);
341 assert_eq!(f.estimate[1].value, rtt_24);
342 assert_eq!(f.estimate[2].value, rtt_25);
343
344 time += Duration::from_millis(300);
345 rtt_min = f.running_min(win, time, rtt_22);
346 assert_eq!(rtt_min, rtt_22);
347 assert_eq!(f.estimate[1].value, rtt_22);
348 assert_eq!(f.estimate[2].value, rtt_22);
349 }
350
351 #[test]
352 fn get_windowed_min_estimates_bandwidth() {
353 let mut f = Minmax::new(0);
354 let bw_500 = 500;
355 let bw_400 = 400;
356 let bw_300 = 300;
357 let bw_200 = 200;
358 let win = Duration::from_secs(1);
359 let mut time = Instant::now();
360
361 let mut bw_min = f.reset(time, bw_300);
362 assert_eq!(bw_min, bw_300);
363
364 time += Duration::from_millis(300);
365 bw_min = f.running_min(win, time, bw_400);
366 assert_eq!(bw_min, bw_300);
367 assert_eq!(f.estimate[1].value, bw_400);
368 assert_eq!(f.estimate[2].value, bw_400);
369
370 time += Duration::from_millis(300);
371 bw_min = f.running_min(win, time, bw_500);
372 assert_eq!(bw_min, bw_300);
373 assert_eq!(f.estimate[1].value, bw_400);
374 assert_eq!(f.estimate[2].value, bw_500);
375
376 time += Duration::from_millis(300);
377 bw_min = f.running_min(win, time, bw_200);
378 assert_eq!(bw_min, bw_200);
379 assert_eq!(f.estimate[1].value, bw_200);
380 assert_eq!(f.estimate[2].value, bw_200);
381 }
382
383 #[test]
384 fn get_windowed_max_estimates_rtt() {
385 let mut f = Minmax::new(Duration::ZERO);
386 let rtt_25 = Duration::from_millis(25);
387 let rtt_24 = Duration::from_millis(24);
388 let rtt_23 = Duration::from_millis(23);
389 let rtt_26 = Duration::from_millis(26);
390 let win = Duration::from_secs(1);
391 let mut time = Instant::now();
392
393 let mut rtt_max = f.reset(time, rtt_25);
394 assert_eq!(rtt_max, rtt_25);
395
396 time += Duration::from_millis(300);
397 rtt_max = f.running_max(win, time, rtt_24);
398 assert_eq!(rtt_max, rtt_25);
399 assert_eq!(f.estimate[1].value, rtt_24);
400 assert_eq!(f.estimate[2].value, rtt_24);
401
402 time += Duration::from_millis(300);
403 rtt_max = f.running_max(win, time, rtt_23);
404 assert_eq!(rtt_max, rtt_25);
405 assert_eq!(f.estimate[1].value, rtt_24);
406 assert_eq!(f.estimate[2].value, rtt_23);
407
408 time += Duration::from_millis(300);
409 rtt_max = f.running_max(win, time, rtt_26);
410 assert_eq!(rtt_max, rtt_26);
411 assert_eq!(f.estimate[1].value, rtt_26);
412 assert_eq!(f.estimate[2].value, rtt_26);
413 }
414
415 #[test]
416 fn get_windowed_max_estimates_bandwidth() {
417 let mut f = Minmax::new(0);
418 let bw_500 = 500;
419 let bw_400 = 400;
420 let bw_300 = 300;
421 let bw_600 = 600;
422 let win = Duration::from_secs(1);
423 let mut time = Instant::now();
424
425 let mut bw_max = f.reset(time, bw_500);
426 assert_eq!(bw_max, bw_500);
427
428 time += Duration::from_millis(300);
429 bw_max = f.running_max(win, time, bw_400);
430 assert_eq!(bw_max, bw_500);
431 assert_eq!(f.estimate[1].value, bw_400);
432 assert_eq!(f.estimate[2].value, bw_400);
433
434 time += Duration::from_millis(300);
435 bw_max = f.running_max(win, time, bw_300);
436 assert_eq!(bw_max, bw_500);
437 assert_eq!(f.estimate[1].value, bw_400);
438 assert_eq!(f.estimate[2].value, bw_300);
439
440 time += Duration::from_millis(300);
441 bw_max = f.running_max(win, time, bw_600);
442 assert_eq!(bw_max, bw_600);
443 assert_eq!(f.estimate[1].value, bw_600);
444 assert_eq!(f.estimate[2].value, bw_600);
445 }
446}