Skip to content

Commit 4b4f087

Browse files
Darrick J. WongKent Overstreet
authored andcommitted
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>
1 parent cdbfa22 commit 4b4f087

File tree

6 files changed

+84
-67
lines changed

6 files changed

+84
-67
lines changed

fs/bcachefs/mean_and_variance.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,17 @@ EXPORT_SYMBOL_GPL(mean_and_variance_get_stddev);
103103
* mean_and_variance_weighted_update() - exponentially weighted variant of mean_and_variance_update()
104104
* @s: mean and variance number of samples and their sums
105105
* @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
106108
*
107109
* see linked pdf: function derived from equations 140-143 where alpha = 2^w.
108110
* values are stored bitshifted for performance and added precision.
109111
*/
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)
111114
{
112115
// previous weighted variance.
113-
u8 w = s->weight;
116+
u8 w = weight;
114117
u64 var_w0 = s->variance;
115118
// new value weighted.
116119
s64 x_w = x << w;
@@ -119,45 +122,50 @@ void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64
119122
// new mean weighted.
120123
s64 u_w1 = s->mean + diff;
121124

122-
if (!s->init) {
125+
if (!initted) {
123126
s->mean = x_w;
124127
s->variance = 0;
125128
} else {
126129
s->mean = u_w1;
127130
s->variance = ((var_w0 << w) - var_w0 + ((diff_w * (x_w - u_w1)) >> w)) >> w;
128131
}
129-
s->init = true;
130132
}
131133
EXPORT_SYMBOL_GPL(mean_and_variance_weighted_update);
132134

133135
/**
134136
* mean_and_variance_weighted_get_mean() - get mean from @s
135137
* @s: mean and variance number of samples and their sums
138+
* @weight: ewma weight
136139
*/
137-
s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s)
140+
s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s,
141+
u8 weight)
138142
{
139-
return fast_divpow2(s.mean, s.weight);
143+
return fast_divpow2(s.mean, weight);
140144
}
141145
EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_mean);
142146

143147
/**
144148
* mean_and_variance_weighted_get_variance() -- get variance from @s
145149
* @s: mean and variance number of samples and their sums
150+
* @weight: ewma weight
146151
*/
147-
u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s)
152+
u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s,
153+
u8 weight)
148154
{
149155
// always positive don't need fast divpow2
150-
return s.variance >> s.weight;
156+
return s.variance >> weight;
151157
}
152158
EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_variance);
153159

154160
/**
155161
* mean_and_variance_weighted_get_stddev() - get standard deviation from @s
156162
* @s: mean and variance number of samples and their sums
163+
* @weight: ewma weight
157164
*/
158-
u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s)
165+
u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s,
166+
u8 weight)
159167
{
160-
return int_sqrt64(mean_and_variance_weighted_get_variance(s));
168+
return int_sqrt64(mean_and_variance_weighted_get_variance(s, weight));
161169
}
162170
EXPORT_SYMBOL_GPL(mean_and_variance_weighted_get_stddev);
163171

fs/bcachefs/mean_and_variance.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,6 @@ struct mean_and_variance {
154154

155155
/* expontentially weighted variant */
156156
struct mean_and_variance_weighted {
157-
bool init;
158-
u8 weight; /* base 2 logarithim */
159157
s64 mean;
160158
u64 variance;
161159
};
@@ -192,10 +190,14 @@ s64 mean_and_variance_get_mean(struct mean_and_variance s);
192190
u64 mean_and_variance_get_variance(struct mean_and_variance s1);
193191
u32 mean_and_variance_get_stddev(struct mean_and_variance s);
194192

195-
void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s, s64 v);
193+
void mean_and_variance_weighted_update(struct mean_and_variance_weighted *s,
194+
s64 v, bool initted, u8 weight);
196195

197-
s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s);
198-
u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s);
199-
u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s);
196+
s64 mean_and_variance_weighted_get_mean(struct mean_and_variance_weighted s,
197+
u8 weight);
198+
u64 mean_and_variance_weighted_get_variance(struct mean_and_variance_weighted s,
199+
u8 weight);
200+
u32 mean_and_variance_weighted_get_stddev(struct mean_and_variance_weighted s,
201+
u8 weight);
200202

201203
#endif // MEAN_AND_VAIRANCE_H_

fs/bcachefs/mean_and_variance_test.c

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,53 +31,59 @@ static void mean_and_variance_basic_test(struct kunit *test)
3131

3232
static void mean_and_variance_weighted_test(struct kunit *test)
3333
{
34-
struct mean_and_variance_weighted s = { .weight = 2 };
34+
struct mean_and_variance_weighted s = { };
3535

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);
3939

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);
4343

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);
4747

48-
s = (struct mean_and_variance_weighted) { .weight = 2 };
48+
s = (struct mean_and_variance_weighted) { };
4949

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);
5353

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);
5757

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);
6161
}
6262

6363
static void mean_and_variance_weighted_advanced_test(struct kunit *test)
6464
{
65-
struct mean_and_variance_weighted s = { .weight = 8 };
65+
struct mean_and_variance_weighted s = { };
66+
bool initted = false;
6667
s64 i;
6768

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+
}
7073

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);
7376

74-
s = (struct mean_and_variance_weighted) { .weight = 8 };
77+
s = (struct mean_and_variance_weighted) { };
78+
initted = false;
7579

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+
}
7884

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);
8187
}
8288

8389
static void do_mean_and_variance_test(struct kunit *test,
@@ -92,26 +98,26 @@ static void do_mean_and_variance_test(struct kunit *test,
9298
s64 *weighted_stddev)
9399
{
94100
struct mean_and_variance mv = {};
95-
struct mean_and_variance_weighted vw = { .weight = weight };
101+
struct mean_and_variance_weighted vw = { };
96102

97103
for (unsigned i = 0; i < initial_n; i++) {
98104
mean_and_variance_update(&mv, initial_value);
99-
mean_and_variance_weighted_update(&vw, initial_value);
105+
mean_and_variance_weighted_update(&vw, initial_value, false, weight);
100106

101107
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), initial_value);
102108
KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), 0);
103-
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), initial_value);
104-
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),0);
109+
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight), initial_value);
110+
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),0);
105111
}
106112

107113
for (unsigned i = 0; i < n; i++) {
108114
mean_and_variance_update(&mv, data[i]);
109-
mean_and_variance_weighted_update(&vw, data[i]);
115+
mean_and_variance_weighted_update(&vw, data[i], true, weight);
110116

111117
KUNIT_EXPECT_EQ(test, mean_and_variance_get_mean(mv), mean[i]);
112118
KUNIT_EXPECT_EQ(test, mean_and_variance_get_stddev(mv), stddev[i]);
113-
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw), weighted_mean[i]);
114-
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw),weighted_stddev[i]);
119+
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_mean(vw, weight), weighted_mean[i]);
120+
KUNIT_EXPECT_EQ(test, mean_and_variance_weighted_get_stddev(vw, weight),weighted_stddev[i]);
115121
}
116122

117123
KUNIT_EXPECT_EQ(test, mv.n, initial_n + n);

fs/bcachefs/time_stats.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,13 @@ static inline void time_stats_update_one(struct bch2_time_stats *stats,
7070
u64 start, u64 end)
7171
{
7272
u64 duration, freq;
73+
bool initted = stats->last_event != 0;
7374

7475
if (time_after64(end, start)) {
7576
duration = end - start;
7677
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);
7880
stats->max_duration = max(stats->max_duration, duration);
7981
stats->min_duration = min(stats->min_duration, duration);
8082
stats->total_duration += duration;
@@ -86,7 +88,8 @@ static inline void time_stats_update_one(struct bch2_time_stats *stats,
8688
if (stats->last_event && time_after64(end, stats->last_event)) {
8789
freq = end - stats->last_event;
8890
mean_and_variance_update(&stats->freq_stats, freq);
89-
mean_and_variance_weighted_update(&stats->freq_stats_weighted, freq);
91+
mean_and_variance_weighted_update(&stats->freq_stats_weighted,
92+
freq, initted, TIME_STATS_MV_WEIGHT);
9093
stats->max_freq = max(stats->max_freq, freq);
9194
stats->min_freq = min(stats->min_freq, freq);
9295
}
@@ -118,15 +121,11 @@ void __bch2_time_stats_update(struct bch2_time_stats *stats, u64 start, u64 end)
118121
{
119122
unsigned long flags;
120123

121-
WARN_ONCE(!stats->duration_stats_weighted.weight ||
122-
!stats->freq_stats_weighted.weight,
123-
"uninitialized bch2_time_stats");
124-
125124
if (!stats->buffer) {
126125
spin_lock_irqsave(&stats->lock, flags);
127126
time_stats_update_one(stats, start, end);
128127

129-
if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted) < 32 &&
128+
if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted, TIME_STATS_MV_WEIGHT) < 32 &&
130129
stats->duration_stats.n > 1024)
131130
stats->buffer =
132131
alloc_percpu_gfp(struct time_stat_buffer,
@@ -158,8 +157,6 @@ void bch2_time_stats_exit(struct bch2_time_stats *stats)
158157
void bch2_time_stats_init(struct bch2_time_stats *stats)
159158
{
160159
memset(stats, 0, sizeof(*stats));
161-
stats->duration_stats_weighted.weight = 8;
162-
stats->freq_stats_weighted.weight = 8;
163160
stats->min_duration = U64_MAX;
164161
stats->min_freq = U64_MAX;
165162
spin_lock_init(&stats->lock);

fs/bcachefs/time_stats.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,12 @@ struct bch2_time_stats {
8080
struct quantiles quantiles;
8181

8282
struct mean_and_variance duration_stats;
83-
struct mean_and_variance_weighted duration_stats_weighted;
8483
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;
8589
struct mean_and_variance_weighted freq_stats_weighted;
8690
struct time_stat_buffer __percpu *buffer;
8791
};

fs/bcachefs/util.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,14 +428,14 @@ void bch2_time_stats_to_text(struct printbuf *out, struct bch2_time_stats *stats
428428
prt_tab(out);
429429
bch2_pr_time_units_aligned(out, d_mean);
430430
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));
432432
prt_newline(out);
433433

434434
prt_printf(out, "stddev:");
435435
prt_tab(out);
436436
bch2_pr_time_units_aligned(out, d_stddev);
437437
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));
439439

440440
printbuf_indent_sub(out, 2);
441441
prt_newline(out);
@@ -451,14 +451,14 @@ void bch2_time_stats_to_text(struct printbuf *out, struct bch2_time_stats *stats
451451
prt_tab(out);
452452
bch2_pr_time_units_aligned(out, f_mean);
453453
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));
455455
prt_newline(out);
456456

457457
prt_printf(out, "stddev:");
458458
prt_tab(out);
459459
bch2_pr_time_units_aligned(out, f_stddev);
460460
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));
462462

463463
printbuf_indent_sub(out, 2);
464464
prt_newline(out);

0 commit comments

Comments
 (0)