summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hill <daniel@gluo.nz>2022-07-25 11:54:28 +1200
committerDaniel Hill <daniel@gluo.nz>2022-08-18 15:59:02 +1200
commit3949cd13db27bf3b74c0069f1ec1229e22816885 (patch)
tree88549766f88631db819da211e24bb780ea57184f
parentb781f3dd87ec22713c2ae7376a1a6a7e08156dcc (diff)
bcachefs: time stats now shows standard deviation.
Signed-off-by: Daniel Hill <daniel@gluo.nz>
-rw-r--r--fs/bcachefs/Kconfig5
-rw-r--r--fs/bcachefs/Makefile2
-rw-r--r--fs/bcachefs/unit_tests.c48
-rw-r--r--fs/bcachefs/unit_tests.h6
-rw-r--r--fs/bcachefs/util.c17
-rw-r--r--fs/bcachefs/util.h19
6 files changed, 90 insertions, 7 deletions
diff --git a/fs/bcachefs/Kconfig b/fs/bcachefs/Kconfig
index 008886967841..cc3816ccca19 100644
--- a/fs/bcachefs/Kconfig
+++ b/fs/bcachefs/Kconfig
@@ -57,3 +57,8 @@ config BCACHEFS_LOCK_TIME_STATS
depends on BCACHEFS_FS
help
Expose statistics for how long we held a lock in debugfs
+
+config BCACHEFS_UNIT_TESTS
+ tristate "bcachefs kunit tests" if !KUNIT_ALL_TESTS
+ depends on BCACHEFS_FS && KUNIT
+ default KUNIT_ALL_TESTS
diff --git a/fs/bcachefs/Makefile b/fs/bcachefs/Makefile
index 5dad8ed03a20..a54f58bd273f 100644
--- a/fs/bcachefs/Makefile
+++ b/fs/bcachefs/Makefile
@@ -67,3 +67,5 @@ bcachefs-y := \
xattr.o
bcachefs-$(CONFIG_BCACHEFS_POSIX_ACL) += acl.o
+
+obj-$(CONFIG_BCACHEFS_UNIT_TESTS) += unit_tests.o
diff --git a/fs/bcachefs/unit_tests.c b/fs/bcachefs/unit_tests.c
new file mode 100644
index 000000000000..59490bab2e7f
--- /dev/null
+++ b/fs/bcachefs/unit_tests.c
@@ -0,0 +1,48 @@
+#include <kunit/test.h>
+#include "util.h"
+
+static void util_test_basic(struct kunit *test)
+{
+ u64 mean = 0;
+ u64 var = 0;
+ u64 i;
+ u64 val;
+
+ for ( i = 100 ; i <= 540 ; i += 20 ) {
+ ewma_cal(&mean, &var, 8, i);
+ }
+ val = 119;
+ KUNIT_EXPECT_GE(test, mean, val - val / 10);
+ KUNIT_EXPECT_LE(test, mean, val + val / 10);
+
+ val = 5442;
+ KUNIT_EXPECT_GE(test, var, val - val / 10);
+ KUNIT_EXPECT_LE(test, var, val + val / 10);
+
+ mean = 0;
+ var = 0;
+
+ for ( i = 1000 ; i <= 5400 ; i += 200 ) {
+ ewma_cal(&mean, &var, 8, i);
+ }
+ val = 1192;
+ KUNIT_EXPECT_GE(test, mean, val - val / 100);
+ KUNIT_EXPECT_LE(test, mean, val + val / 100);
+
+ val = 544257;
+ KUNIT_EXPECT_GE(test, var, val - val / 100);
+ KUNIT_EXPECT_LE(test, var, val + val / 100);
+
+}
+
+static struct kunit_case util_test_cases[] = {
+ KUNIT_CASE(util_test_basic),
+ {}
+};
+
+static struct kunit_suite util_test_suite = {
+.name = "util test cases",
+.test_cases = util_test_cases
+};
+
+kunit_test_suite(util_test_suite);
diff --git a/fs/bcachefs/unit_tests.h b/fs/bcachefs/unit_tests.h
new file mode 100644
index 000000000000..59111ba18768
--- /dev/null
+++ b/fs/bcachefs/unit_tests.h
@@ -0,0 +1,6 @@
+#ifndef UNIT_TESTS_H_
+#define UNIT_TESTS_H_
+
+
+
+#endif // UNIT_TESTS_H_
diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c
index 42da6623d815..533da82b935e 100644
--- a/fs/bcachefs/util.c
+++ b/fs/bcachefs/util.c
@@ -288,13 +288,12 @@ static void bch2_time_stats_update_one(struct time_stats *stats,
stats->count++;
- stats->average_duration = stats->average_duration
- ? ewma_add(stats->average_duration, duration, 6)
- : duration;
-
- stats->average_frequency = stats->average_frequency
- ? ewma_add(stats->average_frequency, freq, 6)
- : freq;
+ ewma_cal(&stats->average_duration,
+ &stats->variance_duration,
+ 8, duration);
+ ewma_cal(&stats->average_frequency,
+ NULL,
+ 8, freq);
stats->max_duration = max(stats->max_duration, duration);
@@ -397,6 +396,10 @@ void bch2_time_stats_to_text(struct printbuf *out, struct time_stats *stats)
pr_time_units(out, stats->average_duration);
prt_newline(out);
+ prt_printf(out, "stddev duration:\t");
+ pr_time_units(out, int_sqrt64(stats->variance_duration));
+
+ prt_newline(out);
prt_printf(out, "max duration:\t");
pr_time_units(out, stats->max_duration);
diff --git a/fs/bcachefs/util.h b/fs/bcachefs/util.h
index ab7e43d4bf8b..88619f06b437 100644
--- a/fs/bcachefs/util.h
+++ b/fs/bcachefs/util.h
@@ -381,6 +381,7 @@ struct time_stats {
/* all fields are in nanoseconds */
u64 average_duration;
u64 average_frequency;
+ u64 variance_duration;
u64 max_duration;
u64 last_event;
struct quantiles quantiles;
@@ -408,6 +409,24 @@ void bch2_time_stats_init(struct time_stats *);
(((_ewma << _weight) - _ewma) + (val)) >> _weight; \
})
+static inline void ewma_cal(u64 *_mean, u64 *_variance, u64 weight, u64 val)
+{
+ u64 m = *_mean;
+ u64 v = *_variance;
+ s64 d = val - m;
+ u64 d2 = d*d;
+
+ if (m) {
+ *_mean = ((m << weight) + d) >> weight;
+ if (_variance)
+ *_variance = (((1 << weight) - 1) * ( (v << weight) + d2)) >> (weight + weight);
+ } else {
+ *_mean = val;
+ if (_variance)
+ *_variance = 0;
+ }
+}
+
struct bch_ratelimit {
/* Next time we want to do some work, in nanoseconds */
u64 next;