bcachefs: mean_and_variance: put struct mean_and_variance_weighted on a diet
authorDarrick J. Wong <djwong@kernel.org>
Thu, 8 Feb 2024 23:33:35 +0000 (18:33 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 14 Mar 2024 01:37:58 +0000 (21:37 -0400)
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>
fs/bcachefs/mean_and_variance.c
fs/bcachefs/mean_and_variance.h
fs/bcachefs/mean_and_variance_test.c
fs/bcachefs/time_stats.c
fs/bcachefs/time_stats.h
fs/bcachefs/util.c

index bf0ef668fd38324132b737e648e3ffcb143bbe92..0ea9f30803a2b3da1372fd1d282dbb56f25d3920 100644 (file)
@@ -103,14 +103,17 @@ EXPORT_SYMBOL_GPL(mean_and_variance_get_stddev);
  * mean_and_variance_weighted_update() - exponentially weighted variant of mean_and_variance_update()
  * @s: mean and variance number of samples and their sums
  * @x: new value to include in the &mean_and_variance_weighted
+ * @initted: caller must track whether this is the first use or not
+ * @weight: ewma weight
  *
  * see linked pdf: function derived from equations 140-143 where alpha = 2^w.
  * values are stored bitshifted for performance and added precision.
  */
-void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64 x)
+void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s,
+               s64 x, bool initted, u8 weight)
 {
        // previous weighted variance.
-       u8 w            = s->weight;
+       u8 w            = weight;
        u64 var_w0      = s->variance;
        // new value weighted.
        s64 x_w         = x << w;
@@ -119,45 +122,50 @@ void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64
        // new mean weighted.
        s64 u_w1        = s->mean + diff;
 
-       if (!s->init) {
+       if (!initted) {
                s->mean = x_w;
                s->variance = 0;
        } else {
                s->mean = u_w1;
                s->variance = ((var_w0 << w) - var_w0 + ((diff_w * (x_w - u_w1)) >> w)) >> w;
        }
-       s->init = true;
 }
 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_update);
 
 /**
  * mean_and_variance_weighted_get_mean() - get mean from @s
  * @s: mean and variance number of samples and their sums
+ * @weight: ewma weight
  */
-s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s)
+s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s,
+               u8 weight)
 {
-       return fast_divpow2(s.mean, s.weight);
+       return fast_divpow2(s.mean, weight);
 }
 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_mean);
 
 /**
  * mean_and_variance_weighted_get_variance() -- get variance from @s
  * @s: mean and variance number of samples and their sums
+ * @weight: ewma weight
  */
-u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s)
+u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s,
+               u8 weight)
 {
        // always positive don't need fast divpow2
-       return s.variance >> s.weight;
+       return s.variance >> weight;
 }
 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_variance);
 
 /**
  * mean_and_variance_weighted_get_stddev() - get standard deviation from @s
  * @s: mean and variance number of samples and their sums
+ * @weight: ewma weight
  */
-u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s)
+u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s,
+               u8 weight)
 {
-       return int_sqrt64(mean_and_variance_weighted_get_variance(s));
+       return int_sqrt64(mean_and_variance_weighted_get_variance(s, weight));
 }
 EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_stddev);
 
index 64df11ab422bf455560bad095973cc6e5a296697..4fcf062dd22c71efd338a9ab37a8e1af5ca22ce5 100644 (file)
@@ -154,8 +154,6 @@ struct mean_and_variance {
 
 /* expontentially weighted variant */
 struct mean_and_variance_weighted {
-       bool    init;
-       u8      weight; /* base 2 logarithim */
        s64     mean;
        u64     variance;
 };
@@ -192,10 +190,14 @@ s64 mean_and_variance_get_mean(struct mean_and_variance s);
 u64 mean_and_variance_get_variance(struct mean_and_variance s1);
 u32 mean_and_variance_get_stddev(struct mean_and_variance s);
 
-void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64 v);
+void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s,
+               s64 v, bool initted, u8 weight);
 
-s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s);
-u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s);
-u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s);
+s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s,
+               u8 weight);
+u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s,
+               u8 weight);
+u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s,
+               u8 weight);
 
 #endif // MEAN_AND_VAIRANCE_H_
index 019583c3ca0eaba79f932223eedfe5a386ffdfa9..db63b3f3b338ad6405ceb34c4526a52765cca7af 100644 (file)
@@ -31,53 +31,59 @@ static void mean_and_variance_basic_test(struct kunit *test)
 
 static void mean_and_variance_weighted_test(struct kunit *test)
 {
-       struct mean_and_variance_weighted s = { .weight = 2 };
+       struct mean_and_variance_weighted s = { };
 
-       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);
+       mean_and_variance_weighted_update(&s, 10, false, 2);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), 10);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 0);
 
-       mean_and_variance_weighted_update(&s, 20);
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 12);
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 18);
+       mean_and_variance_weighted_update(&s, 20, true, 2);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), 12);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 18);
 
-       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);
+       mean_and_variance_weighted_update(&s, 30, true, 2);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), 16);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 72);
 
-       s = (struct mean_and_variance_weighted) { .weight = 2 };
+       s = (struct mean_and_variance_weighted) { };
 
-       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);
+       mean_and_variance_weighted_update(&s, -10, false, 2);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), -10);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 0);
 
-       mean_and_variance_weighted_update(&s, -20);
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -12);
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 18);
+       mean_and_variance_weighted_update(&s, -20, true, 2);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), -12);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 18);
 
-       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);
+       mean_and_variance_weighted_update(&s, -30, true, 2);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 2), -16);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 2), 72);
 }
 
 static void mean_and_variance_weighted_advanced_test(struct kunit *test)
 {
-       struct mean_and_variance_weighted s = { .weight = 8 };
+       struct mean_and_variance_weighted s = { };
+       bool initted = false;
        s64 i;
 
-       for (i = 10; i <= 100; i += 10)
-               mean_and_variance_weighted_update(&s, i);
+       for (i = 10; i <= 100; i += 10) {
+               mean_and_variance_weighted_update(&s, i, initted, 8);
+               initted = true;
+       }
 
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), 11);
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 107);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 8), 11);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 8), 107);
 
-       s = (struct mean_and_variance_weighted) { .weight = 8 };
+       s = (struct mean_and_variance_weighted) { };
+       initted = false;
 
-       for (i = -10; i >= -100; i -= 10)
-               mean_and_variance_weighted_update(&s, i);
+       for (i = -10; i >= -100; i -= 10) {
+               mean_and_variance_weighted_update(&s, i, initted, 8);
+               initted = true;
+       }
 
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s), -11);
-       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s), 107);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(s, 8), -11);
+       KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_variance(s, 8), 107);
 }
 
 static void do_mean_and_variance_test(struct kunit *test,
@@ -92,26 +98,26 @@ static void do_mean_and_variance_test(struct kunit *test,
                                      s64 *weighted_stddev)
 {
        struct mean_and_variance mv = {};
-       struct mean_and_variance_weighted vw = { .weight = weight };
+       struct mean_and_variance_weighted vw = { };
 
        for (unsigned i = 0; i < initial_n; i++) {
                mean_and_variance_update(&mv, initial_value);
-               mean_and_variance_weighted_update(&vw, initial_value);
+               mean_and_variance_weighted_update(&vw, initial_value, false, weight);
 
                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);
+               KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight),  initial_value);
+               KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),0);
        }
 
        for (unsigned i = 0; i < n; i++) {
                mean_and_variance_update(&mv, data[i]);
-               mean_and_variance_weighted_update(&vw, data[i]);
+               mean_and_variance_weighted_update(&vw, data[i], true, weight);
 
                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, mean_and_variance_weighted_get_mean(vw, weight),  weighted_mean[i]);
+               KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),weighted_stddev[i]);
        }
 
        KUNIT_EXPECT_EQ(test, mv.n, initial_n + n);
index af97474c445bfb3e24d4abcd698a29e366ee960d..4ac6ebfd264c768b6a343b107864242e1f409766 100644 (file)
@@ -70,11 +70,13 @@ static inline void time_stats_update_one(struct bch2_time_stats *stats,
                                              u64 start, u64 end)
 {
        u64 duration, freq;
+       bool initted = stats->last_event != 0;
 
        if (time_after64(end, start)) {
                duration = end - start;
                mean_and_variance_update(&stats->duration_stats, duration);
-               mean_and_variance_weighted_update(&stats->duration_stats_weighted, duration);
+               mean_and_variance_weighted_update(&stats->duration_stats_weighted,
+                               duration, initted, TIME_STATS_MV_WEIGHT);
                stats->max_duration = max(stats->max_duration, duration);
                stats->min_duration = min(stats->min_duration, duration);
                stats->total_duration += duration;
@@ -86,7 +88,8 @@ static inline void time_stats_update_one(struct bch2_time_stats *stats,
        if (stats->last_event && time_after64(end, stats->last_event)) {
                freq = end - stats->last_event;
                mean_and_variance_update(&stats->freq_stats, freq);
-               mean_and_variance_weighted_update(&stats->freq_stats_weighted, freq);
+               mean_and_variance_weighted_update(&stats->freq_stats_weighted,
+                               freq, initted, TIME_STATS_MV_WEIGHT);
                stats->max_freq = max(stats->max_freq, freq);
                stats->min_freq = min(stats->min_freq, freq);
        }
@@ -118,15 +121,11 @@ void __bch2_time_stats_update(struct bch2_time_stats *stats, u64 start, u64 end)
 {
        unsigned long flags;
 
-       WARN_ONCE(!stats->duration_stats_weighted.weight ||
-                 !stats->freq_stats_weighted.weight,
-                 "uninitialized bch2_time_stats");
-
        if (!stats->buffer) {
                spin_lock_irqsave(&stats->lock, flags);
                time_stats_update_one(stats, start, end);
 
-               if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted) < 32 &&
+               if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT) < 32 &&
                    stats->duration_stats.n > 1024)
                        stats->buffer =
                                alloc_percpu_gfp(struct time_stat_buffer,
@@ -158,8 +157,6 @@ void bch2_time_stats_exit(struct bch2_time_stats *stats)
 void bch2_time_stats_init(struct bch2_time_stats *stats)
 {
        memset(stats, 0, sizeof(*stats));
-       stats->duration_stats_weighted.weight = 8;
-       stats->freq_stats_weighted.weight = 8;
        stats->min_duration = U64_MAX;
        stats->min_freq = U64_MAX;
        spin_lock_init(&stats->lock);
index d0291ea863ba661aaf3fa98ec14ff47615cb5336..fd6e442443f94d34ef7fc4c06e016a8f0ad3c3e5 100644 (file)
@@ -80,8 +80,12 @@ struct bch2_time_stats {
        struct quantiles quantiles;
 
        struct mean_and_variance          duration_stats;
-       struct mean_and_variance_weighted duration_stats_weighted;
        struct mean_and_variance          freq_stats;
+
+/* default weight for weighted mean and variance calculations */
+#define TIME_STATS_MV_WEIGHT   8
+
+       struct mean_and_variance_weighted duration_stats_weighted;
        struct mean_and_variance_weighted freq_stats_weighted;
        struct time_stat_buffer __percpu *buffer;
 };
index 96de039fc8908e3f429b81bd6b85a687075968bf..0f11e0c4e46d34f9c4a5a3201a6378215f25425a 100644 (file)
@@ -428,14 +428,14 @@ void bch2_time_stats_to_text(struct printbuf *out, struct bch2_time_stats *stats
        prt_tab(out);
        bch2_pr_time_units_aligned(out, d_mean);
        prt_tab(out);
-       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->duration_stats_weighted));
+       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->duration_stats_weighted, TIME_STATS_MV_WEIGHT));
        prt_newline(out);
 
        prt_printf(out, "stddev:");
        prt_tab(out);
        bch2_pr_time_units_aligned(out, d_stddev);
        prt_tab(out);
-       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->duration_stats_weighted));
+       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->duration_stats_weighted, TIME_STATS_MV_WEIGHT));
 
        printbuf_indent_sub(out, 2);
        prt_newline(out);
@@ -451,14 +451,14 @@ void bch2_time_stats_to_text(struct printbuf *out, struct bch2_time_stats *stats
        prt_tab(out);
        bch2_pr_time_units_aligned(out, f_mean);
        prt_tab(out);
-       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->freq_stats_weighted));
+       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_mean(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT));
        prt_newline(out);
 
        prt_printf(out, "stddev:");
        prt_tab(out);
        bch2_pr_time_units_aligned(out, f_stddev);
        prt_tab(out);
-       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->freq_stats_weighted));
+       bch2_pr_time_units_aligned(out, mean_and_variance_weighted_get_stddev(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT));
 
        printbuf_indent_sub(out, 2);
        prt_newline(out);