aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorDivyesh Shah <dpshah@google.com>2010-04-09 00:15:10 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-04-09 02:36:08 -0400
commitcdc1184cf4a7bd99f5473a91244197accc49146b (patch)
treeecd572867bfa5a82fa4ed16d7303448c7ea7d24c /block
parent812d402648f4fc1ab1091b2172a46fc1b367c724 (diff)
blkio: Add io_queued and avg_queue_size stats
These stats are useful for getting a feel for the queue depth of the cgroup, i.e., how filled up its queues are at a given instant and over the existence of the cgroup. This ability is useful when debugging problems in the wild as it helps understand the application's IO pattern w/o having to read through the userspace code (coz its tedious or just not available) or w/o the ability to run blktrace (since you may not have root access and/or not want to disturb performance). Signed-off-by: Divyesh Shah<dpshah@google.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-cgroup.c98
-rw-r--r--block/blk-cgroup.h20
-rw-r--r--block/cfq-iosched.c11
3 files changed, 123 insertions, 6 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index d23b538858ce..1e0c4970b35d 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -81,6 +81,71 @@ static void blkio_add_stat(uint64_t *stat, uint64_t add, bool direction,
81 stat[BLKIO_STAT_ASYNC] += add; 81 stat[BLKIO_STAT_ASYNC] += add;
82} 82}
83 83
84/*
85 * Decrements the appropriate stat variable if non-zero depending on the
86 * request type. Panics on value being zero.
87 * This should be called with the blkg->stats_lock held.
88 */
89static void blkio_check_and_dec_stat(uint64_t *stat, bool direction, bool sync)
90{
91 if (direction) {
92 BUG_ON(stat[BLKIO_STAT_WRITE] == 0);
93 stat[BLKIO_STAT_WRITE]--;
94 } else {
95 BUG_ON(stat[BLKIO_STAT_READ] == 0);
96 stat[BLKIO_STAT_READ]--;
97 }
98 if (sync) {
99 BUG_ON(stat[BLKIO_STAT_SYNC] == 0);
100 stat[BLKIO_STAT_SYNC]--;
101 } else {
102 BUG_ON(stat[BLKIO_STAT_ASYNC] == 0);
103 stat[BLKIO_STAT_ASYNC]--;
104 }
105}
106
107#ifdef CONFIG_DEBUG_BLK_CGROUP
108void blkiocg_update_set_active_queue_stats(struct blkio_group *blkg)
109{
110 unsigned long flags;
111 struct blkio_group_stats *stats;
112
113 spin_lock_irqsave(&blkg->stats_lock, flags);
114 stats = &blkg->stats;
115 stats->avg_queue_size_sum +=
116 stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_READ] +
117 stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_WRITE];
118 stats->avg_queue_size_samples++;
119 spin_unlock_irqrestore(&blkg->stats_lock, flags);
120}
121EXPORT_SYMBOL_GPL(blkiocg_update_set_active_queue_stats);
122#endif
123
124void blkiocg_update_request_add_stats(struct blkio_group *blkg,
125 struct blkio_group *curr_blkg, bool direction,
126 bool sync)
127{
128 unsigned long flags;
129
130 spin_lock_irqsave(&blkg->stats_lock, flags);
131 blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_QUEUED], 1, direction,
132 sync);
133 spin_unlock_irqrestore(&blkg->stats_lock, flags);
134}
135EXPORT_SYMBOL_GPL(blkiocg_update_request_add_stats);
136
137void blkiocg_update_request_remove_stats(struct blkio_group *blkg,
138 bool direction, bool sync)
139{
140 unsigned long flags;
141
142 spin_lock_irqsave(&blkg->stats_lock, flags);
143 blkio_check_and_dec_stat(blkg->stats.stat_arr[BLKIO_STAT_QUEUED],
144 direction, sync);
145 spin_unlock_irqrestore(&blkg->stats_lock, flags);
146}
147EXPORT_SYMBOL_GPL(blkiocg_update_request_remove_stats);
148
84void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time) 149void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time)
85{ 150{
86 unsigned long flags; 151 unsigned long flags;
@@ -253,14 +318,18 @@ blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
253 struct blkio_cgroup *blkcg; 318 struct blkio_cgroup *blkcg;
254 struct blkio_group *blkg; 319 struct blkio_group *blkg;
255 struct hlist_node *n; 320 struct hlist_node *n;
256 struct blkio_group_stats *stats; 321 uint64_t queued[BLKIO_STAT_TOTAL];
322 int i;
257 323
258 blkcg = cgroup_to_blkio_cgroup(cgroup); 324 blkcg = cgroup_to_blkio_cgroup(cgroup);
259 spin_lock_irq(&blkcg->lock); 325 spin_lock_irq(&blkcg->lock);
260 hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { 326 hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
261 spin_lock(&blkg->stats_lock); 327 spin_lock(&blkg->stats_lock);
262 stats = &blkg->stats; 328 for (i = 0; i < BLKIO_STAT_TOTAL; i++)
263 memset(stats, 0, sizeof(struct blkio_group_stats)); 329 queued[i] = blkg->stats.stat_arr[BLKIO_STAT_QUEUED][i];
330 memset(&blkg->stats, 0, sizeof(struct blkio_group_stats));
331 for (i = 0; i < BLKIO_STAT_TOTAL; i++)
332 blkg->stats.stat_arr[BLKIO_STAT_QUEUED][i] = queued[i];
264 spin_unlock(&blkg->stats_lock); 333 spin_unlock(&blkg->stats_lock);
265 } 334 }
266 spin_unlock_irq(&blkcg->lock); 335 spin_unlock_irq(&blkcg->lock);
@@ -323,6 +392,15 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
323 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, 392 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
324 blkg->stats.sectors, cb, dev); 393 blkg->stats.sectors, cb, dev);
325#ifdef CONFIG_DEBUG_BLK_CGROUP 394#ifdef CONFIG_DEBUG_BLK_CGROUP
395 if (type == BLKIO_STAT_AVG_QUEUE_SIZE) {
396 uint64_t sum = blkg->stats.avg_queue_size_sum;
397 uint64_t samples = blkg->stats.avg_queue_size_samples;
398 if (samples)
399 do_div(sum, samples);
400 else
401 sum = 0;
402 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, sum, cb, dev);
403 }
326 if (type == BLKIO_STAT_DEQUEUE) 404 if (type == BLKIO_STAT_DEQUEUE)
327 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, 405 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
328 blkg->stats.dequeue, cb, dev); 406 blkg->stats.dequeue, cb, dev);
@@ -376,8 +454,10 @@ SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1);
376SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1); 454SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1);
377SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1); 455SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1);
378SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1); 456SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1);
457SHOW_FUNCTION_PER_GROUP(io_queued, BLKIO_STAT_QUEUED, 1);
379#ifdef CONFIG_DEBUG_BLK_CGROUP 458#ifdef CONFIG_DEBUG_BLK_CGROUP
380SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0); 459SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0);
460SHOW_FUNCTION_PER_GROUP(avg_queue_size, BLKIO_STAT_AVG_QUEUE_SIZE, 0);
381#endif 461#endif
382#undef SHOW_FUNCTION_PER_GROUP 462#undef SHOW_FUNCTION_PER_GROUP
383 463
@@ -425,14 +505,22 @@ struct cftype blkio_files[] = {
425 .read_map = blkiocg_io_merged_read, 505 .read_map = blkiocg_io_merged_read,
426 }, 506 },
427 { 507 {
508 .name = "io_queued",
509 .read_map = blkiocg_io_queued_read,
510 },
511 {
428 .name = "reset_stats", 512 .name = "reset_stats",
429 .write_u64 = blkiocg_reset_stats, 513 .write_u64 = blkiocg_reset_stats,
430 }, 514 },
431#ifdef CONFIG_DEBUG_BLK_CGROUP 515#ifdef CONFIG_DEBUG_BLK_CGROUP
432 { 516 {
517 .name = "avg_queue_size",
518 .read_map = blkiocg_avg_queue_size_read,
519 },
520 {
433 .name = "dequeue", 521 .name = "dequeue",
434 .read_map = blkiocg_dequeue_read, 522 .read_map = blkiocg_dequeue_read,
435 }, 523 },
436#endif 524#endif
437}; 525};
438 526
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 470a29db6bec..bea7f3b9a88e 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -36,10 +36,13 @@ enum stat_type {
36 BLKIO_STAT_WAIT_TIME, 36 BLKIO_STAT_WAIT_TIME,
37 /* Number of IOs merged */ 37 /* Number of IOs merged */
38 BLKIO_STAT_MERGED, 38 BLKIO_STAT_MERGED,
39 /* Number of IOs queued up */
40 BLKIO_STAT_QUEUED,
39 /* All the single valued stats go below this */ 41 /* All the single valued stats go below this */
40 BLKIO_STAT_TIME, 42 BLKIO_STAT_TIME,
41 BLKIO_STAT_SECTORS, 43 BLKIO_STAT_SECTORS,
42#ifdef CONFIG_DEBUG_BLK_CGROUP 44#ifdef CONFIG_DEBUG_BLK_CGROUP
45 BLKIO_STAT_AVG_QUEUE_SIZE,
43 BLKIO_STAT_DEQUEUE 46 BLKIO_STAT_DEQUEUE
44#endif 47#endif
45}; 48};
@@ -63,8 +66,12 @@ struct blkio_group_stats {
63 /* total disk time and nr sectors dispatched by this group */ 66 /* total disk time and nr sectors dispatched by this group */
64 uint64_t time; 67 uint64_t time;
65 uint64_t sectors; 68 uint64_t sectors;
66 uint64_t stat_arr[BLKIO_STAT_MERGED + 1][BLKIO_STAT_TOTAL]; 69 uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL];
67#ifdef CONFIG_DEBUG_BLK_CGROUP 70#ifdef CONFIG_DEBUG_BLK_CGROUP
71 /* Sum of number of IOs queued across all samples */
72 uint64_t avg_queue_size_sum;
73 /* Count of samples taken for average */
74 uint64_t avg_queue_size_samples;
68 /* How many times this group has been removed from service tree */ 75 /* How many times this group has been removed from service tree */
69 unsigned long dequeue; 76 unsigned long dequeue;
70#endif 77#endif
@@ -127,10 +134,13 @@ static inline char *blkg_path(struct blkio_group *blkg)
127{ 134{
128 return blkg->path; 135 return blkg->path;
129} 136}
137void blkiocg_update_set_active_queue_stats(struct blkio_group *blkg);
130void blkiocg_update_dequeue_stats(struct blkio_group *blkg, 138void blkiocg_update_dequeue_stats(struct blkio_group *blkg,
131 unsigned long dequeue); 139 unsigned long dequeue);
132#else 140#else
133static inline char *blkg_path(struct blkio_group *blkg) { return NULL; } 141static inline char *blkg_path(struct blkio_group *blkg) { return NULL; }
142static inline void blkiocg_update_set_active_queue_stats(
143 struct blkio_group *blkg) {}
134static inline void blkiocg_update_dequeue_stats(struct blkio_group *blkg, 144static inline void blkiocg_update_dequeue_stats(struct blkio_group *blkg,
135 unsigned long dequeue) {} 145 unsigned long dequeue) {}
136#endif 146#endif
@@ -152,6 +162,10 @@ void blkiocg_update_completion_stats(struct blkio_group *blkg,
152 uint64_t start_time, uint64_t io_start_time, bool direction, bool sync); 162 uint64_t start_time, uint64_t io_start_time, bool direction, bool sync);
153void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction, 163void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
154 bool sync); 164 bool sync);
165void blkiocg_update_request_add_stats(struct blkio_group *blkg,
166 struct blkio_group *curr_blkg, bool direction, bool sync);
167void blkiocg_update_request_remove_stats(struct blkio_group *blkg,
168 bool direction, bool sync);
155#else 169#else
156struct cgroup; 170struct cgroup;
157static inline struct blkio_cgroup * 171static inline struct blkio_cgroup *
@@ -175,5 +189,9 @@ static inline void blkiocg_update_completion_stats(struct blkio_group *blkg,
175 bool sync) {} 189 bool sync) {}
176static inline void blkiocg_update_io_merged_stats(struct blkio_group *blkg, 190static inline void blkiocg_update_io_merged_stats(struct blkio_group *blkg,
177 bool direction, bool sync) {} 191 bool direction, bool sync) {}
192static inline void blkiocg_update_request_add_stats(struct blkio_group *blkg,
193 struct blkio_group *curr_blkg, bool direction, bool sync) {}
194static inline void blkiocg_update_request_remove_stats(struct blkio_group *blkg,
195 bool direction, bool sync) {}
178#endif 196#endif
179#endif /* _BLK_CGROUP_H */ 197#endif /* _BLK_CGROUP_H */
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 4eb1906cf6c6..8e0b86a9111a 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1380,7 +1380,12 @@ static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
1380{ 1380{
1381 elv_rb_del(&cfqq->sort_list, rq); 1381 elv_rb_del(&cfqq->sort_list, rq);
1382 cfqq->queued[rq_is_sync(rq)]--; 1382 cfqq->queued[rq_is_sync(rq)]--;
1383 blkiocg_update_request_remove_stats(&cfqq->cfqg->blkg, rq_data_dir(rq),
1384 rq_is_sync(rq));
1383 cfq_add_rq_rb(rq); 1385 cfq_add_rq_rb(rq);
1386 blkiocg_update_request_add_stats(
1387 &cfqq->cfqg->blkg, &cfqq->cfqd->serving_group->blkg,
1388 rq_data_dir(rq), rq_is_sync(rq));
1384} 1389}
1385 1390
1386static struct request * 1391static struct request *
@@ -1436,6 +1441,8 @@ static void cfq_remove_request(struct request *rq)
1436 cfq_del_rq_rb(rq); 1441 cfq_del_rq_rb(rq);
1437 1442
1438 cfqq->cfqd->rq_queued--; 1443 cfqq->cfqd->rq_queued--;
1444 blkiocg_update_request_remove_stats(&cfqq->cfqg->blkg, rq_data_dir(rq),
1445 rq_is_sync(rq));
1439 if (rq_is_meta(rq)) { 1446 if (rq_is_meta(rq)) {
1440 WARN_ON(!cfqq->meta_pending); 1447 WARN_ON(!cfqq->meta_pending);
1441 cfqq->meta_pending--; 1448 cfqq->meta_pending--;
@@ -1527,6 +1534,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
1527 if (cfqq) { 1534 if (cfqq) {
1528 cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d", 1535 cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d",
1529 cfqd->serving_prio, cfqd->serving_type); 1536 cfqd->serving_prio, cfqd->serving_type);
1537 blkiocg_update_set_active_queue_stats(&cfqq->cfqg->blkg);
1530 cfqq->slice_start = 0; 1538 cfqq->slice_start = 0;
1531 cfqq->dispatch_start = jiffies; 1539 cfqq->dispatch_start = jiffies;
1532 cfqq->allocated_slice = 0; 1540 cfqq->allocated_slice = 0;
@@ -3213,6 +3221,9 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
3213 list_add_tail(&rq->queuelist, &cfqq->fifo); 3221 list_add_tail(&rq->queuelist, &cfqq->fifo);
3214 cfq_add_rq_rb(rq); 3222 cfq_add_rq_rb(rq);
3215 3223
3224 blkiocg_update_request_add_stats(&cfqq->cfqg->blkg,
3225 &cfqd->serving_group->blkg, rq_data_dir(rq),
3226 rq_is_sync(rq));
3216 cfq_rq_enqueued(cfqd, cfqq, rq); 3227 cfq_rq_enqueued(cfqd, cfqq, rq);
3217} 3228}
3218 3229