summaryrefslogtreecommitdiff
path: root/libbcachefs/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/util.c')
-rw-r--r--libbcachefs/util.c173
1 files changed, 133 insertions, 40 deletions
diff --git a/libbcachefs/util.c b/libbcachefs/util.c
index d1919350..f08215af 100644
--- a/libbcachefs/util.c
+++ b/libbcachefs/util.c
@@ -22,6 +22,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/sched/clock.h>
+#include <linux/mean_and_variance.h>
#include "eytzinger.h"
#include "util.h"
@@ -323,38 +324,44 @@ static void bch2_time_stats_update_one(struct time_stats *stats,
{
u64 duration, freq;
- duration = time_after64(end, start)
- ? end - start : 0;
- freq = time_after64(end, stats->last_event)
- ? end - stats->last_event : 0;
-
- 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;
-
- stats->max_duration = max(stats->max_duration, duration);
-
- stats->last_event = end;
+ if (time_after64(end, start)) {
+ duration = end - start;
+ stats->duration_stats = mean_and_variance_update(stats->duration_stats,
+ duration);
+ stats->duration_stats_weighted = mean_and_variance_weighted_update(
+ stats->duration_stats_weighted,
+ duration);
+ stats->max_duration = max(stats->max_duration, duration);
+ stats->min_duration = min(stats->min_duration, duration);
+ bch2_quantiles_update(&stats->quantiles, duration);
+ }
- bch2_quantiles_update(&stats->quantiles, duration);
+ if (time_after64(end, stats->last_event)) {
+ freq = end - stats->last_event;
+ stats->freq_stats = mean_and_variance_update(stats->freq_stats, freq);
+ stats->freq_stats_weighted = mean_and_variance_weighted_update(
+ stats->freq_stats_weighted,
+ freq);
+ stats->max_freq = max(stats->max_freq, freq);
+ stats->min_freq = min(stats->min_freq, freq);
+ stats->last_event = end;
+ }
}
void __bch2_time_stats_update(struct time_stats *stats, u64 start, u64 end)
{
unsigned long flags;
+ WARN_RATELIMIT(!stats->min_duration || !stats->min_freq,
+ "time_stats: min_duration = %llu, min_freq = %llu",
+ stats->min_duration, stats->min_freq);
+
if (!stats->buffer) {
spin_lock_irqsave(&stats->lock, flags);
bch2_time_stats_update_one(stats, start, end);
- if (stats->average_frequency < 32 &&
- stats->count > 1024)
+ if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted) < 32 &&
+ stats->duration_stats.n > 1024)
stats->buffer =
alloc_percpu_gfp(struct time_stat_buffer,
GFP_ATOMIC);
@@ -389,12 +396,15 @@ void __bch2_time_stats_update(struct time_stats *stats, u64 start, u64 end)
static const struct time_unit {
const char *name;
- u32 nsecs;
+ u64 nsecs;
} time_units[] = {
- { "ns", 1 },
- { "us", NSEC_PER_USEC },
- { "ms", NSEC_PER_MSEC },
- { "sec", NSEC_PER_SEC },
+ { "ns", 1 },
+ { "us", NSEC_PER_USEC },
+ { "ms", NSEC_PER_MSEC },
+ { "s", NSEC_PER_SEC },
+ { "m", NSEC_PER_SEC * 60},
+ { "h", NSEC_PER_SEC * 3600},
+ { "eon", U64_MAX },
};
static const struct time_unit *pick_time_units(u64 ns)
@@ -414,38 +424,117 @@ static void pr_time_units(struct printbuf *out, u64 ns)
{
const struct time_unit *u = pick_time_units(ns);
- prt_printf(out, "%llu %s", div_u64(ns, u->nsecs), u->name);
+ prt_printf(out, "%llu ", div64_u64(ns, u->nsecs));
+ prt_tab_rjust(out);
+ prt_printf(out, "%s", u->name);
+}
+
+#define TABSTOP_SIZE 12
+
+static inline void pr_name_and_units(struct printbuf *out, const char *name, u64 ns)
+{
+ prt_printf(out, name);
+ prt_tab(out);
+ pr_time_units(out, ns);
+ prt_newline(out);
}
void bch2_time_stats_to_text(struct printbuf *out, struct time_stats *stats)
{
const struct time_unit *u;
- u64 freq = READ_ONCE(stats->average_frequency);
- u64 q, last_q = 0;
+ s64 f_mean = 0, d_mean = 0;
+ u64 q, last_q = 0, f_stddev = 0, d_stddev = 0;
int i;
+ /*
+ * avoid divide by zero
+ */
+ if (stats->freq_stats.n) {
+ f_mean = mean_and_variance_get_mean(stats->freq_stats);
+ f_stddev = mean_and_variance_get_stddev(stats->freq_stats);
+ d_mean = mean_and_variance_get_mean(stats->duration_stats);
+ d_stddev = mean_and_variance_get_stddev(stats->duration_stats);
+ }
- prt_printf(out, "count:\t\t%llu",
- stats->count);
+ printbuf_tabstop_push(out, out->indent + TABSTOP_SIZE);
+ prt_printf(out, "count:");
+ prt_tab(out);
+ prt_printf(out, "%llu ",
+ stats->duration_stats.n);
+ printbuf_tabstop_pop(out);
prt_newline(out);
- prt_printf(out, "rate:\t\t%llu/sec",
- freq ? div64_u64(NSEC_PER_SEC, freq) : 0);
+
+ printbuf_tabstops_reset(out);
+
+ printbuf_tabstop_push(out, out->indent + 20);
+ printbuf_tabstop_push(out, TABSTOP_SIZE + 2);
+ printbuf_tabstop_push(out, 0);
+ printbuf_tabstop_push(out, TABSTOP_SIZE + 2);
+
+ prt_tab(out);
+ prt_printf(out, "since mount");
+ prt_tab_rjust(out);
+ prt_tab(out);
+ prt_printf(out, "recent");
+ prt_tab_rjust(out);
prt_newline(out);
- prt_printf(out, "frequency:\t");
- pr_time_units(out, freq);
+ printbuf_tabstops_reset(out);
+ printbuf_tabstop_push(out, out->indent + 20);
+ printbuf_tabstop_push(out, TABSTOP_SIZE);
+ printbuf_tabstop_push(out, 2);
+ printbuf_tabstop_push(out, TABSTOP_SIZE);
+ prt_printf(out, "duration of events");
prt_newline(out);
- prt_printf(out, "avg duration:\t");
- pr_time_units(out, stats->average_duration);
+ printbuf_indent_add(out, 2);
+
+ pr_name_and_units(out, "min:", stats->min_duration);
+ pr_name_and_units(out, "max:", stats->max_duration);
+ prt_printf(out, "mean:");
+ prt_tab(out);
+ pr_time_units(out, d_mean);
+ prt_tab(out);
+ pr_time_units(out, mean_and_variance_weighted_get_mean(stats->duration_stats_weighted));
prt_newline(out);
- prt_printf(out, "max duration:\t");
- pr_time_units(out, stats->max_duration);
+
+ prt_printf(out, "stddev:");
+ prt_tab(out);
+ pr_time_units(out, d_stddev);
+ prt_tab(out);
+ pr_time_units(out, mean_and_variance_weighted_get_stddev(stats->duration_stats_weighted));
+
+ printbuf_indent_sub(out, 2);
+ prt_newline(out);
+
+ prt_printf(out, "time between events");
+ prt_newline(out);
+ printbuf_indent_add(out, 2);
+
+ pr_name_and_units(out, "min:", stats->min_freq);
+ pr_name_and_units(out, "max:", stats->max_freq);
+
+ prt_printf(out, "mean:");
+ prt_tab(out);
+ pr_time_units(out, f_mean);
+ prt_tab(out);
+ pr_time_units(out, mean_and_variance_weighted_get_mean(stats->freq_stats_weighted));
+ prt_newline(out);
+
+ prt_printf(out, "stddev:");
+ prt_tab(out);
+ pr_time_units(out, f_stddev);
+ prt_tab(out);
+ pr_time_units(out, mean_and_variance_weighted_get_stddev(stats->freq_stats_weighted));
+
+ printbuf_indent_sub(out, 2);
+ prt_newline(out);
+
+ printbuf_tabstops_reset(out);
i = eytzinger0_first(NR_QUANTILES);
u = pick_time_units(stats->quantiles.entries[i].m);
- prt_newline(out);
prt_printf(out, "quantiles (%s):\t", u->name);
eytzinger0_for_each(i, NR_QUANTILES) {
bool is_last = eytzinger0_next(i, NR_QUANTILES) == -1;
@@ -467,6 +556,10 @@ void bch2_time_stats_exit(struct time_stats *stats)
void bch2_time_stats_init(struct time_stats *stats)
{
memset(stats, 0, sizeof(*stats));
+ stats->duration_stats_weighted.w = 8;
+ stats->freq_stats_weighted.w = 8;
+ stats->min_duration = U64_MAX;
+ stats->min_freq = U64_MAX;
spin_lock_init(&stats->lock);
}