Skip to content

Commit e78138d

Browse files
committed
WIP: window filter
1 parent 40018bc commit e78138d

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

include/haproxy/window_filter.h

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#ifndef _HAPROXY_WINDOW_FILTER_H
2+
#define _HAPROXY_WINDOW_FILTER_H
3+
4+
/* Window filter sample */
5+
struct wf_smp {
6+
uint64_t v;
7+
uint32_t t;
8+
};
9+
10+
/* Window filter */
11+
struct wf {
12+
size_t len;
13+
struct wf_smp smp[3];
14+
};
15+
16+
static inline void wf_init(struct wf *wf, size_t len)
17+
{
18+
wf->len = len;
19+
memset(wf->smp, 0xff, sizeof(wf->smp));
20+
}
21+
22+
static inline void wf_reset(struct wf *wf, uint64_t v, uint32_t t)
23+
{
24+
struct wf_smp smp = { .v = v, .t = t };
25+
26+
wf->smp[2] = wf->smp[1] = wf->smp[0] = smp;
27+
}
28+
29+
/* Updates best estimates with |v| sample value, and expires and updates best
30+
* estimates as necessary.
31+
* Similar to minmax_subwin_update() linux kernel function (see lib/win_minmax.c
32+
* function).
33+
*/
34+
static inline void wf_update(struct wf *wf, uint64_t v, uint32_t t)
35+
{
36+
/* Reset all estimates if they have not yet been initialized, if new
37+
sample is a new best, or if the newest recorded estimate is too
38+
old. */
39+
if (wf->smp[0].v == UINT64_MAX || v > wf->smp[0].v || t - wf->smp[2].t > wf->len) {
40+
wf_reset(wf, v, t);
41+
return;
42+
}
43+
44+
if (v > wf->smp[1].v) {
45+
wf->smp[1].v = v;
46+
wf->smp[1].t = t;
47+
wf->smp[2] = wf->smp[1];
48+
} else if (v > wf->smp[2].v) {
49+
wf->smp[2].v = v;
50+
wf->smp[2].t = t;
51+
}
52+
53+
/* Expire and update smp as necessary. */
54+
if (t - wf->smp[0].t > wf->len) {
55+
/* The best estimate hasn't been updated for an entire window, so
56+
promote second and third best smp. */
57+
wf->smp[0] = wf->smp[1];
58+
wf->smp[1] = wf->smp[2];
59+
wf->smp[2].v = v;
60+
wf->smp[2].t = t;
61+
62+
/* Need to iterate one more time. Check if the new best estimate
63+
is outside the window as well, since it may also have been
64+
recorded a long time ago. Don't need to iterate once more
65+
since we cover that case at the beginning of the method. */
66+
if (t - wf->smp[0].t > wf->len) {
67+
wf->smp[0] = wf->smp[1];
68+
wf->smp[1] = wf->smp[2];
69+
}
70+
return;
71+
}
72+
73+
if (wf->smp[1].v == wf->smp[0].v && t - wf->smp[1].t > wf->len >> 2) {
74+
/* A quarter of the window has passed without a better sample, so
75+
the second-best estimate is taken from the second quarter of
76+
the window. */
77+
wf->smp[2].v = v;
78+
wf->smp[2].t = t;
79+
wf->smp[1] = wf->smp[2];
80+
return;
81+
}
82+
83+
if (wf->smp[2].v == wf->smp[1].v && t - wf->smp[2].t > wf->len >> 1) {
84+
/* We've passed a half of the window without a better estimate, so
85+
take a third-best estimate from the second half of the
86+
window. */
87+
wf->smp[2].v = v;
88+
wf->smp[2].t = t;
89+
}
90+
}
91+
92+
static inline uint64_t wf_get_best(struct wf *wf)
93+
{
94+
return wf->smp[0].v;
95+
}
96+
97+
#endif /* _HAPROXY_WINDOW_FILTER_H */

0 commit comments

Comments
 (0)