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

bcachefs: mean_and_variance: put struct mean_and_variance_weighted on a diet

The only caller of this code (time_stats) always knows the weights and
whether or not any information has been collected. Pass this
information into the mean and variance code so that it doesn't have to
store that information. This reduces the structure size from 24 to 16
bytes, which shrinks each time_stats counter to 192 bytes from 208.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

authored by

Darrick J. Wong and committed by
Kent Overstreet
4b4f0876 cdbfa228

+84 -67
+18 -10
fs/bcachefs/mean_and_variance.c
··· 103 103 * mean_and_variance_weighted_update() - exponentially weighted variant of mean_and_variance_update() 104 104 * @s: mean and variance number of samples and their sums 105 105 * @x: new value to include in the &mean_and_variance_weighted 106 + * @initted: caller must track whether this is the first use or not 107 + * @weight: ewma weight 106 108 * 107 109 * see linked pdf: function derived from equations 140-143 where alpha = 2^w. 108 110 * values are stored bitshifted for performance and added precision. 109 111 */ 110 - void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64 x) 112 + void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, 113 + s64 x, bool initted, u8 weight) 111 114 { 112 115 // previous weighted variance. 113 - u8 w = s->weight; 116 + u8 w = weight; 114 117 u64 var_w0 = s->variance; 115 118 // new value weighted. 116 119 s64 x_w = x << w; ··· 122 119 // new mean weighted. 123 120 s64 u_w1 = s->mean + diff; 124 121 125 - if (!s->init) { 122 + if (!initted) { 126 123 s->mean = x_w; 127 124 s->variance = 0; 128 125 } else { 129 126 s->mean = u_w1; 130 127 s->variance = ((var_w0 << w) - var_w0 + ((diff_w * (x_w - u_w1)) >> w)) >> w; 131 128 } 132 - s->init = true; 133 129 } 134 130 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_update); 135 131 136 132 /** 137 133 * mean_and_variance_weighted_get_mean() - get mean from @s 138 134 * @s: mean and variance number of samples and their sums 135 + * @weight: ewma weight 139 136 */ 140 - s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s) 137 + s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s, 138 + u8 weight) 141 139 { 142 - return fast_divpow2(s.mean, s.weight); 140 + return fast_divpow2(s.mean, weight); 143 141 } 144 142 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_mean); 145 143 146 144 /** 147 145 * mean_and_variance_weighted_get_variance() -- get variance from @s 148 146 * @s: mean and variance number of samples and their sums 147 + * @weight: ewma weight 149 148 */ 150 - u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s) 149 + u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s, 150 + u8 weight) 151 151 { 152 152 // always positive don't need fast divpow2 153 - return s.variance >> s.weight; 153 + return s.variance >> weight; 154 154 } 155 155 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_variance); 156 156 157 157 /** 158 158 * mean_and_variance_weighted_get_stddev() - get standard deviation from @s 159 159 * @s: mean and variance number of samples and their sums 160 + * @weight: ewma weight 160 161 */ 161 - u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s) 162 + u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s, 163 + u8 weight) 162 164 { 163 - return int_sqrt64(mean_and_variance_weighted_get_variance(s)); 165 + return int_sqrt64(mean_and_variance_weighted_get_variance(s, weight)); 164 166 } 165 167 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_stddev); 166 168
+8 -6
fs/bcachefs/mean_and_variance.h
··· 154 154 155 155 /* expontentially weighted variant */ 156 156 struct mean_and_variance_weighted { 157 - bool init; 158 - u8 weight; /* base 2 logarithim */ 159 157 s64 mean; 160 158 u64 variance; 161 159 }; ··· 190 192 u64 mean_and_variance_get_variance(struct mean_and_variance s1); 191 193 u32 mean_and_variance_get_stddev(struct mean_and_variance s); 192 194 193 - void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64 v); 195 + void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, 196 + s64 v, bool initted, u8 weight); 194 197 195 - s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s); 196 - u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s); 197 - u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s); 198 + s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s, 199 + u8 weight); 200 + u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s, 201 + u8 weight); 202 + u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s, 203 + u8 weight); 198 204 199 205 #endif // MEAN_AND_VAIRANCE_H_
+43 -37
fs/bcachefs/mean_and_variance_test.c
··· 31 31 32 32 static void mean_and_variance_weighted_test(struct kunit *test) 33 33 { 34 - struct mean_and_variance_weighted s = { .weight = 2 }; 34 + struct mean_and_variance_weighted s = { }; 35 35 36 - mean_and_variance_weighted_update(&s, 10); 37 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 10); 38 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 0); 36 + mean_and_variance_weighted_update(&s, 10, false, 2); 37 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), 10); 38 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 0); 39 39 40 - mean_and_variance_weighted_update(&s, 20); 41 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 12); 42 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 18); 40 + mean_and_variance_weighted_update(&s, 20, true, 2); 41 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), 12); 42 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 18); 43 43 44 - mean_and_variance_weighted_update(&s, 30); 45 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 16); 46 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 72); 44 + mean_and_variance_weighted_update(&s, 30, true, 2); 45 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), 16); 46 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 72); 47 47 48 - s = (struct mean_and_variance_weighted) { .weight = 2 }; 48 + s = (struct mean_and_variance_weighted) { }; 49 49 50 - mean_and_variance_weighted_update(&s, -10); 51 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -10); 52 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 0); 50 + mean_and_variance_weighted_update(&s, -10, false, 2); 51 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), -10); 52 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 0); 53 53 54 - mean_and_variance_weighted_update(&s, -20); 55 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -12); 56 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 18); 54 + mean_and_variance_weighted_update(&s, -20, true, 2); 55 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), -12); 56 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 18); 57 57 58 - mean_and_variance_weighted_update(&s, -30); 59 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -16); 60 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 72); 58 + mean_and_variance_weighted_update(&s, -30, true, 2); 59 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), -16); 60 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 72); 61 61 } 62 62 63 63 static void mean_and_variance_weighted_advanced_test(struct kunit *test) 64 64 { 65 - struct mean_and_variance_weighted s = { .weight = 8 }; 65 + struct mean_and_variance_weighted s = { }; 66 + bool initted = false; 66 67 s64 i; 67 68 68 - for (i = 10; i <= 100; i += 10) 69 - mean_and_variance_weighted_update(&s, i); 69 + for (i = 10; i <= 100; i += 10) { 70 + mean_and_variance_weighted_update(&s, i, initted, 8); 71 + initted = true; 72 + } 70 73 71 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 11); 72 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 107); 74 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 8), 11); 75 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 8), 107); 73 76 74 - s = (struct mean_and_variance_weighted) { .weight = 8 }; 77 + s = (struct mean_and_variance_weighted) { }; 78 + initted = false; 75 79 76 - for (i = -10; i >= -100; i -= 10) 77 - mean_and_variance_weighted_update(&s, i); 80 + for (i = -10; i >= -100; i -= 10) { 81 + mean_and_variance_weighted_update(&s, i, initted, 8); 82 + initted = true; 83 + } 78 84 79 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -11); 80 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 107); 85 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 8), -11); 86 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 8), 107); 81 87 } 82 88 83 89 static void do_mean_and_variance_test(struct kunit *test, ··· 98 92 s64 *weighted_stddev) 99 93 { 100 94 struct mean_and_variance mv = {}; 101 - struct mean_and_variance_weighted vw = { .weight = weight }; 95 + struct mean_and_variance_weighted vw = { }; 102 96 103 97 for (unsigned i = 0; i < initial_n; i++) { 104 98 mean_and_variance_update(&mv, initial_value); 105 - mean_and_variance_weighted_update(&vw, initial_value); 99 + mean_and_variance_weighted_update(&vw, initial_value, false, weight); 106 100 107 101 KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), initial_value); 108 102 KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), 0); 109 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), initial_value); 110 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),0); 103 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight), initial_value); 104 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),0); 111 105 } 112 106 113 107 for (unsigned i = 0; i < n; i++) { 114 108 mean_and_variance_update(&mv, data[i]); 115 - mean_and_variance_weighted_update(&vw, data[i]); 109 + mean_and_variance_weighted_update(&vw, data[i], true, weight); 116 110 117 111 KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), mean[i]); 118 112 KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), stddev[i]); 119 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), weighted_mean[i]); 120 - KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),weighted_stddev[i]); 113 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight), weighted_mean[i]); 114 + KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),weighted_stddev[i]); 121 115 } 122 116 123 117 KUNIT_EXPECT_EQ(test, mv.n, initial_n + n);
+6 -9
fs/bcachefs/time_stats.c
··· 70 70 u64 start, u64 end) 71 71 { 72 72 u64 duration, freq; 73 + bool initted = stats->last_event != 0; 73 74 74 75 if (time_after64(end, start)) { 75 76 duration = end - start; 76 77 mean_and_variance_update(&stats->duration_stats, duration); 77 - mean_and_variance_weighted_update(&stats->duration_stats_weighted, duration); 78 + mean_and_variance_weighted_update(&stats->duration_stats_weighted, 79 + duration, initted, TIME_STATS_MV_WEIGHT); 78 80 stats->max_duration = max(stats->max_duration, duration); 79 81 stats->min_duration = min(stats->min_duration, duration); 80 82 stats->total_duration += duration; ··· 88 86 if (stats->last_event && time_after64(end, stats->last_event)) { 89 87 freq = end - stats->last_event; 90 88 mean_and_variance_update(&stats->freq_stats, freq); 91 - mean_and_variance_weighted_update(&stats->freq_stats_weighted, freq); 89 + mean_and_variance_weighted_update(&stats->freq_stats_weighted, 90 + freq, initted, TIME_STATS_MV_WEIGHT); 92 91 stats->max_freq = max(stats->max_freq, freq); 93 92 stats->min_freq = min(stats->min_freq, freq); 94 93 } ··· 121 118 { 122 119 unsigned long flags; 123 120 124 - WARN_ONCE(!stats->duration_stats_weighted.weight || 125 - !stats->freq_stats_weighted.weight, 126 - "uninitialized bch2_time_stats"); 127 - 128 121 if (!stats->buffer) { 129 122 spin_lock_irqsave(&stats->lock, flags); 130 123 time_stats_update_one(stats, start, end); 131 124 132 - if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted) < 32 && 125 + if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT) < 32 && 133 126 stats->duration_stats.n > 1024) 134 127 stats->buffer = 135 128 alloc_percpu_gfp(struct time_stat_buffer, ··· 157 158 void bch2_time_stats_init(struct bch2_time_stats *stats) 158 159 { 159 160 memset(stats, 0, sizeof(*stats)); 160 - stats->duration_stats_weighted.weight = 8; 161 - stats->freq_stats_weighted.weight = 8; 162 161 stats->min_duration = U64_MAX; 163 162 stats->min_freq = U64_MAX; 164 163 spin_lock_init(&stats->lock);
+5 -1
fs/bcachefs/time_stats.h
··· 80 80 struct quantiles quantiles; 81 81 82 82 struct mean_and_variance duration_stats; 83 - struct mean_and_variance_weighted duration_stats_weighted; 84 83 struct mean_and_variance freq_stats; 84 + 85 + /* default weight for weighted mean and variance calculations */ 86 + #define TIME_STATS_MV_WEIGHT 8 87 + 88 + struct mean_and_variance_weighted duration_stats_weighted; 85 89 struct mean_and_variance_weighted freq_stats_weighted; 86 90 struct time_stat_buffer __percpu *buffer; 87 91 };
+4 -4
fs/bcachefs/util.c
··· 428 428 prt_tab(out); 429 429 bch2_pr_time_units_aligned(out, d_mean); 430 430 prt_tab(out); 431 - bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->duration_stats_weighted)); 431 + bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->duration_stats_weighted, TIME_STATS_MV_WEIGHT)); 432 432 prt_newline(out); 433 433 434 434 prt_printf(out, "stddev:"); 435 435 prt_tab(out); 436 436 bch2_pr_time_units_aligned(out, d_stddev); 437 437 prt_tab(out); 438 - bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->duration_stats_weighted)); 438 + bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->duration_stats_weighted, TIME_STATS_MV_WEIGHT)); 439 439 440 440 printbuf_indent_sub(out, 2); 441 441 prt_newline(out); ··· 451 451 prt_tab(out); 452 452 bch2_pr_time_units_aligned(out, f_mean); 453 453 prt_tab(out); 454 - bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->freq_stats_weighted)); 454 + bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT)); 455 455 prt_newline(out); 456 456 457 457 prt_printf(out, "stddev:"); 458 458 prt_tab(out); 459 459 bch2_pr_time_units_aligned(out, f_stddev); 460 460 prt_tab(out); 461 - bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->freq_stats_weighted)); 461 + bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT)); 462 462 463 463 printbuf_indent_sub(out, 2); 464 464 prt_newline(out);