1 /* SPDX-License-Identifier: GPL-2.0 */
3 * bch2_time_stats - collect statistics on events that have a duration, with nicely
4 * formatted textual output on demand
6 * - percpu buffering of event collection: cheap enough to shotgun
7 * everywhere without worrying about overhead
11 * - maximum event duration ever seen
12 * - sum of all event durations
13 * - average event duration, standard and weighted
14 * - standard deviation of event durations, standard and weighted
15 * and analagous statistics for the frequency of events
17 * We provide both mean and weighted mean (exponentially weighted), and standard
18 * deviation and weighted standard deviation, to give an efficient-to-compute
19 * view of current behaviour versus. average behaviour - "did this event source
20 * just become wonky, or is this typical?".
22 * Particularly useful for tracking down latency issues.
24 #ifndef _BCACHEFS_TIME_STATS_H
25 #define _BCACHEFS_TIME_STATS_H
27 #include <linux/sched/clock.h>
28 #include <linux/spinlock_types.h>
29 #include <linux/string.h>
31 #include "mean_and_variance.h"
39 * given a nanosecond value, pick the preferred time units for printing:
41 const struct time_unit
*bch2_pick_time_units(u64 ns
);
44 * quantiles - do not use:
46 * Only enabled if bch2_time_stats->quantiles_enabled has been manually set - don't
50 #define NR_QUANTILES 15
51 #define QUANTILE_IDX(i) inorder_to_eytzinger0(i, NR_QUANTILES)
52 #define QUANTILE_FIRST eytzinger0_first(NR_QUANTILES)
53 #define QUANTILE_LAST eytzinger0_last(NR_QUANTILES)
56 struct quantile_entry
{
59 } entries
[NR_QUANTILES
];
62 struct time_stat_buffer
{
64 struct time_stat_buffer_entry
{
70 struct bch2_time_stats
{
73 struct time_stat_buffer __percpu
*buffer
;
74 /* all fields are in nanoseconds */
83 struct mean_and_variance duration_stats
;
84 struct mean_and_variance freq_stats
;
86 /* default weight for weighted mean and variance calculations */
87 #define TIME_STATS_MV_WEIGHT 8
89 struct mean_and_variance_weighted duration_stats_weighted
;
90 struct mean_and_variance_weighted freq_stats_weighted
;
93 struct bch2_time_stats_quantiles
{
94 struct bch2_time_stats stats
;
95 struct quantiles quantiles
;
98 static inline struct quantiles
*time_stats_to_quantiles(struct bch2_time_stats
*stats
)
100 return stats
->have_quantiles
101 ? &container_of(stats
, struct bch2_time_stats_quantiles
, stats
)->quantiles
105 void __bch2_time_stats_clear_buffer(struct bch2_time_stats
*, struct time_stat_buffer
*);
106 void __bch2_time_stats_update(struct bch2_time_stats
*stats
, u64
, u64
);
109 * time_stats_update - collect a new event being tracked
111 * @stats - bch2_time_stats to update
112 * @start - start time of event, recorded with local_clock()
114 * The end duration of the event will be the current time
116 static inline void bch2_time_stats_update(struct bch2_time_stats
*stats
, u64 start
)
118 __bch2_time_stats_update(stats
, start
, local_clock());
122 * track_event_change - track state change events
124 * @stats - bch2_time_stats to update
125 * @v - new state, true or false
127 * Use this when tracking time stats for state changes, i.e. resource X becoming
130 static inline bool track_event_change(struct bch2_time_stats
*stats
, bool v
)
132 if (v
!= !!stats
->last_event_start
) {
134 bch2_time_stats_update(stats
, stats
->last_event_start
);
135 stats
->last_event_start
= 0;
137 stats
->last_event_start
= local_clock() ?: 1;
145 void bch2_time_stats_reset(struct bch2_time_stats
*);
146 void bch2_time_stats_exit(struct bch2_time_stats
*);
147 void bch2_time_stats_init(struct bch2_time_stats
*);
149 static inline void bch2_time_stats_quantiles_exit(struct bch2_time_stats_quantiles
*statq
)
151 bch2_time_stats_exit(&statq
->stats
);
153 static inline void bch2_time_stats_quantiles_init(struct bch2_time_stats_quantiles
*statq
)
155 bch2_time_stats_init(&statq
->stats
);
156 statq
->stats
.have_quantiles
= true;
157 memset(&statq
->quantiles
, 0, sizeof(statq
->quantiles
));
160 #endif /* _BCACHEFS_TIME_STATS_H */