Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+101 -16
+5 -7
fs/bcachefs/mean_and_variance.h
··· 176 176 * 177 177 * see linked pdf equation 12. 178 178 */ 179 - static inline struct mean_and_variance 180 - mean_and_variance_update(struct mean_and_variance s, s64 v) 179 + static inline void 180 + mean_and_variance_update(struct mean_and_variance *s, s64 v) 181 181 { 182 - return (struct mean_and_variance) { 183 - .n = s.n + 1, 184 - .sum = s.sum + v, 185 - .sum_squares = u128_add(s.sum_squares, u128_square(abs(v))), 186 - }; 182 + s->n++; 183 + s->sum += v; 184 + s->sum_squares = u128_add(s->sum_squares, u128_square(abs(v))); 187 185 } 188 186 189 187 s64 mean_and_variance_get_mean(struct mean_and_variance s);
+94 -7
fs/bcachefs/mean_and_variance_test.c
··· 9 9 { 10 10 struct mean_and_variance s = {}; 11 11 12 - s = mean_and_variance_update(s, 2); 13 - s = mean_and_variance_update(s, 2); 12 + mean_and_variance_update(&s, 2); 13 + mean_and_variance_update(&s, 2); 14 14 15 15 KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(s), 2); 16 16 KUNIT_EXPECT_EQ(test, mean_and_variance_get_variance(s), 0); 17 17 KUNIT_EXPECT_EQ(test, s.n, 2); 18 18 19 - s = mean_and_variance_update(s, 4); 20 - s = mean_and_variance_update(s, 4); 19 + mean_and_variance_update(&s, 4); 20 + mean_and_variance_update(&s, 4); 21 21 22 22 KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(s), 3); 23 23 KUNIT_EXPECT_EQ(test, mean_and_variance_get_variance(s), 1); ··· 32 32 static void mean_and_variance_weighted_test(struct kunit *test) 33 33 { 34 34 struct mean_and_variance_weighted s = { .weight = 2 }; 35 - 36 - s.weight = 2; 37 35 38 36 mean_and_variance_weighted_update(&s, 10); 39 37 KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 10); ··· 58 60 mean_and_variance_weighted_update(&s, -30); 59 61 KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -16); 60 62 KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 72); 61 - 62 63 } 63 64 64 65 static void mean_and_variance_weighted_advanced_test(struct kunit *test) ··· 78 81 79 82 KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -11); 80 83 KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 107); 84 + } 81 85 86 + static void do_mean_and_variance_test(struct kunit *test, 87 + s64 initial_value, 88 + s64 initial_n, 89 + s64 n, 90 + unsigned weight, 91 + s64 *data, 92 + s64 *mean, 93 + s64 *stddev, 94 + s64 *weighted_mean, 95 + s64 *weighted_stddev) 96 + { 97 + struct mean_and_variance mv = {}; 98 + struct mean_and_variance_weighted vw = { .weight = weight }; 99 + 100 + for (unsigned i = 0; i < initial_n; i++) { 101 + mean_and_variance_update(&mv, initial_value); 102 + mean_and_variance_weighted_update(&vw, initial_value); 103 + 104 + KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), initial_value); 105 + KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), 0); 106 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), initial_value); 107 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),0); 108 + } 109 + 110 + for (unsigned i = 0; i < n; i++) { 111 + mean_and_variance_update(&mv, data[i]); 112 + mean_and_variance_weighted_update(&vw, data[i]); 113 + 114 + KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), mean[i]); 115 + KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), stddev[i]); 116 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), weighted_mean[i]); 117 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),weighted_stddev[i]); 118 + } 119 + 120 + KUNIT_EXPECT_EQ(test, mv.n, initial_n + n); 121 + } 122 + 123 + /* Test behaviour with a single outlier, then back to steady state: */ 124 + static void mean_and_variance_test_1(struct kunit *test) 125 + { 126 + s64 d[] = { 100, 10, 10, 10, 10, 10, 10 }; 127 + s64 mean[] = { 22, 21, 20, 19, 18, 17, 16 }; 128 + s64 stddev[] = { 32, 29, 28, 27, 26, 25, 24 }; 129 + s64 weighted_mean[] = { 32, 27, 22, 19, 17, 15, 14 }; 130 + s64 weighted_stddev[] = { 38, 35, 31, 27, 24, 21, 18 }; 131 + 132 + do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2, 133 + d, mean, stddev, weighted_mean, weighted_stddev); 134 + } 135 + 136 + static void mean_and_variance_test_2(struct kunit *test) 137 + { 138 + s64 d[] = { 100, 10, 10, 10, 10, 10, 10 }; 139 + s64 mean[] = { 10, 10, 10, 10, 10, 10, 10 }; 140 + s64 stddev[] = { 9, 9, 9, 9, 9, 9, 9 }; 141 + s64 weighted_mean[] = { 32, 27, 22, 19, 17, 15, 14 }; 142 + s64 weighted_stddev[] = { 38, 35, 31, 27, 24, 21, 18 }; 143 + 144 + do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2, 145 + d, mean, stddev, weighted_mean, weighted_stddev); 146 + } 147 + 148 + /* Test behaviour where we switch from one steady state to another: */ 149 + static void mean_and_variance_test_3(struct kunit *test) 150 + { 151 + s64 d[] = { 100, 100, 100, 100, 100 }; 152 + s64 mean[] = { 22, 32, 40, 46, 50 }; 153 + s64 stddev[] = { 32, 39, 42, 44, 45 }; 154 + s64 weighted_mean[] = { 32, 49, 61, 71, 78 }; 155 + s64 weighted_stddev[] = { 38, 44, 44, 41, 38 }; 156 + 157 + do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2, 158 + d, mean, stddev, weighted_mean, weighted_stddev); 159 + } 160 + 161 + static void mean_and_variance_test_4(struct kunit *test) 162 + { 163 + s64 d[] = { 100, 100, 100, 100, 100 }; 164 + s64 mean[] = { 10, 11, 12, 13, 14 }; 165 + s64 stddev[] = { 9, 13, 15, 17, 19 }; 166 + s64 weighted_mean[] = { 32, 49, 61, 71, 78 }; 167 + s64 weighted_stddev[] = { 38, 44, 44, 41, 38 }; 168 + 169 + do_mean_and_variance_test(test, 10, 6, ARRAY_SIZE(d), 2, 170 + d, mean, stddev, weighted_mean, weighted_stddev); 82 171 } 83 172 84 173 static void mean_and_variance_fast_divpow2(struct kunit *test) ··· 222 139 KUNIT_CASE(mean_and_variance_basic_test), 223 140 KUNIT_CASE(mean_and_variance_weighted_test), 224 141 KUNIT_CASE(mean_and_variance_weighted_advanced_test), 142 + KUNIT_CASE(mean_and_variance_test_1), 143 + KUNIT_CASE(mean_and_variance_test_2), 144 + KUNIT_CASE(mean_and_variance_test_3), 145 + KUNIT_CASE(mean_and_variance_test_4), 225 146 {} 226 147 }; 227 148
+2 -2
fs/bcachefs/util.c
··· 350 350 351 351 if (time_after64(end, start)) { 352 352 duration = end - start; 353 - stats->duration_stats = mean_and_variance_update(stats->duration_stats, duration); 353 + mean_and_variance_update(&stats->duration_stats, duration); 354 354 mean_and_variance_weighted_update(&stats->duration_stats_weighted, duration); 355 355 stats->max_duration = max(stats->max_duration, duration); 356 356 stats->min_duration = min(stats->min_duration, duration); ··· 359 359 360 360 if (time_after64(end, stats->last_event)) { 361 361 freq = end - stats->last_event; 362 - stats->freq_stats = mean_and_variance_update(stats->freq_stats, freq); 362 + mean_and_variance_update(&stats->freq_stats, freq); 363 363 mean_and_variance_weighted_update(&stats->freq_stats_weighted, freq); 364 364 stats->max_freq = max(stats->max_freq, freq); 365 365 stats->min_freq = min(stats->min_freq, freq);