mean and variance: More tests
Add some more tests that test conventional and weighted mean simultaneously, and with a table of values that represents events that we'll be using this to look for so we can verify-by-eyeball that the output looks sane. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
aab5e0972a
commit
65bc410907
@ -176,14 +176,12 @@ static inline s64 fast_divpow2(s64 n, u8 d)
|
||||
*
|
||||
* see linked pdf equation 12.
|
||||
*/
|
||||
static inline struct mean_and_variance
|
||||
mean_and_variance_update(struct mean_and_variance s, s64 v)
|
||||
static inline void
|
||||
mean_and_variance_update(struct mean_and_variance *s, s64 v)
|
||||
{
|
||||
return (struct mean_and_variance) {
|
||||
.n = s.n + 1,
|
||||
.sum = s.sum + v,
|
||||
.sum_squares = u128_add(s.sum_squares, u128_square(abs(v))),
|
||||
};
|
||||
s->n++;
|
||||
s->sum += v;
|
||||
s->sum_squares = u128_add(s->sum_squares, u128_square(abs(v)));
|
||||
}
|
||||
|
||||
s64 mean_and_variance_get_mean(struct mean_and_variance s);
|
||||
|
@ -9,15 +9,15 @@ static void mean_and_variance_basic_test(struct kunit *test)
|
||||
{
|
||||
struct mean_and_variance s = {};
|
||||
|
||||
s = mean_and_variance_update(s, 2);
|
||||
s = mean_and_variance_update(s, 2);
|
||||
mean_and_variance_update(&s, 2);
|
||||
mean_and_variance_update(&s, 2);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(s), 2);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_variance(s), 0);
|
||||
KUNIT_EXPECT_EQ(test, s.n, 2);
|
||||
|
||||
s = mean_and_variance_update(s, 4);
|
||||
s = mean_and_variance_update(s, 4);
|
||||
mean_and_variance_update(&s, 4);
|
||||
mean_and_variance_update(&s, 4);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(s), 3);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_variance(s), 1);
|
||||
@ -33,8 +33,6 @@ static void mean_and_variance_weighted_test(struct kunit *test)
|
||||
{
|
||||
struct mean_and_variance_weighted s = { .weight = 2 };
|
||||
|
||||
s.weight = 2;
|
||||
|
||||
mean_and_variance_weighted_update(&s, 10);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 10);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 0);
|
||||
@ -60,7 +58,6 @@ static void mean_and_variance_weighted_test(struct kunit *test)
|
||||
mean_and_variance_weighted_update(&s, -30);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -16);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 72);
|
||||
|
||||
}
|
||||
|
||||
static void mean_and_variance_weighted_advanced_test(struct kunit *test)
|
||||
@ -81,7 +78,93 @@ static void mean_and_variance_weighted_advanced_test(struct kunit *test)
|
||||
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -11);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 107);
|
||||
}
|
||||
|
||||
static void do_mean_and_variance_test(struct kunit *test,
|
||||
s64 initial_value,
|
||||
s64 initial_n,
|
||||
s64 n,
|
||||
unsigned weight,
|
||||
s64 *data,
|
||||
s64 *mean,
|
||||
s64 *stddev,
|
||||
s64 *weighted_mean,
|
||||
s64 *weighted_stddev)
|
||||
{
|
||||
struct mean_and_variance mv = {};
|
||||
struct mean_and_variance_weighted vw = { .weight = weight };
|
||||
|
||||
for (unsigned i = 0; i < initial_n; i++) {
|
||||
mean_and_variance_update(&mv, initial_value);
|
||||
mean_and_variance_weighted_update(&vw, initial_value);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), initial_value);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), 0);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), initial_value);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),0);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
mean_and_variance_update(&mv, data[i]);
|
||||
mean_and_variance_weighted_update(&vw, data[i]);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), mean[i]);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), stddev[i]);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), weighted_mean[i]);
|
||||
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),weighted_stddev[i]);
|
||||
}
|
||||
|
||||
KUNIT_EXPECT_EQ(test, mv.n, initial_n + n);
|
||||
}
|
||||
|
||||
/* Test behaviour with a single outlier, then back to steady state: */
|
||||
static void mean_and_variance_test_1(struct kunit *test)
|
||||
{
|
||||
s64 d[] = { 100, 10, 10, 10, 10, 10, 10 };
|
||||
s64 mean[] = { 22, 21, 20, 19, 18, 17, 16 };
|
||||
s64 stddev[] = { 32, 29, 28, 27, 26, 25, 24 };
|
||||
s64 weighted_mean[] = { 32, 27, 22, 19, 17, 15, 14 };
|
||||
s64 weighted_stddev[] = { 38, 35, 31, 27, 24, 21, 18 };
|
||||
|
||||
do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2,
|
||||
d, mean, stddev, weighted_mean, weighted_stddev);
|
||||
}
|
||||
|
||||
static void mean_and_variance_test_2(struct kunit *test)
|
||||
{
|
||||
s64 d[] = { 100, 10, 10, 10, 10, 10, 10 };
|
||||
s64 mean[] = { 10, 10, 10, 10, 10, 10, 10 };
|
||||
s64 stddev[] = { 9, 9, 9, 9, 9, 9, 9 };
|
||||
s64 weighted_mean[] = { 32, 27, 22, 19, 17, 15, 14 };
|
||||
s64 weighted_stddev[] = { 38, 35, 31, 27, 24, 21, 18 };
|
||||
|
||||
do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2,
|
||||
d, mean, stddev, weighted_mean, weighted_stddev);
|
||||
}
|
||||
|
||||
/* Test behaviour where we switch from one steady state to another: */
|
||||
static void mean_and_variance_test_3(struct kunit *test)
|
||||
{
|
||||
s64 d[] = { 100, 100, 100, 100, 100 };
|
||||
s64 mean[] = { 22, 32, 40, 46, 50 };
|
||||
s64 stddev[] = { 32, 39, 42, 44, 45 };
|
||||
s64 weighted_mean[] = { 32, 49, 61, 71, 78 };
|
||||
s64 weighted_stddev[] = { 38, 44, 44, 41, 38 };
|
||||
|
||||
do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2,
|
||||
d, mean, stddev, weighted_mean, weighted_stddev);
|
||||
}
|
||||
|
||||
static void mean_and_variance_test_4(struct kunit *test)
|
||||
{
|
||||
s64 d[] = { 100, 100, 100, 100, 100 };
|
||||
s64 mean[] = { 10, 11, 12, 13, 14 };
|
||||
s64 stddev[] = { 9, 13, 15, 17, 19 };
|
||||
s64 weighted_mean[] = { 32, 49, 61, 71, 78 };
|
||||
s64 weighted_stddev[] = { 38, 44, 44, 41, 38 };
|
||||
|
||||
do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2,
|
||||
d, mean, stddev, weighted_mean, weighted_stddev);
|
||||
}
|
||||
|
||||
static void mean_and_variance_fast_divpow2(struct kunit *test)
|
||||
@ -139,6 +222,10 @@ static struct kunit_case mean_and_variance_test_cases[] = {
|
||||
KUNIT_CASE(mean_and_variance_basic_test),
|
||||
KUNIT_CASE(mean_and_variance_weighted_test),
|
||||
KUNIT_CASE(mean_and_variance_weighted_advanced_test),
|
||||
KUNIT_CASE(mean_and_variance_test_1),
|
||||
KUNIT_CASE(mean_and_variance_test_2),
|
||||
KUNIT_CASE(mean_and_variance_test_3),
|
||||
KUNIT_CASE(mean_and_variance_test_4),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -350,7 +350,7 @@ static inline void bch2_time_stats_update_one(struct bch2_time_stats *stats,
|
||||
|
||||
if (time_after64(end, start)) {
|
||||
duration = end - start;
|
||||
stats->duration_stats = mean_and_variance_update(stats->duration_stats, duration);
|
||||
mean_and_variance_update(&stats->duration_stats, duration);
|
||||
mean_and_variance_weighted_update(&stats->duration_stats_weighted, duration);
|
||||
stats->max_duration = max(stats->max_duration, duration);
|
||||
stats->min_duration = min(stats->min_duration, duration);
|
||||
@ -359,7 +359,7 @@ static inline void bch2_time_stats_update_one(struct bch2_time_stats *stats,
|
||||
|
||||
if (time_after64(end, stats->last_event)) {
|
||||
freq = end - stats->last_event;
|
||||
stats->freq_stats = mean_and_variance_update(stats->freq_stats, freq);
|
||||
mean_and_variance_update(&stats->freq_stats, freq);
|
||||
mean_and_variance_weighted_update(&stats->freq_stats_weighted, freq);
|
||||
stats->max_freq = max(stats->max_freq, freq);
|
||||
stats->min_freq = min(stats->min_freq, freq);
|
||||
|
Loading…
Reference in New Issue
Block a user