From 3949cd13db27bf3b74c0069f1ec1229e22816885 Mon Sep 17 00:00:00 2001 From: Daniel Hill Date: Mon, 25 Jul 2022 11:54:28 +1200 Subject: bcachefs: time stats now shows standard deviation. Signed-off-by: Daniel Hill --- fs/bcachefs/Kconfig | 5 +++++ fs/bcachefs/Makefile | 2 ++ fs/bcachefs/unit_tests.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/bcachefs/unit_tests.h | 6 ++++++ fs/bcachefs/util.c | 17 ++++++++++------- fs/bcachefs/util.h | 19 +++++++++++++++++++ 6 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 fs/bcachefs/unit_tests.c create mode 100644 fs/bcachefs/unit_tests.h 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 +#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); @@ -396,6 +395,10 @@ void bch2_time_stats_to_text(struct printbuf *out, struct time_stats *stats) prt_printf(out, "avg duration:\t"); 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; -- cgit v1.2.3