mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-24 05:32:21 +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:
parent
23cd43e2d6
commit
627505d36a
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user