![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0 0002 /** 0003 * lib/minmax.c: windowed min/max tracker 0004 * 0005 * Kathleen Nichols' algorithm for tracking the minimum (or maximum) 0006 * value of a data stream over some fixed time interval. (E.g., 0007 * the minimum RTT over the past five minutes.) It uses constant 0008 * space and constant time per update yet almost always delivers 0009 * the same minimum as an implementation that has to keep all the 0010 * data in the window. 0011 * 0012 * The algorithm keeps track of the best, 2nd best & 3rd best min 0013 * values, maintaining an invariant that the measurement time of 0014 * the n'th best >= n-1'th best. It also makes sure that the three 0015 * values are widely separated in the time window since that bounds 0016 * the worse case error when that data is monotonically increasing 0017 * over the window. 0018 * 0019 * Upon getting a new min, we can forget everything earlier because 0020 * it has no value - the new min is <= everything else in the window 0021 * by definition and it's the most recent. So we restart fresh on 0022 * every new min and overwrites 2nd & 3rd choices. The same property 0023 * holds for 2nd & 3rd best. 0024 */ 0025 #include <linux/module.h> 0026 #include <linux/win_minmax.h> 0027 0028 /* As time advances, update the 1st, 2nd, and 3rd choices. */ 0029 static u32 minmax_subwin_update(struct minmax *m, u32 win, 0030 const struct minmax_sample *val) 0031 { 0032 u32 dt = val->t - m->s[0].t; 0033 0034 if (unlikely(dt > win)) { 0035 /* 0036 * Passed entire window without a new val so make 2nd 0037 * choice the new val & 3rd choice the new 2nd choice. 0038 * we may have to iterate this since our 2nd choice 0039 * may also be outside the window (we checked on entry 0040 * that the third choice was in the window). 0041 */ 0042 m->s[0] = m->s[1]; 0043 m->s[1] = m->s[2]; 0044 m->s[2] = *val; 0045 if (unlikely(val->t - m->s[0].t > win)) { 0046 m->s[0] = m->s[1]; 0047 m->s[1] = m->s[2]; 0048 m->s[2] = *val; 0049 } 0050 } else if (unlikely(m->s[1].t == m->s[0].t) && dt > win/4) { 0051 /* 0052 * We've passed a quarter of the window without a new val 0053 * so take a 2nd choice from the 2nd quarter of the window. 0054 */ 0055 m->s[2] = m->s[1] = *val; 0056 } else if (unlikely(m->s[2].t == m->s[1].t) && dt > win/2) { 0057 /* 0058 * We've passed half the window without finding a new val 0059 * so take a 3rd choice from the last half of the window 0060 */ 0061 m->s[2] = *val; 0062 } 0063 return m->s[0].v; 0064 } 0065 0066 /* Check if new measurement updates the 1st, 2nd or 3rd choice max. */ 0067 u32 minmax_running_max(struct minmax *m, u32 win, u32 t, u32 meas) 0068 { 0069 struct minmax_sample val = { .t = t, .v = meas }; 0070 0071 if (unlikely(val.v >= m->s[0].v) || /* found new max? */ 0072 unlikely(val.t - m->s[2].t > win)) /* nothing left in window? */ 0073 return minmax_reset(m, t, meas); /* forget earlier samples */ 0074 0075 if (unlikely(val.v >= m->s[1].v)) 0076 m->s[2] = m->s[1] = val; 0077 else if (unlikely(val.v >= m->s[2].v)) 0078 m->s[2] = val; 0079 0080 return minmax_subwin_update(m, win, &val); 0081 } 0082 EXPORT_SYMBOL(minmax_running_max); 0083 0084 /* Check if new measurement updates the 1st, 2nd or 3rd choice min. */ 0085 u32 minmax_running_min(struct minmax *m, u32 win, u32 t, u32 meas) 0086 { 0087 struct minmax_sample val = { .t = t, .v = meas }; 0088 0089 if (unlikely(val.v <= m->s[0].v) || /* found new min? */ 0090 unlikely(val.t - m->s[2].t > win)) /* nothing left in window? */ 0091 return minmax_reset(m, t, meas); /* forget earlier samples */ 0092 0093 if (unlikely(val.v <= m->s[1].v)) 0094 m->s[2] = m->s[1] = val; 0095 else if (unlikely(val.v <= m->s[2].v)) 0096 m->s[2] = val; 0097 0098 return minmax_subwin_update(m, win, &val); 0099 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |