1 /* SPDX-License-Identifier: GPL-2.0 */
3 * 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 _LINUX_TIME_STATS_H
25 #define _LINUX_TIME_STATS_H
27 #include <linux/mean_and_variance.h>
28 #include <linux/sched/clock.h>
29 #include <linux/spinlock_types.h>
30 #include <linux/string.h>
38 * given a nanosecond value, pick the preferred time units for printing:
40 const struct time_unit *pick_time_units(u64 ns);
43 * quantiles - do not use:
45 * Only enabled if time_stats->quantiles_enabled has been manually set - don't
49 #define NR_QUANTILES 15
50 #define QUANTILE_IDX(i) inorder_to_eytzinger0(i, NR_QUANTILES)
51 #define QUANTILE_FIRST eytzinger0_first(NR_QUANTILES)
52 #define QUANTILE_LAST eytzinger0_last(NR_QUANTILES)
55 struct quantile_entry {
58 } entries[NR_QUANTILES];
61 struct time_stat_buffer {
63 struct time_stat_buffer_entry {
72 /* all fields are in nanoseconds */
81 struct mean_and_variance duration_stats;
82 struct mean_and_variance freq_stats;
84 /* default weight for weighted mean and variance calculations */
85 #define TIME_STATS_MV_WEIGHT 8
87 struct mean_and_variance_weighted duration_stats_weighted;
88 struct mean_and_variance_weighted freq_stats_weighted;
89 struct time_stat_buffer __percpu *buffer;
94 struct time_stats_quantiles {
95 struct time_stats stats;
96 struct quantiles quantiles;
99 static inline struct quantiles *time_stats_to_quantiles(struct time_stats *stats)
101 return stats->have_quantiles
102 ? &container_of(stats, struct time_stats_quantiles, stats)->quantiles
106 void __time_stats_clear_buffer(struct time_stats *, struct time_stat_buffer *);
107 void __time_stats_update(struct time_stats *stats, u64, u64);
110 * time_stats_update - collect a new event being tracked
112 * @stats - time_stats to update
113 * @start - start time of event, recorded with local_clock()
115 * The end duration of the event will be the current time
117 static inline void time_stats_update(struct time_stats *stats, u64 start)
119 __time_stats_update(stats, start, local_clock());
123 * track_event_change - track state change events
125 * @stats - time_stats to update
126 * @v - new state, true or false
128 * Use this when tracking time stats for state changes, i.e. resource X becoming
131 static inline bool track_event_change(struct time_stats *stats, bool v)
133 if (v != !!stats->last_event_start) {
135 time_stats_update(stats, stats->last_event_start);
136 stats->last_event_start = 0;
138 stats->last_event_start = local_clock() ?: 1;
146 #define TIME_STATS_PRINT_NO_ZEROES (1U << 0) /* print nothing if zero count */
148 void time_stats_to_seq_buf(struct seq_buf *, struct time_stats *,
149 const char *epoch_name, unsigned int flags);
150 void time_stats_to_json(struct seq_buf *, struct time_stats *,
151 const char *epoch_name, unsigned int flags);
153 void time_stats_exit(struct time_stats *);
154 void time_stats_init(struct time_stats *);
156 static inline void time_stats_quantiles_exit(struct time_stats_quantiles *statq)
158 time_stats_exit(&statq->stats);
160 static inline void time_stats_quantiles_init(struct time_stats_quantiles *statq)
162 time_stats_init(&statq->stats);
163 statq->stats.have_quantiles = true;
164 memset(&statq->quantiles, 0, sizeof(statq->quantiles));
167 #endif /* _LINUX_TIME_STATS_H */