1
0
mirror of http://git.haproxy.org/git/haproxy.git/ synced 2024-12-19 18:28:33 +00:00

MINOR: freq_ctr: add swrate_add_scaled() to work with large samples

Some samples representing time will cover more than one sample at once
if they are units of time per time. For this we'd need to have the
ability to loop over swrate_add() multiple times but that would be
inefficient. By developing the function elevated to power N, it's
visible that some coefficients quickly disappear and that those which
remain at the first order more or less compensate each other.

Thus a simplified version of this function was added to provide a single
value for a given number of samples. Tests with multiple values, window
sizes and sample sizes have shown that it is possible to make it remain
surprisingly accurate (typical error < 0.2% over various large window
and sample sizes, even samples representing up to 1/4 of the window).
This commit is contained in:
Willy Tarreau 2018-10-17 09:24:56 +02:00
parent 23cd43e2d6
commit 627505d36a

View File

@ -244,6 +244,33 @@ static inline unsigned int swrate_add(unsigned int *sum, unsigned int n, unsigne
return *sum = *sum - (*sum + n - 1) / n + v;
}
/* Adds sample value <v> spanning <s> samples to sliding window sum <sum>
* configured for <n> samples, where <n> is supposed to be "much larger" than
* <s>. The sample is returned. Better if <n> is a power of two. Note that this
* is only an approximate. Indeed, as can be seen with two samples only over a
* 8-sample window, the original function would return :
* sum1 = sum - (sum + 7) / 8 + v
* sum2 = sum1 - (sum1 + 7) / 8 + v
* = (sum - (sum + 7) / 8 + v) - (sum - (sum + 7) / 8 + v + 7) / 8 + v
* ~= 7sum/8 - 7/8 + v - sum/8 + sum/64 - 7/64 - v/8 - 7/8 + v
* ~= (3sum/4 + sum/64) - (7/4 + 7/64) + 15v/8
*
* while the function below would return :
* sum = sum + 2*v - (sum + 8) * 2 / 8
* = 3sum/4 + 2v - 2
*
* this presents an error of ~ (sum/64 + 9/64 + v/8) = (sum+n+1)/(n^s) + v/n
*
* Thus the simplified function effectively replaces a part of the history with
* a linear sum instead of applying the exponential one. But as long as s/n is
* "small enough", the error fades away and remains small for both small and
* large values of n and s (typically < 0.2% measured).
*/
static inline unsigned int swrate_add_scaled(unsigned int *sum, unsigned int n, unsigned int v, unsigned int s)
{
return *sum = *sum + v * s - div64_32((unsigned long long)(*sum + n) * s, n);
}
/* Returns the average sample value for the sum <sum> over a sliding window of
* <n> samples. Better if <n> is a power of two. It must be the same <n> as the
* one used above in all additions.