Commit 220841906fccafaf4094e87bdb6d252e20cf8c7c
Committed by
Jens Axboe
1 parent
2868ef7b39
Exists in
master
and in
7 other branches
blkio: Export disk time and sectors used by a group to user space
o Export disk time and sector used by a group to user space through cgroup interface. o Also export a "dequeue" interface to cgroup which keeps track of how many a times a group was deleted from service tree. Helps in debugging. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Showing 3 changed files with 99 additions and 6 deletions Side-by-side Diff
block/blk-cgroup.c
... | ... | @@ -11,6 +11,8 @@ |
11 | 11 | * Nauman Rafique <nauman@google.com> |
12 | 12 | */ |
13 | 13 | #include <linux/ioprio.h> |
14 | +#include <linux/seq_file.h> | |
15 | +#include <linux/kdev_t.h> | |
14 | 16 | #include "blk-cgroup.h" |
15 | 17 | |
16 | 18 | extern void cfq_unlink_blkio_group(void *, struct blkio_group *); |
17 | 19 | |
... | ... | @@ -23,8 +25,15 @@ |
23 | 25 | struct blkio_cgroup, css); |
24 | 26 | } |
25 | 27 | |
28 | +void blkiocg_update_blkio_group_stats(struct blkio_group *blkg, | |
29 | + unsigned long time, unsigned long sectors) | |
30 | +{ | |
31 | + blkg->time += time; | |
32 | + blkg->sectors += sectors; | |
33 | +} | |
34 | + | |
26 | 35 | void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, |
27 | - struct blkio_group *blkg, void *key) | |
36 | + struct blkio_group *blkg, void *key, dev_t dev) | |
28 | 37 | { |
29 | 38 | unsigned long flags; |
30 | 39 | |
... | ... | @@ -37,6 +46,7 @@ |
37 | 46 | /* Need to take css reference ? */ |
38 | 47 | cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path)); |
39 | 48 | #endif |
49 | + blkg->dev = dev; | |
40 | 50 | } |
41 | 51 | |
42 | 52 | static void __blkiocg_del_blkio_group(struct blkio_group *blkg) |
43 | 53 | |
... | ... | @@ -115,12 +125,64 @@ |
115 | 125 | return 0; |
116 | 126 | } |
117 | 127 | |
128 | +#define SHOW_FUNCTION_PER_GROUP(__VAR) \ | |
129 | +static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \ | |
130 | + struct cftype *cftype, struct seq_file *m) \ | |
131 | +{ \ | |
132 | + struct blkio_cgroup *blkcg; \ | |
133 | + struct blkio_group *blkg; \ | |
134 | + struct hlist_node *n; \ | |
135 | + \ | |
136 | + if (!cgroup_lock_live_group(cgroup)) \ | |
137 | + return -ENODEV; \ | |
138 | + \ | |
139 | + blkcg = cgroup_to_blkio_cgroup(cgroup); \ | |
140 | + rcu_read_lock(); \ | |
141 | + hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\ | |
142 | + if (blkg->dev) \ | |
143 | + seq_printf(m, "%u:%u %lu\n", MAJOR(blkg->dev), \ | |
144 | + MINOR(blkg->dev), blkg->__VAR); \ | |
145 | + } \ | |
146 | + rcu_read_unlock(); \ | |
147 | + cgroup_unlock(); \ | |
148 | + return 0; \ | |
149 | +} | |
150 | + | |
151 | +SHOW_FUNCTION_PER_GROUP(time); | |
152 | +SHOW_FUNCTION_PER_GROUP(sectors); | |
153 | +#ifdef CONFIG_DEBUG_BLK_CGROUP | |
154 | +SHOW_FUNCTION_PER_GROUP(dequeue); | |
155 | +#endif | |
156 | +#undef SHOW_FUNCTION_PER_GROUP | |
157 | + | |
158 | +#ifdef CONFIG_DEBUG_BLK_CGROUP | |
159 | +void blkiocg_update_blkio_group_dequeue_stats(struct blkio_group *blkg, | |
160 | + unsigned long dequeue) | |
161 | +{ | |
162 | + blkg->dequeue += dequeue; | |
163 | +} | |
164 | +#endif | |
165 | + | |
118 | 166 | struct cftype blkio_files[] = { |
119 | 167 | { |
120 | 168 | .name = "weight", |
121 | 169 | .read_u64 = blkiocg_weight_read, |
122 | 170 | .write_u64 = blkiocg_weight_write, |
123 | 171 | }, |
172 | + { | |
173 | + .name = "time", | |
174 | + .read_seq_string = blkiocg_time_read, | |
175 | + }, | |
176 | + { | |
177 | + .name = "sectors", | |
178 | + .read_seq_string = blkiocg_sectors_read, | |
179 | + }, | |
180 | +#ifdef CONFIG_DEBUG_BLK_CGROUP | |
181 | + { | |
182 | + .name = "dequeue", | |
183 | + .read_seq_string = blkiocg_dequeue_read, | |
184 | + }, | |
185 | +#endif | |
124 | 186 | }; |
125 | 187 | |
126 | 188 | static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup) |
block/blk-cgroup.h
... | ... | @@ -30,7 +30,15 @@ |
30 | 30 | #ifdef CONFIG_DEBUG_BLK_CGROUP |
31 | 31 | /* Store cgroup path */ |
32 | 32 | char path[128]; |
33 | + /* How many times this group has been removed from service tree */ | |
34 | + unsigned long dequeue; | |
33 | 35 | #endif |
36 | + /* The device MKDEV(major, minor), this group has been created for */ | |
37 | + dev_t dev; | |
38 | + | |
39 | + /* total disk time and nr sectors dispatched by this group */ | |
40 | + unsigned long time; | |
41 | + unsigned long sectors; | |
34 | 42 | }; |
35 | 43 | |
36 | 44 | #define BLKIO_WEIGHT_MIN 100 |
37 | 45 | |
38 | 46 | |
39 | 47 | |
40 | 48 | |
... | ... | @@ -42,24 +50,30 @@ |
42 | 50 | { |
43 | 51 | return blkg->path; |
44 | 52 | } |
53 | +void blkiocg_update_blkio_group_dequeue_stats(struct blkio_group *blkg, | |
54 | + unsigned long dequeue); | |
45 | 55 | #else |
46 | 56 | static inline char *blkg_path(struct blkio_group *blkg) { return NULL; } |
57 | +static inline void blkiocg_update_blkio_group_dequeue_stats( | |
58 | + struct blkio_group *blkg, unsigned long dequeue) {} | |
47 | 59 | #endif |
48 | 60 | |
49 | 61 | #ifdef CONFIG_BLK_CGROUP |
50 | 62 | extern struct blkio_cgroup blkio_root_cgroup; |
51 | 63 | extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup); |
52 | 64 | extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, |
53 | - struct blkio_group *blkg, void *key); | |
65 | + struct blkio_group *blkg, void *key, dev_t dev); | |
54 | 66 | extern int blkiocg_del_blkio_group(struct blkio_group *blkg); |
55 | 67 | extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, |
56 | 68 | void *key); |
69 | +void blkiocg_update_blkio_group_stats(struct blkio_group *blkg, | |
70 | + unsigned long time, unsigned long sectors); | |
57 | 71 | #else |
58 | 72 | static inline struct blkio_cgroup * |
59 | 73 | cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; } |
60 | 74 | |
61 | 75 | static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, |
62 | - struct blkio_group *blkg, void *key) | |
76 | + struct blkio_group *blkg, void *key, dev_t dev) | |
63 | 77 | { |
64 | 78 | } |
65 | 79 | |
... | ... | @@ -68,6 +82,10 @@ |
68 | 82 | |
69 | 83 | static inline struct blkio_group * |
70 | 84 | blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key) { return NULL; } |
85 | +static inline void blkiocg_update_blkio_group_stats(struct blkio_group *blkg, | |
86 | + unsigned long time, unsigned long sectors) | |
87 | +{ | |
88 | +} | |
71 | 89 | #endif |
72 | 90 | #endif /* _BLK_CGROUP_H */ |
block/cfq-iosched.c
... | ... | @@ -143,6 +143,8 @@ |
143 | 143 | struct cfq_rb_root *service_tree; |
144 | 144 | struct cfq_queue *new_cfqq; |
145 | 145 | struct cfq_group *cfqg; |
146 | + /* Sectors dispatched in current dispatch round */ | |
147 | + unsigned long nr_sectors; | |
146 | 148 | }; |
147 | 149 | |
148 | 150 | /* |
... | ... | @@ -852,6 +854,7 @@ |
852 | 854 | if (!RB_EMPTY_NODE(&cfqg->rb_node)) |
853 | 855 | cfq_rb_erase(&cfqg->rb_node, st); |
854 | 856 | cfqg->saved_workload_slice = 0; |
857 | + blkiocg_update_blkio_group_dequeue_stats(&cfqg->blkg, 1); | |
855 | 858 | } |
856 | 859 | |
857 | 860 | static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq) |
... | ... | @@ -878,7 +881,8 @@ |
878 | 881 | slice_used = allocated_slice; |
879 | 882 | } |
880 | 883 | |
881 | - cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u", slice_used); | |
884 | + cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u sect=%lu", slice_used, | |
885 | + cfqq->nr_sectors); | |
882 | 886 | return slice_used; |
883 | 887 | } |
884 | 888 | |
... | ... | @@ -906,6 +910,8 @@ |
906 | 910 | |
907 | 911 | cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime, |
908 | 912 | st->min_vdisktime); |
913 | + blkiocg_update_blkio_group_stats(&cfqg->blkg, used_sl, | |
914 | + cfqq->nr_sectors); | |
909 | 915 | } |
910 | 916 | |
911 | 917 | #ifdef CONFIG_CFQ_GROUP_IOSCHED |
... | ... | @@ -924,6 +930,8 @@ |
924 | 930 | void *key = cfqd; |
925 | 931 | int i, j; |
926 | 932 | struct cfq_rb_root *st; |
933 | + struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info; | |
934 | + unsigned int major, minor; | |
927 | 935 | |
928 | 936 | /* Do we need to take this reference */ |
929 | 937 | if (!css_tryget(&blkcg->css)) |
... | ... | @@ -951,7 +959,9 @@ |
951 | 959 | atomic_set(&cfqg->ref, 1); |
952 | 960 | |
953 | 961 | /* Add group onto cgroup list */ |
954 | - blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd); | |
962 | + sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); | |
963 | + blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, | |
964 | + MKDEV(major, minor)); | |
955 | 965 | |
956 | 966 | /* Add group on cfqd list */ |
957 | 967 | hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); |
... | ... | @@ -1478,6 +1488,7 @@ |
1478 | 1488 | cfqq->dispatch_start = jiffies; |
1479 | 1489 | cfqq->slice_end = 0; |
1480 | 1490 | cfqq->slice_dispatch = 0; |
1491 | + cfqq->nr_sectors = 0; | |
1481 | 1492 | |
1482 | 1493 | cfq_clear_cfqq_wait_request(cfqq); |
1483 | 1494 | cfq_clear_cfqq_must_dispatch(cfqq); |
... | ... | @@ -1801,6 +1812,7 @@ |
1801 | 1812 | |
1802 | 1813 | if (cfq_cfqq_sync(cfqq)) |
1803 | 1814 | cfqd->sync_flight++; |
1815 | + cfqq->nr_sectors += blk_rq_sectors(rq); | |
1804 | 1816 | } |
1805 | 1817 | |
1806 | 1818 | /* |
... | ... | @@ -3513,7 +3525,8 @@ |
3513 | 3525 | * to make sure that cfq_put_cfqg() does not try to kfree root group |
3514 | 3526 | */ |
3515 | 3527 | atomic_set(&cfqg->ref, 1); |
3516 | - blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg, (void *)cfqd); | |
3528 | + blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg, (void *)cfqd, | |
3529 | + 0); | |
3517 | 3530 | #endif |
3518 | 3531 | /* |
3519 | 3532 | * Not strictly needed (since RB_ROOT just clears the node and we |