diff --git a/include/proto/freq_ctr.h b/include/proto/freq_ctr.h index c10ddf2aa..277bfda5a 100644 --- a/include/proto/freq_ctr.h +++ b/include/proto/freq_ctr.h @@ -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 spanning samples to sliding window sum + * configured for samples, where is supposed to be "much larger" than + * . The sample is returned. Better if 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 over a sliding window of * samples. Better if is a power of two. It must be the same as the * one used above in all additions.