blk-stat.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Block stat tracking code
  3. *
  4. * Copyright (C) 2016 Jens Axboe
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/rculist.h>
  8. #include <linux/blk-mq.h>
  9. #include "blk-stat.h"
  10. #include "blk-mq.h"
  11. #include "blk.h"
  12. #define BLK_RQ_STAT_BATCH 64
  13. struct blk_queue_stats {
  14. struct list_head callbacks;
  15. spinlock_t lock;
  16. bool enable_accounting;
  17. };
  18. static void blk_stat_init(struct blk_rq_stat *stat)
  19. {
  20. stat->min = -1ULL;
  21. stat->max = stat->nr_samples = stat->mean = 0;
  22. stat->batch = stat->nr_batch = 0;
  23. }
  24. static void blk_stat_flush_batch(struct blk_rq_stat *stat)
  25. {
  26. const s32 nr_batch = READ_ONCE(stat->nr_batch);
  27. const s32 nr_samples = READ_ONCE(stat->nr_samples);
  28. if (!nr_batch)
  29. return;
  30. if (!nr_samples)
  31. stat->mean = div64_s64(stat->batch, nr_batch);
  32. else {
  33. stat->mean = div64_s64((stat->mean * nr_samples) +
  34. stat->batch,
  35. nr_batch + nr_samples);
  36. }
  37. stat->nr_samples += nr_batch;
  38. stat->nr_batch = stat->batch = 0;
  39. }
  40. static void blk_stat_sum(struct blk_rq_stat *dst, struct blk_rq_stat *src)
  41. {
  42. blk_stat_flush_batch(src);
  43. if (!src->nr_samples)
  44. return;
  45. dst->min = min(dst->min, src->min);
  46. dst->max = max(dst->max, src->max);
  47. if (!dst->nr_samples)
  48. dst->mean = src->mean;
  49. else {
  50. dst->mean = div64_s64((src->mean * src->nr_samples) +
  51. (dst->mean * dst->nr_samples),
  52. dst->nr_samples + src->nr_samples);
  53. }
  54. dst->nr_samples += src->nr_samples;
  55. }
  56. static void __blk_stat_add(struct blk_rq_stat *stat, u64 value)
  57. {
  58. stat->min = min(stat->min, value);
  59. stat->max = max(stat->max, value);
  60. if (stat->batch + value < stat->batch ||
  61. stat->nr_batch + 1 == BLK_RQ_STAT_BATCH)
  62. blk_stat_flush_batch(stat);
  63. stat->batch += value;
  64. stat->nr_batch++;
  65. }
  66. void blk_stat_add(struct request *rq)
  67. {
  68. struct request_queue *q = rq->q;
  69. struct blk_stat_callback *cb;
  70. struct blk_rq_stat *stat;
  71. int bucket;
  72. s64 now, value;
  73. now = __blk_stat_time(ktime_to_ns(ktime_get()));
  74. if (now < blk_stat_time(&rq->issue_stat))
  75. return;
  76. value = now - blk_stat_time(&rq->issue_stat);
  77. blk_throtl_stat_add(rq, value);
  78. rcu_read_lock();
  79. list_for_each_entry_rcu(cb, &q->stats->callbacks, list) {
  80. if (!blk_stat_is_active(cb))
  81. continue;
  82. bucket = cb->bucket_fn(rq);
  83. if (bucket < 0)
  84. continue;
  85. stat = &get_cpu_ptr(cb->cpu_stat)[bucket];
  86. __blk_stat_add(stat, value);
  87. put_cpu_ptr(cb->cpu_stat);
  88. }
  89. rcu_read_unlock();
  90. }
  91. static void blk_stat_timer_fn(unsigned long data)
  92. {
  93. struct blk_stat_callback *cb = (void *)data;
  94. unsigned int bucket;
  95. int cpu;
  96. for (bucket = 0; bucket < cb->buckets; bucket++)
  97. blk_stat_init(&cb->stat[bucket]);
  98. for_each_online_cpu(cpu) {
  99. struct blk_rq_stat *cpu_stat;
  100. cpu_stat = per_cpu_ptr(cb->cpu_stat, cpu);
  101. for (bucket = 0; bucket < cb->buckets; bucket++) {
  102. blk_stat_sum(&cb->stat[bucket], &cpu_stat[bucket]);
  103. blk_stat_init(&cpu_stat[bucket]);
  104. }
  105. }
  106. cb->timer_fn(cb);
  107. }
  108. struct blk_stat_callback *
  109. blk_stat_alloc_callback(void (*timer_fn)(struct blk_stat_callback *),
  110. int (*bucket_fn)(const struct request *),
  111. unsigned int buckets, void *data)
  112. {
  113. struct blk_stat_callback *cb;
  114. cb = kmalloc(sizeof(*cb), GFP_KERNEL);
  115. if (!cb)
  116. return NULL;
  117. cb->stat = kmalloc_array(buckets, sizeof(struct blk_rq_stat),
  118. GFP_KERNEL);
  119. if (!cb->stat) {
  120. kfree(cb);
  121. return NULL;
  122. }
  123. cb->cpu_stat = __alloc_percpu(buckets * sizeof(struct blk_rq_stat),
  124. __alignof__(struct blk_rq_stat));
  125. if (!cb->cpu_stat) {
  126. kfree(cb->stat);
  127. kfree(cb);
  128. return NULL;
  129. }
  130. cb->timer_fn = timer_fn;
  131. cb->bucket_fn = bucket_fn;
  132. cb->data = data;
  133. cb->buckets = buckets;
  134. setup_timer(&cb->timer, blk_stat_timer_fn, (unsigned long)cb);
  135. return cb;
  136. }
  137. EXPORT_SYMBOL_GPL(blk_stat_alloc_callback);
  138. void blk_stat_add_callback(struct request_queue *q,
  139. struct blk_stat_callback *cb)
  140. {
  141. unsigned int bucket;
  142. int cpu;
  143. for_each_possible_cpu(cpu) {
  144. struct blk_rq_stat *cpu_stat;
  145. cpu_stat = per_cpu_ptr(cb->cpu_stat, cpu);
  146. for (bucket = 0; bucket < cb->buckets; bucket++)
  147. blk_stat_init(&cpu_stat[bucket]);
  148. }
  149. spin_lock(&q->stats->lock);
  150. list_add_tail_rcu(&cb->list, &q->stats->callbacks);
  151. set_bit(QUEUE_FLAG_STATS, &q->queue_flags);
  152. spin_unlock(&q->stats->lock);
  153. }
  154. EXPORT_SYMBOL_GPL(blk_stat_add_callback);
  155. void blk_stat_remove_callback(struct request_queue *q,
  156. struct blk_stat_callback *cb)
  157. {
  158. spin_lock(&q->stats->lock);
  159. list_del_rcu(&cb->list);
  160. if (list_empty(&q->stats->callbacks) && !q->stats->enable_accounting)
  161. clear_bit(QUEUE_FLAG_STATS, &q->queue_flags);
  162. spin_unlock(&q->stats->lock);
  163. del_timer_sync(&cb->timer);
  164. }
  165. EXPORT_SYMBOL_GPL(blk_stat_remove_callback);
  166. static void blk_stat_free_callback_rcu(struct rcu_head *head)
  167. {
  168. struct blk_stat_callback *cb;
  169. cb = container_of(head, struct blk_stat_callback, rcu);
  170. free_percpu(cb->cpu_stat);
  171. kfree(cb->stat);
  172. kfree(cb);
  173. }
  174. void blk_stat_free_callback(struct blk_stat_callback *cb)
  175. {
  176. if (cb)
  177. call_rcu(&cb->rcu, blk_stat_free_callback_rcu);
  178. }
  179. EXPORT_SYMBOL_GPL(blk_stat_free_callback);
  180. void blk_stat_enable_accounting(struct request_queue *q)
  181. {
  182. spin_lock(&q->stats->lock);
  183. q->stats->enable_accounting = true;
  184. set_bit(QUEUE_FLAG_STATS, &q->queue_flags);
  185. spin_unlock(&q->stats->lock);
  186. }
  187. struct blk_queue_stats *blk_alloc_queue_stats(void)
  188. {
  189. struct blk_queue_stats *stats;
  190. stats = kmalloc(sizeof(*stats), GFP_KERNEL);
  191. if (!stats)
  192. return NULL;
  193. INIT_LIST_HEAD(&stats->callbacks);
  194. spin_lock_init(&stats->lock);
  195. stats->enable_accounting = false;
  196. return stats;
  197. }
  198. void blk_free_queue_stats(struct blk_queue_stats *stats)
  199. {
  200. if (!stats)
  201. return;
  202. WARN_ON(!list_empty(&stats->callbacks));
  203. kfree(stats);
  204. }