2 * Block stat tracking code
4 * Copyright (C) 2016 Jens Axboe
6 #include <linux/kernel.h>
7 #include <linux/rculist.h>
8 #include <linux/blk-mq.h>
14 #define BLK_RQ_STAT_BATCH 64
16 struct blk_queue_stats
{
17 struct list_head callbacks
;
19 bool enable_accounting
;
22 int blk_stat_rq_ddir(const struct request
*rq
)
24 return rq_data_dir(rq
);
26 EXPORT_SYMBOL_GPL(blk_stat_rq_ddir
);
28 static void blk_stat_init(struct blk_rq_stat
*stat
)
31 stat
->max
= stat
->nr_samples
= stat
->mean
= 0;
32 stat
->batch
= stat
->nr_batch
= 0;
35 static void blk_stat_flush_batch(struct blk_rq_stat
*stat
)
37 const s32 nr_batch
= READ_ONCE(stat
->nr_batch
);
38 const s32 nr_samples
= READ_ONCE(stat
->nr_samples
);
43 stat
->mean
= div64_s64(stat
->batch
, nr_batch
);
45 stat
->mean
= div64_s64((stat
->mean
* nr_samples
) +
47 nr_batch
+ nr_samples
);
50 stat
->nr_samples
+= nr_batch
;
51 stat
->nr_batch
= stat
->batch
= 0;
54 static void blk_stat_sum(struct blk_rq_stat
*dst
, struct blk_rq_stat
*src
)
56 blk_stat_flush_batch(src
);
61 dst
->min
= min(dst
->min
, src
->min
);
62 dst
->max
= max(dst
->max
, src
->max
);
65 dst
->mean
= src
->mean
;
67 dst
->mean
= div64_s64((src
->mean
* src
->nr_samples
) +
68 (dst
->mean
* dst
->nr_samples
),
69 dst
->nr_samples
+ src
->nr_samples
);
71 dst
->nr_samples
+= src
->nr_samples
;
74 static void __blk_stat_add(struct blk_rq_stat
*stat
, u64 value
)
76 stat
->min
= min(stat
->min
, value
);
77 stat
->max
= max(stat
->max
, value
);
79 if (stat
->batch
+ value
< stat
->batch
||
80 stat
->nr_batch
+ 1 == BLK_RQ_STAT_BATCH
)
81 blk_stat_flush_batch(stat
);
87 void blk_stat_add(struct request
*rq
)
89 struct request_queue
*q
= rq
->q
;
90 struct blk_stat_callback
*cb
;
91 struct blk_rq_stat
*stat
;
95 now
= __blk_stat_time(ktime_to_ns(ktime_get()));
96 if (now
< blk_stat_time(&rq
->issue_stat
))
99 value
= now
- blk_stat_time(&rq
->issue_stat
);
101 blk_throtl_stat_add(rq
, value
);
104 list_for_each_entry_rcu(cb
, &q
->stats
->callbacks
, list
) {
105 if (blk_stat_is_active(cb
)) {
106 bucket
= cb
->bucket_fn(rq
);
109 stat
= &this_cpu_ptr(cb
->cpu_stat
)[bucket
];
110 __blk_stat_add(stat
, value
);
116 static void blk_stat_timer_fn(unsigned long data
)
118 struct blk_stat_callback
*cb
= (void *)data
;
122 for (bucket
= 0; bucket
< cb
->buckets
; bucket
++)
123 blk_stat_init(&cb
->stat
[bucket
]);
125 for_each_online_cpu(cpu
) {
126 struct blk_rq_stat
*cpu_stat
;
128 cpu_stat
= per_cpu_ptr(cb
->cpu_stat
, cpu
);
129 for (bucket
= 0; bucket
< cb
->buckets
; bucket
++) {
130 blk_stat_sum(&cb
->stat
[bucket
], &cpu_stat
[bucket
]);
131 blk_stat_init(&cpu_stat
[bucket
]);
138 struct blk_stat_callback
*
139 blk_stat_alloc_callback(void (*timer_fn
)(struct blk_stat_callback
*),
140 int (*bucket_fn
)(const struct request
*),
141 unsigned int buckets
, void *data
)
143 struct blk_stat_callback
*cb
;
145 cb
= kmalloc(sizeof(*cb
), GFP_KERNEL
);
149 cb
->stat
= kmalloc_array(buckets
, sizeof(struct blk_rq_stat
),
155 cb
->cpu_stat
= __alloc_percpu(buckets
* sizeof(struct blk_rq_stat
),
156 __alignof__(struct blk_rq_stat
));
163 cb
->timer_fn
= timer_fn
;
164 cb
->bucket_fn
= bucket_fn
;
166 cb
->buckets
= buckets
;
167 setup_timer(&cb
->timer
, blk_stat_timer_fn
, (unsigned long)cb
);
171 EXPORT_SYMBOL_GPL(blk_stat_alloc_callback
);
173 void blk_stat_add_callback(struct request_queue
*q
,
174 struct blk_stat_callback
*cb
)
179 for_each_possible_cpu(cpu
) {
180 struct blk_rq_stat
*cpu_stat
;
182 cpu_stat
= per_cpu_ptr(cb
->cpu_stat
, cpu
);
183 for (bucket
= 0; bucket
< cb
->buckets
; bucket
++)
184 blk_stat_init(&cpu_stat
[bucket
]);
187 spin_lock(&q
->stats
->lock
);
188 list_add_tail_rcu(&cb
->list
, &q
->stats
->callbacks
);
189 set_bit(QUEUE_FLAG_STATS
, &q
->queue_flags
);
190 spin_unlock(&q
->stats
->lock
);
192 EXPORT_SYMBOL_GPL(blk_stat_add_callback
);
194 void blk_stat_remove_callback(struct request_queue
*q
,
195 struct blk_stat_callback
*cb
)
197 spin_lock(&q
->stats
->lock
);
198 list_del_rcu(&cb
->list
);
199 if (list_empty(&q
->stats
->callbacks
) && !q
->stats
->enable_accounting
)
200 clear_bit(QUEUE_FLAG_STATS
, &q
->queue_flags
);
201 spin_unlock(&q
->stats
->lock
);
203 del_timer_sync(&cb
->timer
);
205 EXPORT_SYMBOL_GPL(blk_stat_remove_callback
);
207 static void blk_stat_free_callback_rcu(struct rcu_head
*head
)
209 struct blk_stat_callback
*cb
;
211 cb
= container_of(head
, struct blk_stat_callback
, rcu
);
212 free_percpu(cb
->cpu_stat
);
217 void blk_stat_free_callback(struct blk_stat_callback
*cb
)
220 call_rcu(&cb
->rcu
, blk_stat_free_callback_rcu
);
222 EXPORT_SYMBOL_GPL(blk_stat_free_callback
);
224 void blk_stat_enable_accounting(struct request_queue
*q
)
226 spin_lock(&q
->stats
->lock
);
227 q
->stats
->enable_accounting
= true;
228 set_bit(QUEUE_FLAG_STATS
, &q
->queue_flags
);
229 spin_unlock(&q
->stats
->lock
);
232 struct blk_queue_stats
*blk_alloc_queue_stats(void)
234 struct blk_queue_stats
*stats
;
236 stats
= kmalloc(sizeof(*stats
), GFP_KERNEL
);
240 INIT_LIST_HEAD(&stats
->callbacks
);
241 spin_lock_init(&stats
->lock
);
242 stats
->enable_accounting
= false;
247 void blk_free_queue_stats(struct blk_queue_stats
*stats
)
252 WARN_ON(!list_empty(&stats
->callbacks
));