aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDivyesh Shah <dpshah@google.com>2010-04-09 00:14:23 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-04-09 02:36:07 -0400
commit812d402648f4fc1ab1091b2172a46fc1b367c724 (patch)
tree9dc52d5bfdbc170559169a0157ed3295d551e9cf
parent84c124da9ff50bd71fab9c939ee5b7cd8bef2bd9 (diff)
blkio: Add io_merged stat
This includes both the number of bios merged into requests belonging to this cgroup as well as the number of requests merged together. In the past, we've observed different merging behavior across upstream kernels, some by design some actual bugs. This stat helps a lot in debugging such problems when applications report decreased throughput with a new kernel version. This needed adding an extra elevator function to capture bios being merged as I did not want to pollute elevator code with blkiocg knowledge and hence needed the accounting invocation to come from CFQ. Signed-off-by: Divyesh Shah<dpshah@google.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--Documentation/cgroups/blkio-controller.txt5
-rw-r--r--block/blk-cgroup.c17
-rw-r--r--block/blk-cgroup.h8
-rw-r--r--block/blk-core.c2
-rw-r--r--block/cfq-iosched.c11
-rw-r--r--block/elevator.c9
-rw-r--r--include/linux/elevator.h6
7 files changed, 57 insertions, 1 deletions
diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt
index ed04fe9cce1a..810e30171a54 100644
--- a/Documentation/cgroups/blkio-controller.txt
+++ b/Documentation/cgroups/blkio-controller.txt
@@ -134,6 +134,11 @@ Details of cgroup files
134 minor number of the device, third field specifies the operation type 134 minor number of the device, third field specifies the operation type
135 and the fourth field specifies the io_wait_time in ns. 135 and the fourth field specifies the io_wait_time in ns.
136 136
137- blkio.io_merged
138 - Total number of bios/requests merged into requests belonging to this
139 cgroup. This is further divided by the type of operation - read or
140 write, sync or async.
141
137- blkio.dequeue 142- blkio.dequeue
138 - Debugging aid only enabled if CONFIG_DEBUG_CFQ_IOSCHED=y. This 143 - Debugging aid only enabled if CONFIG_DEBUG_CFQ_IOSCHED=y. This
139 gives the statistics about how many a times a group was dequeued 144 gives the statistics about how many a times a group was dequeued
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 6797df508821..d23b538858ce 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -127,6 +127,18 @@ void blkiocg_update_completion_stats(struct blkio_group *blkg,
127} 127}
128EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats); 128EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats);
129 129
130void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
131 bool sync)
132{
133 unsigned long flags;
134
135 spin_lock_irqsave(&blkg->stats_lock, flags);
136 blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_MERGED], 1, direction,
137 sync);
138 spin_unlock_irqrestore(&blkg->stats_lock, flags);
139}
140EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
141
130void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, 142void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
131 struct blkio_group *blkg, void *key, dev_t dev) 143 struct blkio_group *blkg, void *key, dev_t dev)
132{ 144{
@@ -363,6 +375,7 @@ SHOW_FUNCTION_PER_GROUP(io_service_bytes, BLKIO_STAT_SERVICE_BYTES, 1);
363SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1); 375SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1);
364SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1); 376SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1);
365SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1); 377SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1);
378SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1);
366#ifdef CONFIG_DEBUG_BLK_CGROUP 379#ifdef CONFIG_DEBUG_BLK_CGROUP
367SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0); 380SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0);
368#endif 381#endif
@@ -408,6 +421,10 @@ struct cftype blkio_files[] = {
408 .read_map = blkiocg_io_wait_time_read, 421 .read_map = blkiocg_io_wait_time_read,
409 }, 422 },
410 { 423 {
424 .name = "io_merged",
425 .read_map = blkiocg_io_merged_read,
426 },
427 {
411 .name = "reset_stats", 428 .name = "reset_stats",
412 .write_u64 = blkiocg_reset_stats, 429 .write_u64 = blkiocg_reset_stats,
413 }, 430 },
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index b22e55390a4f..470a29db6bec 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -34,6 +34,8 @@ enum stat_type {
34 BLKIO_STAT_SERVICED, 34 BLKIO_STAT_SERVICED,
35 /* Total time spent waiting in scheduler queue in ns */ 35 /* Total time spent waiting in scheduler queue in ns */
36 BLKIO_STAT_WAIT_TIME, 36 BLKIO_STAT_WAIT_TIME,
37 /* Number of IOs merged */
38 BLKIO_STAT_MERGED,
37 /* All the single valued stats go below this */ 39 /* All the single valued stats go below this */
38 BLKIO_STAT_TIME, 40 BLKIO_STAT_TIME,
39 BLKIO_STAT_SECTORS, 41 BLKIO_STAT_SECTORS,
@@ -61,7 +63,7 @@ struct blkio_group_stats {
61 /* total disk time and nr sectors dispatched by this group */ 63 /* total disk time and nr sectors dispatched by this group */
62 uint64_t time; 64 uint64_t time;
63 uint64_t sectors; 65 uint64_t sectors;
64 uint64_t stat_arr[BLKIO_STAT_WAIT_TIME + 1][BLKIO_STAT_TOTAL]; 66 uint64_t stat_arr[BLKIO_STAT_MERGED + 1][BLKIO_STAT_TOTAL];
65#ifdef CONFIG_DEBUG_BLK_CGROUP 67#ifdef CONFIG_DEBUG_BLK_CGROUP
66 /* How many times this group has been removed from service tree */ 68 /* How many times this group has been removed from service tree */
67 unsigned long dequeue; 69 unsigned long dequeue;
@@ -148,6 +150,8 @@ void blkiocg_update_dispatch_stats(struct blkio_group *blkg, uint64_t bytes,
148 bool direction, bool sync); 150 bool direction, bool sync);
149void blkiocg_update_completion_stats(struct blkio_group *blkg, 151void blkiocg_update_completion_stats(struct blkio_group *blkg,
150 uint64_t start_time, uint64_t io_start_time, bool direction, bool sync); 152 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,
154 bool sync);
151#else 155#else
152struct cgroup; 156struct cgroup;
153static inline struct blkio_cgroup * 157static inline struct blkio_cgroup *
@@ -169,5 +173,7 @@ static inline void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
169static inline void blkiocg_update_completion_stats(struct blkio_group *blkg, 173static inline void blkiocg_update_completion_stats(struct blkio_group *blkg,
170 uint64_t start_time, uint64_t io_start_time, bool direction, 174 uint64_t start_time, uint64_t io_start_time, bool direction,
171 bool sync) {} 175 bool sync) {}
176static inline void blkiocg_update_io_merged_stats(struct blkio_group *blkg,
177 bool direction, bool sync) {}
172#endif 178#endif
173#endif /* _BLK_CGROUP_H */ 179#endif /* _BLK_CGROUP_H */
diff --git a/block/blk-core.c b/block/blk-core.c
index 4b1b29ef2cb0..e9a5ae25db8c 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1202,6 +1202,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
1202 if (!blk_rq_cpu_valid(req)) 1202 if (!blk_rq_cpu_valid(req))
1203 req->cpu = bio->bi_comp_cpu; 1203 req->cpu = bio->bi_comp_cpu;
1204 drive_stat_acct(req, 0); 1204 drive_stat_acct(req, 0);
1205 elv_bio_merged(q, req, bio);
1205 if (!attempt_back_merge(q, req)) 1206 if (!attempt_back_merge(q, req))
1206 elv_merged_request(q, req, el_ret); 1207 elv_merged_request(q, req, el_ret);
1207 goto out; 1208 goto out;
@@ -1235,6 +1236,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
1235 if (!blk_rq_cpu_valid(req)) 1236 if (!blk_rq_cpu_valid(req))
1236 req->cpu = bio->bi_comp_cpu; 1237 req->cpu = bio->bi_comp_cpu;
1237 drive_stat_acct(req, 0); 1238 drive_stat_acct(req, 0);
1239 elv_bio_merged(q, req, bio);
1238 if (!attempt_front_merge(q, req)) 1240 if (!attempt_front_merge(q, req))
1239 elv_merged_request(q, req, el_ret); 1241 elv_merged_request(q, req, el_ret);
1240 goto out; 1242 goto out;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 5617ae030b15..4eb1906cf6c6 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1467,6 +1467,14 @@ static void cfq_merged_request(struct request_queue *q, struct request *req,
1467 } 1467 }
1468} 1468}
1469 1469
1470static void cfq_bio_merged(struct request_queue *q, struct request *req,
1471 struct bio *bio)
1472{
1473 struct cfq_queue *cfqq = RQ_CFQQ(req);
1474 blkiocg_update_io_merged_stats(&cfqq->cfqg->blkg, bio_data_dir(bio),
1475 cfq_bio_sync(bio));
1476}
1477
1470static void 1478static void
1471cfq_merged_requests(struct request_queue *q, struct request *rq, 1479cfq_merged_requests(struct request_queue *q, struct request *rq,
1472 struct request *next) 1480 struct request *next)
@@ -1484,6 +1492,8 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
1484 if (cfqq->next_rq == next) 1492 if (cfqq->next_rq == next)
1485 cfqq->next_rq = rq; 1493 cfqq->next_rq = rq;
1486 cfq_remove_request(next); 1494 cfq_remove_request(next);
1495 blkiocg_update_io_merged_stats(&cfqq->cfqg->blkg, rq_data_dir(next),
1496 rq_is_sync(next));
1487} 1497}
1488 1498
1489static int cfq_allow_merge(struct request_queue *q, struct request *rq, 1499static int cfq_allow_merge(struct request_queue *q, struct request *rq,
@@ -3861,6 +3871,7 @@ static struct elevator_type iosched_cfq = {
3861 .elevator_merged_fn = cfq_merged_request, 3871 .elevator_merged_fn = cfq_merged_request,
3862 .elevator_merge_req_fn = cfq_merged_requests, 3872 .elevator_merge_req_fn = cfq_merged_requests,
3863 .elevator_allow_merge_fn = cfq_allow_merge, 3873 .elevator_allow_merge_fn = cfq_allow_merge,
3874 .elevator_bio_merged_fn = cfq_bio_merged,
3864 .elevator_dispatch_fn = cfq_dispatch_requests, 3875 .elevator_dispatch_fn = cfq_dispatch_requests,
3865 .elevator_add_req_fn = cfq_insert_request, 3876 .elevator_add_req_fn = cfq_insert_request,
3866 .elevator_activate_req_fn = cfq_activate_request, 3877 .elevator_activate_req_fn = cfq_activate_request,
diff --git a/block/elevator.c b/block/elevator.c
index 76e3702d5381..5e734592bb40 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -539,6 +539,15 @@ void elv_merge_requests(struct request_queue *q, struct request *rq,
539 q->last_merge = rq; 539 q->last_merge = rq;
540} 540}
541 541
542void elv_bio_merged(struct request_queue *q, struct request *rq,
543 struct bio *bio)
544{
545 struct elevator_queue *e = q->elevator;
546
547 if (e->ops->elevator_bio_merged_fn)
548 e->ops->elevator_bio_merged_fn(q, rq, bio);
549}
550
542void elv_requeue_request(struct request_queue *q, struct request *rq) 551void elv_requeue_request(struct request_queue *q, struct request *rq)
543{ 552{
544 /* 553 /*
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 1cb3372e65d8..2c958f4fce1e 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -14,6 +14,9 @@ typedef void (elevator_merged_fn) (struct request_queue *, struct request *, int
14 14
15typedef int (elevator_allow_merge_fn) (struct request_queue *, struct request *, struct bio *); 15typedef int (elevator_allow_merge_fn) (struct request_queue *, struct request *, struct bio *);
16 16
17typedef void (elevator_bio_merged_fn) (struct request_queue *,
18 struct request *, struct bio *);
19
17typedef int (elevator_dispatch_fn) (struct request_queue *, int); 20typedef int (elevator_dispatch_fn) (struct request_queue *, int);
18 21
19typedef void (elevator_add_req_fn) (struct request_queue *, struct request *); 22typedef void (elevator_add_req_fn) (struct request_queue *, struct request *);
@@ -36,6 +39,7 @@ struct elevator_ops
36 elevator_merged_fn *elevator_merged_fn; 39 elevator_merged_fn *elevator_merged_fn;
37 elevator_merge_req_fn *elevator_merge_req_fn; 40 elevator_merge_req_fn *elevator_merge_req_fn;
38 elevator_allow_merge_fn *elevator_allow_merge_fn; 41 elevator_allow_merge_fn *elevator_allow_merge_fn;
42 elevator_bio_merged_fn *elevator_bio_merged_fn;
39 43
40 elevator_dispatch_fn *elevator_dispatch_fn; 44 elevator_dispatch_fn *elevator_dispatch_fn;
41 elevator_add_req_fn *elevator_add_req_fn; 45 elevator_add_req_fn *elevator_add_req_fn;
@@ -103,6 +107,8 @@ extern int elv_merge(struct request_queue *, struct request **, struct bio *);
103extern void elv_merge_requests(struct request_queue *, struct request *, 107extern void elv_merge_requests(struct request_queue *, struct request *,
104 struct request *); 108 struct request *);
105extern void elv_merged_request(struct request_queue *, struct request *, int); 109extern void elv_merged_request(struct request_queue *, struct request *, int);
110extern void elv_bio_merged(struct request_queue *q, struct request *,
111 struct bio *);
106extern void elv_requeue_request(struct request_queue *, struct request *); 112extern void elv_requeue_request(struct request_queue *, struct request *);
107extern int elv_queue_empty(struct request_queue *); 113extern int elv_queue_empty(struct request_queue *);
108extern struct request *elv_former_request(struct request_queue *, struct request *); 114extern struct request *elv_former_request(struct request_queue *, struct request *);