Skip to content

Commit f1ca1ab

Browse files
author
Kent Overstreet
committed
bcachefs: pull out time_stats.[ch]
prep work for lifting out of fs/bcachefs/ Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent cdce109 commit f1ca1ab

File tree

11 files changed

+326
-279
lines changed

11 files changed

+326
-279
lines changed

fs/bcachefs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ bcachefs-y := \
8282
super-io.o \
8383
sysfs.o \
8484
tests.o \
85+
time_stats.o \
8586
thread_with_file.o \
8687
trace.o \
8788
two_state_shared_lock.o \

fs/bcachefs/alloc_foreground.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,7 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
236236
if (cl)
237237
closure_wait(&c->open_buckets_wait, cl);
238238

239-
track_event_change(&c->times[BCH_TIME_blocked_allocate_open_bucket],
240-
&c->blocked_allocate_open_bucket, true);
239+
track_event_change(&c->times[BCH_TIME_blocked_allocate_open_bucket], true);
241240
spin_unlock(&c->freelist_lock);
242241
return ERR_PTR(-BCH_ERR_open_buckets_empty);
243242
}
@@ -263,11 +262,8 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
263262
ca->nr_open_buckets++;
264263
bch2_open_bucket_hash_add(c, ob);
265264

266-
track_event_change(&c->times[BCH_TIME_blocked_allocate_open_bucket],
267-
&c->blocked_allocate_open_bucket, false);
268-
269-
track_event_change(&c->times[BCH_TIME_blocked_allocate],
270-
&c->blocked_allocate, false);
265+
track_event_change(&c->times[BCH_TIME_blocked_allocate_open_bucket], false);
266+
track_event_change(&c->times[BCH_TIME_blocked_allocate], false);
271267

272268
spin_unlock(&c->freelist_lock);
273269
return ob;
@@ -555,8 +551,7 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
555551
goto again;
556552
}
557553

558-
track_event_change(&c->times[BCH_TIME_blocked_allocate],
559-
&c->blocked_allocate, true);
554+
track_event_change(&c->times[BCH_TIME_blocked_allocate], true);
560555

561556
ob = ERR_PTR(-BCH_ERR_freelist_empty);
562557
goto err;

fs/bcachefs/bcachefs.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
#include "recovery_types.h"
213213
#include "sb-errors_types.h"
214214
#include "seqmutex.h"
215+
#include "time_stats.h"
215216
#include "util.h"
216217

217218
#ifdef CONFIG_BCACHEFS_DEBUG
@@ -924,8 +925,6 @@ struct bch_fs {
924925
/* ALLOCATOR */
925926
spinlock_t freelist_lock;
926927
struct closure_waitlist freelist_wait;
927-
u64 blocked_allocate;
928-
u64 blocked_allocate_open_bucket;
929928

930929
open_bucket_idx_t open_buckets_freelist;
931930
open_bucket_idx_t open_buckets_nr_free;

fs/bcachefs/journal.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,7 @@ static int __journal_res_get(struct journal *j, struct journal_res *res,
566566
ret = -BCH_ERR_journal_res_get_blocked;
567567

568568
if (ret == JOURNAL_ERR_max_in_flight &&
569-
track_event_change(&c->times[BCH_TIME_blocked_journal_max_in_flight],
570-
&j->max_in_flight_start, true)) {
569+
track_event_change(&c->times[BCH_TIME_blocked_journal_max_in_flight], true)) {
571570

572571
struct printbuf buf = PRINTBUF;
573572
prt_printf(&buf, "seq %llu\n", journal_cur_seq(j));

fs/bcachefs/journal_io.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,8 +1680,7 @@ static CLOSURE_CALLBACK(journal_write_done)
16801680
bch2_journal_reclaim_fast(j);
16811681
bch2_journal_space_available(j);
16821682

1683-
track_event_change(&c->times[BCH_TIME_blocked_journal_max_in_flight],
1684-
&j->max_in_flight_start, false);
1683+
track_event_change(&c->times[BCH_TIME_blocked_journal_max_in_flight], false);
16851684

16861685
journal_wake(j);
16871686
}

fs/bcachefs/journal_reclaim.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,9 @@ void bch2_journal_set_watermark(struct journal *j)
6262
? BCH_WATERMARK_reclaim
6363
: BCH_WATERMARK_stripe;
6464

65-
if (track_event_change(&c->times[BCH_TIME_blocked_journal_low_on_space],
66-
&j->low_on_space_start, low_on_space) ||
67-
track_event_change(&c->times[BCH_TIME_blocked_journal_low_on_pin],
68-
&j->low_on_pin_start, low_on_pin) ||
69-
track_event_change(&c->times[BCH_TIME_blocked_write_buffer_full],
70-
&j->write_buffer_full_start, low_on_wb))
65+
if (track_event_change(&c->times[BCH_TIME_blocked_journal_low_on_space], low_on_space) ||
66+
track_event_change(&c->times[BCH_TIME_blocked_journal_low_on_pin], low_on_pin) ||
67+
track_event_change(&c->times[BCH_TIME_blocked_write_buffer_full], low_on_wb))
7168
trace_and_count(c, journal_full, c);
7269

7370
swap(watermark, j->watermark);

fs/bcachefs/journal_types.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,6 @@ struct journal {
287287
u64 nr_noflush_writes;
288288
u64 entry_bytes_written;
289289

290-
u64 low_on_space_start;
291-
u64 low_on_pin_start;
292-
u64 max_in_flight_start;
293-
u64 write_buffer_full_start;
294-
295290
struct bch2_time_stats *flush_write_time;
296291
struct bch2_time_stats *noflush_write_time;
297292
struct bch2_time_stats *flush_seq_time;

fs/bcachefs/time_stats.c

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/jiffies.h>
4+
#include <linux/module.h>
5+
#include <linux/percpu.h>
6+
#include <linux/preempt.h>
7+
#include <linux/time.h>
8+
#include <linux/spinlock.h>
9+
10+
#include "eytzinger.h"
11+
#include "time_stats.h"
12+
13+
static const struct time_unit time_units[] = {
14+
{ "ns", 1 },
15+
{ "us", NSEC_PER_USEC },
16+
{ "ms", NSEC_PER_MSEC },
17+
{ "s", NSEC_PER_SEC },
18+
{ "m", (u64) NSEC_PER_SEC * 60},
19+
{ "h", (u64) NSEC_PER_SEC * 3600},
20+
{ "eon", U64_MAX },
21+
};
22+
23+
const struct time_unit *bch2_pick_time_units(u64 ns)
24+
{
25+
const struct time_unit *u;
26+
27+
for (u = time_units;
28+
u + 1 < time_units + ARRAY_SIZE(time_units) &&
29+
ns >= u[1].nsecs << 1;
30+
u++)
31+
;
32+
33+
return u;
34+
}
35+
36+
static void quantiles_update(struct quantiles *q, u64 v)
37+
{
38+
unsigned i = 0;
39+
40+
while (i < ARRAY_SIZE(q->entries)) {
41+
struct quantile_entry *e = q->entries + i;
42+
43+
if (unlikely(!e->step)) {
44+
e->m = v;
45+
e->step = max_t(unsigned, v / 2, 1024);
46+
} else if (e->m > v) {
47+
e->m = e->m >= e->step
48+
? e->m - e->step
49+
: 0;
50+
} else if (e->m < v) {
51+
e->m = e->m + e->step > e->m
52+
? e->m + e->step
53+
: U32_MAX;
54+
}
55+
56+
if ((e->m > v ? e->m - v : v - e->m) < e->step)
57+
e->step = max_t(unsigned, e->step / 2, 1);
58+
59+
if (v >= e->m)
60+
break;
61+
62+
i = eytzinger0_child(i, v > e->m);
63+
}
64+
}
65+
66+
static inline void time_stats_update_one(struct bch2_time_stats *stats,
67+
u64 start, u64 end)
68+
{
69+
u64 duration, freq;
70+
71+
if (time_after64(end, start)) {
72+
duration = end - start;
73+
mean_and_variance_update(&stats->duration_stats, duration);
74+
mean_and_variance_weighted_update(&stats->duration_stats_weighted, duration);
75+
stats->max_duration = max(stats->max_duration, duration);
76+
stats->min_duration = min(stats->min_duration, duration);
77+
stats->total_duration += duration;
78+
79+
if (stats->quantiles_enabled)
80+
quantiles_update(&stats->quantiles, duration);
81+
}
82+
83+
if (stats->last_event && time_after64(end, stats->last_event)) {
84+
freq = end - stats->last_event;
85+
mean_and_variance_update(&stats->freq_stats, freq);
86+
mean_and_variance_weighted_update(&stats->freq_stats_weighted, freq);
87+
stats->max_freq = max(stats->max_freq, freq);
88+
stats->min_freq = min(stats->min_freq, freq);
89+
}
90+
91+
stats->last_event = end;
92+
}
93+
94+
void __bch2_time_stats_clear_buffer(struct bch2_time_stats *stats,
95+
struct time_stat_buffer *b)
96+
{
97+
for (struct time_stat_buffer_entry *i = b->entries;
98+
i < b->entries + ARRAY_SIZE(b->entries);
99+
i++)
100+
time_stats_update_one(stats, i->start, i->end);
101+
b->nr = 0;
102+
}
103+
104+
static noinline void time_stats_clear_buffer(struct bch2_time_stats *stats,
105+
struct time_stat_buffer *b)
106+
{
107+
unsigned long flags;
108+
109+
spin_lock_irqsave(&stats->lock, flags);
110+
__bch2_time_stats_clear_buffer(stats, b);
111+
spin_unlock_irqrestore(&stats->lock, flags);
112+
}
113+
114+
void __bch2_time_stats_update(struct bch2_time_stats *stats, u64 start, u64 end)
115+
{
116+
unsigned long flags;
117+
118+
WARN_ONCE(!stats->duration_stats_weighted.weight ||
119+
!stats->freq_stats_weighted.weight,
120+
"uninitialized bch2_time_stats");
121+
122+
if (!stats->buffer) {
123+
spin_lock_irqsave(&stats->lock, flags);
124+
time_stats_update_one(stats, start, end);
125+
126+
if (mean_and_variance_weighted_get_mean(stats->freq_stats_weighted) < 32 &&
127+
stats->duration_stats.n > 1024)
128+
stats->buffer =
129+
alloc_percpu_gfp(struct time_stat_buffer,
130+
GFP_ATOMIC);
131+
spin_unlock_irqrestore(&stats->lock, flags);
132+
} else {
133+
struct time_stat_buffer *b;
134+
135+
preempt_disable();
136+
b = this_cpu_ptr(stats->buffer);
137+
138+
BUG_ON(b->nr >= ARRAY_SIZE(b->entries));
139+
b->entries[b->nr++] = (struct time_stat_buffer_entry) {
140+
.start = start,
141+
.end = end
142+
};
143+
144+
if (unlikely(b->nr == ARRAY_SIZE(b->entries)))
145+
time_stats_clear_buffer(stats, b);
146+
preempt_enable();
147+
}
148+
}
149+
150+
void bch2_time_stats_exit(struct bch2_time_stats *stats)
151+
{
152+
free_percpu(stats->buffer);
153+
}
154+
155+
void bch2_time_stats_init(struct bch2_time_stats *stats)
156+
{
157+
memset(stats, 0, sizeof(*stats));
158+
stats->duration_stats_weighted.weight = 8;
159+
stats->freq_stats_weighted.weight = 8;
160+
stats->min_duration = U64_MAX;
161+
stats->min_freq = U64_MAX;
162+
spin_lock_init(&stats->lock);
163+
}

0 commit comments

Comments
 (0)