Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 1 | #ifndef BLK_STAT_H |
| 2 | #define BLK_STAT_H |
| 3 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 4 | #include <linux/kernel.h> |
| 5 | #include <linux/blkdev.h> |
| 6 | #include <linux/ktime.h> |
| 7 | #include <linux/rcupdate.h> |
| 8 | #include <linux/timer.h> |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 9 | |
| 10 | /* |
Shaohua Li | 88eeca4 | 2017-03-27 15:19:41 -0700 | [diff] [blame^] | 11 | * from upper: |
| 12 | * 3 bits: reserved for other usage |
| 13 | * 12 bits: size |
| 14 | * 49 bits: time |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 15 | */ |
| 16 | #define BLK_STAT_RES_BITS 3 |
Shaohua Li | 88eeca4 | 2017-03-27 15:19:41 -0700 | [diff] [blame^] | 17 | #define BLK_STAT_SIZE_BITS 12 |
| 18 | #define BLK_STAT_RES_SHIFT (64 - BLK_STAT_RES_BITS) |
| 19 | #define BLK_STAT_SIZE_SHIFT (BLK_STAT_RES_SHIFT - BLK_STAT_SIZE_BITS) |
| 20 | #define BLK_STAT_TIME_MASK ((1ULL << BLK_STAT_SIZE_SHIFT) - 1) |
| 21 | #define BLK_STAT_SIZE_MASK \ |
| 22 | (((1ULL << BLK_STAT_SIZE_BITS) - 1) << BLK_STAT_SIZE_SHIFT) |
| 23 | #define BLK_STAT_RES_MASK (~((1ULL << BLK_STAT_RES_SHIFT) - 1)) |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 24 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 25 | /** |
| 26 | * struct blk_stat_callback - Block statistics callback. |
| 27 | * |
| 28 | * A &struct blk_stat_callback is associated with a &struct request_queue. While |
| 29 | * @timer is active, that queue's request completion latencies are sorted into |
| 30 | * buckets by @bucket_fn and added to a per-cpu buffer, @cpu_stat. When the |
| 31 | * timer fires, @cpu_stat is flushed to @stat and @timer_fn is invoked. |
| 32 | */ |
| 33 | struct blk_stat_callback { |
| 34 | /* |
| 35 | * @list: RCU list of callbacks for a &struct request_queue. |
| 36 | */ |
| 37 | struct list_head list; |
| 38 | |
| 39 | /** |
| 40 | * @timer: Timer for the next callback invocation. |
| 41 | */ |
| 42 | struct timer_list timer; |
| 43 | |
| 44 | /** |
| 45 | * @cpu_stat: Per-cpu statistics buckets. |
| 46 | */ |
| 47 | struct blk_rq_stat __percpu *cpu_stat; |
| 48 | |
| 49 | /** |
| 50 | * @bucket_fn: Given a request, returns which statistics bucket it |
| 51 | * should be accounted under. |
| 52 | */ |
| 53 | unsigned int (*bucket_fn)(const struct request *); |
| 54 | |
| 55 | /** |
| 56 | * @buckets: Number of statistics buckets. |
| 57 | */ |
| 58 | unsigned int buckets; |
| 59 | |
| 60 | /** |
| 61 | * @stat: Array of statistics buckets. |
| 62 | */ |
| 63 | struct blk_rq_stat *stat; |
| 64 | |
| 65 | /** |
| 66 | * @fn: Callback function. |
| 67 | */ |
| 68 | void (*timer_fn)(struct blk_stat_callback *); |
| 69 | |
| 70 | /** |
| 71 | * @data: Private pointer for the user. |
| 72 | */ |
| 73 | void *data; |
| 74 | |
| 75 | struct rcu_head rcu; |
| 76 | }; |
| 77 | |
| 78 | struct blk_queue_stats *blk_alloc_queue_stats(void); |
| 79 | void blk_free_queue_stats(struct blk_queue_stats *); |
| 80 | |
| 81 | void blk_stat_add(struct request *); |
| 82 | |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 83 | static inline u64 __blk_stat_time(u64 time) |
| 84 | { |
| 85 | return time & BLK_STAT_TIME_MASK; |
| 86 | } |
| 87 | |
| 88 | static inline u64 blk_stat_time(struct blk_issue_stat *stat) |
| 89 | { |
Shaohua Li | 88eeca4 | 2017-03-27 15:19:41 -0700 | [diff] [blame^] | 90 | return __blk_stat_time(stat->stat); |
| 91 | } |
| 92 | |
| 93 | static inline sector_t blk_capped_size(sector_t size) |
| 94 | { |
| 95 | return size & ((1ULL << BLK_STAT_SIZE_BITS) - 1); |
| 96 | } |
| 97 | |
| 98 | static inline sector_t blk_stat_size(struct blk_issue_stat *stat) |
| 99 | { |
| 100 | return (stat->stat & BLK_STAT_SIZE_MASK) >> BLK_STAT_SIZE_SHIFT; |
| 101 | } |
| 102 | |
| 103 | static inline void blk_stat_set_issue(struct blk_issue_stat *stat, |
| 104 | sector_t size) |
| 105 | { |
| 106 | stat->stat = (stat->stat & BLK_STAT_RES_MASK) | |
| 107 | (ktime_to_ns(ktime_get()) & BLK_STAT_TIME_MASK) | |
| 108 | (((u64)blk_capped_size(size)) << BLK_STAT_SIZE_SHIFT); |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 109 | } |
| 110 | |
Omar Sandoval | 34dbad5 | 2017-03-21 08:56:08 -0700 | [diff] [blame] | 111 | /* |
| 112 | * blk_stat_rq_ddir() - Bucket callback function for the request data direction. |
| 113 | * @rq: Request. |
| 114 | * |
| 115 | * This is the same as rq_data_dir() but as a function so it can be used as |
| 116 | * @bucket_fn for blk_stat_alloc_callback(). |
| 117 | * |
| 118 | * Return: Data direction of the request, either READ or WRITE. |
| 119 | */ |
| 120 | unsigned int blk_stat_rq_ddir(const struct request *rq); |
| 121 | |
| 122 | /** |
| 123 | * blk_stat_alloc_callback() - Allocate a block statistics callback. |
| 124 | * @timer_fn: Timer callback function. |
| 125 | * @bucket_fn: Bucket callback function. |
| 126 | * @buckets: Number of statistics buckets. |
| 127 | * @data: Value for the @data field of the &struct blk_stat_callback. |
| 128 | * |
| 129 | * See &struct blk_stat_callback for details on the callback functions. |
| 130 | * |
| 131 | * Return: &struct blk_stat_callback on success or NULL on ENOMEM. |
| 132 | */ |
| 133 | struct blk_stat_callback * |
| 134 | blk_stat_alloc_callback(void (*timer_fn)(struct blk_stat_callback *), |
| 135 | unsigned int (*bucket_fn)(const struct request *), |
| 136 | unsigned int buckets, void *data); |
| 137 | |
| 138 | /** |
| 139 | * blk_stat_add_callback() - Add a block statistics callback to be run on a |
| 140 | * request queue. |
| 141 | * @q: The request queue. |
| 142 | * @cb: The callback. |
| 143 | * |
| 144 | * Note that a single &struct blk_stat_callback can only be added to a single |
| 145 | * &struct request_queue. |
| 146 | */ |
| 147 | void blk_stat_add_callback(struct request_queue *q, |
| 148 | struct blk_stat_callback *cb); |
| 149 | |
| 150 | /** |
| 151 | * blk_stat_remove_callback() - Remove a block statistics callback from a |
| 152 | * request queue. |
| 153 | * @q: The request queue. |
| 154 | * @cb: The callback. |
| 155 | * |
| 156 | * When this returns, the callback is not running on any CPUs and will not be |
| 157 | * called again unless readded. |
| 158 | */ |
| 159 | void blk_stat_remove_callback(struct request_queue *q, |
| 160 | struct blk_stat_callback *cb); |
| 161 | |
| 162 | /** |
| 163 | * blk_stat_free_callback() - Free a block statistics callback. |
| 164 | * @cb: The callback. |
| 165 | * |
| 166 | * @cb may be NULL, in which case this does nothing. If it is not NULL, @cb must |
| 167 | * not be associated with a request queue. I.e., if it was previously added with |
| 168 | * blk_stat_add_callback(), it must also have been removed since then with |
| 169 | * blk_stat_remove_callback(). |
| 170 | */ |
| 171 | void blk_stat_free_callback(struct blk_stat_callback *cb); |
| 172 | |
| 173 | /** |
| 174 | * blk_stat_is_active() - Check if a block statistics callback is currently |
| 175 | * gathering statistics. |
| 176 | * @cb: The callback. |
| 177 | */ |
| 178 | static inline bool blk_stat_is_active(struct blk_stat_callback *cb) |
| 179 | { |
| 180 | return timer_pending(&cb->timer); |
| 181 | } |
| 182 | |
| 183 | /** |
| 184 | * blk_stat_activate_nsecs() - Gather block statistics during a time window in |
| 185 | * nanoseconds. |
| 186 | * @cb: The callback. |
| 187 | * @nsecs: Number of nanoseconds to gather statistics for. |
| 188 | * |
| 189 | * The timer callback will be called when the window expires. |
| 190 | */ |
| 191 | static inline void blk_stat_activate_nsecs(struct blk_stat_callback *cb, |
| 192 | u64 nsecs) |
| 193 | { |
| 194 | mod_timer(&cb->timer, jiffies + nsecs_to_jiffies(nsecs)); |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * blk_stat_activate_msecs() - Gather block statistics during a time window in |
| 199 | * milliseconds. |
| 200 | * @cb: The callback. |
| 201 | * @msecs: Number of milliseconds to gather statistics for. |
| 202 | * |
| 203 | * The timer callback will be called when the window expires. |
| 204 | */ |
| 205 | static inline void blk_stat_activate_msecs(struct blk_stat_callback *cb, |
| 206 | unsigned int msecs) |
| 207 | { |
| 208 | mod_timer(&cb->timer, jiffies + msecs_to_jiffies(msecs)); |
| 209 | } |
| 210 | |
Jens Axboe | cf43e6b | 2016-11-07 21:32:37 -0700 | [diff] [blame] | 211 | #endif |