diff options
author | Luca Miccio <lucmiccio@gmail.com> | 2017-11-13 01:34:10 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-11-14 22:13:33 -0500 |
commit | a33801e8b4735b8d473f963e5854172f9cde3e8b (patch) | |
tree | acebf1dbfbe5effb178f76d31b841b9fb24f45fd /block/bfq-cgroup.c | |
parent | 24bfd19bb7890255693ee5cb6dc100d8d215d00b (diff) |
block, bfq: move debug blkio stats behind CONFIG_DEBUG_BLK_CGROUP
BFQ currently creates, and updates, its own instance of the whole
set of blkio statistics that cfq creates. Yet, from the comments
of Tejun Heo in [1], it turned out that most of these statistics
are meant/useful only for debugging. This commit makes BFQ create
the latter, debugging statistics only if the option
CONFIG_DEBUG_BLK_CGROUP is set.
By doing so, this commit also enables BFQ to enjoy a high perfomance
boost. The reason is that, if CONFIG_DEBUG_BLK_CGROUP is not set, then
BFQ has to update far fewer statistics, and, in particular, not the
heaviest to update. To give an idea of the benefits, if
CONFIG_DEBUG_BLK_CGROUP is not set, then, on an Intel i7-4850HQ, and
with 8 threads doing random I/O in parallel on null_blk (configured
with 0 latency), the throughput of BFQ grows from 310 to 400 KIOPS
(+30%). We have measured similar or even much higher boosts with other
CPUs: e.g., +45% with an ARM CortexTM-A53 Octa-core. Our results have
been obtained and can be reproduced very easily with the script in [1].
[1] https://www.spinics.net/lists/linux-block/msg18943.html
Suggested-by: Tejun Heo <tj@kernel.org>
Suggested-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Lee Tibbert <lee.tibbert@gmail.com>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Signed-off-by: Luca Miccio <lucmiccio@gmail.com>
Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/bfq-cgroup.c')
-rw-r--r-- | block/bfq-cgroup.c | 148 |
1 files changed, 84 insertions, 64 deletions
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index ceefb9a706d6..da1525ec4c87 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #include "bfq-iosched.h" | 25 | #include "bfq-iosched.h" |
26 | 26 | ||
27 | #ifdef CONFIG_BFQ_GROUP_IOSCHED | 27 | #if defined(CONFIG_BFQ_GROUP_IOSCHED) && defined(CONFIG_DEBUG_BLK_CGROUP) |
28 | 28 | ||
29 | /* bfqg stats flags */ | 29 | /* bfqg stats flags */ |
30 | enum bfqg_stats_flags { | 30 | enum bfqg_stats_flags { |
@@ -152,6 +152,57 @@ void bfqg_stats_update_avg_queue_size(struct bfq_group *bfqg) | |||
152 | bfqg_stats_update_group_wait_time(stats); | 152 | bfqg_stats_update_group_wait_time(stats); |
153 | } | 153 | } |
154 | 154 | ||
155 | void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq, | ||
156 | unsigned int op) | ||
157 | { | ||
158 | blkg_rwstat_add(&bfqg->stats.queued, op, 1); | ||
159 | bfqg_stats_end_empty_time(&bfqg->stats); | ||
160 | if (!(bfqq == ((struct bfq_data *)bfqg->bfqd)->in_service_queue)) | ||
161 | bfqg_stats_set_start_group_wait_time(bfqg, bfqq_group(bfqq)); | ||
162 | } | ||
163 | |||
164 | void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op) | ||
165 | { | ||
166 | blkg_rwstat_add(&bfqg->stats.queued, op, -1); | ||
167 | } | ||
168 | |||
169 | void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op) | ||
170 | { | ||
171 | blkg_rwstat_add(&bfqg->stats.merged, op, 1); | ||
172 | } | ||
173 | |||
174 | void bfqg_stats_update_completion(struct bfq_group *bfqg, uint64_t start_time, | ||
175 | uint64_t io_start_time, unsigned int op) | ||
176 | { | ||
177 | struct bfqg_stats *stats = &bfqg->stats; | ||
178 | unsigned long long now = sched_clock(); | ||
179 | |||
180 | if (time_after64(now, io_start_time)) | ||
181 | blkg_rwstat_add(&stats->service_time, op, | ||
182 | now - io_start_time); | ||
183 | if (time_after64(io_start_time, start_time)) | ||
184 | blkg_rwstat_add(&stats->wait_time, op, | ||
185 | io_start_time - start_time); | ||
186 | } | ||
187 | |||
188 | #else /* CONFIG_BFQ_GROUP_IOSCHED && CONFIG_DEBUG_BLK_CGROUP */ | ||
189 | |||
190 | void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq, | ||
191 | unsigned int op) { } | ||
192 | void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op) { } | ||
193 | void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op) { } | ||
194 | void bfqg_stats_update_completion(struct bfq_group *bfqg, uint64_t start_time, | ||
195 | uint64_t io_start_time, unsigned int op) { } | ||
196 | void bfqg_stats_update_dequeue(struct bfq_group *bfqg) { } | ||
197 | void bfqg_stats_set_start_empty_time(struct bfq_group *bfqg) { } | ||
198 | void bfqg_stats_update_idle_time(struct bfq_group *bfqg) { } | ||
199 | void bfqg_stats_set_start_idle_time(struct bfq_group *bfqg) { } | ||
200 | void bfqg_stats_update_avg_queue_size(struct bfq_group *bfqg) { } | ||
201 | |||
202 | #endif /* CONFIG_BFQ_GROUP_IOSCHED && CONFIG_DEBUG_BLK_CGROUP */ | ||
203 | |||
204 | #ifdef CONFIG_BFQ_GROUP_IOSCHED | ||
205 | |||
155 | /* | 206 | /* |
156 | * blk-cgroup policy-related handlers | 207 | * blk-cgroup policy-related handlers |
157 | * The following functions help in converting between blk-cgroup | 208 | * The following functions help in converting between blk-cgroup |
@@ -229,42 +280,10 @@ void bfqg_and_blkg_put(struct bfq_group *bfqg) | |||
229 | blkg_put(bfqg_to_blkg(bfqg)); | 280 | blkg_put(bfqg_to_blkg(bfqg)); |
230 | } | 281 | } |
231 | 282 | ||
232 | void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq, | ||
233 | unsigned int op) | ||
234 | { | ||
235 | blkg_rwstat_add(&bfqg->stats.queued, op, 1); | ||
236 | bfqg_stats_end_empty_time(&bfqg->stats); | ||
237 | if (!(bfqq == ((struct bfq_data *)bfqg->bfqd)->in_service_queue)) | ||
238 | bfqg_stats_set_start_group_wait_time(bfqg, bfqq_group(bfqq)); | ||
239 | } | ||
240 | |||
241 | void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op) | ||
242 | { | ||
243 | blkg_rwstat_add(&bfqg->stats.queued, op, -1); | ||
244 | } | ||
245 | |||
246 | void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op) | ||
247 | { | ||
248 | blkg_rwstat_add(&bfqg->stats.merged, op, 1); | ||
249 | } | ||
250 | |||
251 | void bfqg_stats_update_completion(struct bfq_group *bfqg, uint64_t start_time, | ||
252 | uint64_t io_start_time, unsigned int op) | ||
253 | { | ||
254 | struct bfqg_stats *stats = &bfqg->stats; | ||
255 | unsigned long long now = sched_clock(); | ||
256 | |||
257 | if (time_after64(now, io_start_time)) | ||
258 | blkg_rwstat_add(&stats->service_time, op, | ||
259 | now - io_start_time); | ||
260 | if (time_after64(io_start_time, start_time)) | ||
261 | blkg_rwstat_add(&stats->wait_time, op, | ||
262 | io_start_time - start_time); | ||
263 | } | ||
264 | |||
265 | /* @stats = 0 */ | 283 | /* @stats = 0 */ |
266 | static void bfqg_stats_reset(struct bfqg_stats *stats) | 284 | static void bfqg_stats_reset(struct bfqg_stats *stats) |
267 | { | 285 | { |
286 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
268 | /* queued stats shouldn't be cleared */ | 287 | /* queued stats shouldn't be cleared */ |
269 | blkg_rwstat_reset(&stats->merged); | 288 | blkg_rwstat_reset(&stats->merged); |
270 | blkg_rwstat_reset(&stats->service_time); | 289 | blkg_rwstat_reset(&stats->service_time); |
@@ -276,6 +295,7 @@ static void bfqg_stats_reset(struct bfqg_stats *stats) | |||
276 | blkg_stat_reset(&stats->group_wait_time); | 295 | blkg_stat_reset(&stats->group_wait_time); |
277 | blkg_stat_reset(&stats->idle_time); | 296 | blkg_stat_reset(&stats->idle_time); |
278 | blkg_stat_reset(&stats->empty_time); | 297 | blkg_stat_reset(&stats->empty_time); |
298 | #endif | ||
279 | } | 299 | } |
280 | 300 | ||
281 | /* @to += @from */ | 301 | /* @to += @from */ |
@@ -284,6 +304,7 @@ static void bfqg_stats_add_aux(struct bfqg_stats *to, struct bfqg_stats *from) | |||
284 | if (!to || !from) | 304 | if (!to || !from) |
285 | return; | 305 | return; |
286 | 306 | ||
307 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
287 | /* queued stats shouldn't be cleared */ | 308 | /* queued stats shouldn't be cleared */ |
288 | blkg_rwstat_add_aux(&to->merged, &from->merged); | 309 | blkg_rwstat_add_aux(&to->merged, &from->merged); |
289 | blkg_rwstat_add_aux(&to->service_time, &from->service_time); | 310 | blkg_rwstat_add_aux(&to->service_time, &from->service_time); |
@@ -296,6 +317,7 @@ static void bfqg_stats_add_aux(struct bfqg_stats *to, struct bfqg_stats *from) | |||
296 | blkg_stat_add_aux(&to->group_wait_time, &from->group_wait_time); | 317 | blkg_stat_add_aux(&to->group_wait_time, &from->group_wait_time); |
297 | blkg_stat_add_aux(&to->idle_time, &from->idle_time); | 318 | blkg_stat_add_aux(&to->idle_time, &from->idle_time); |
298 | blkg_stat_add_aux(&to->empty_time, &from->empty_time); | 319 | blkg_stat_add_aux(&to->empty_time, &from->empty_time); |
320 | #endif | ||
299 | } | 321 | } |
300 | 322 | ||
301 | /* | 323 | /* |
@@ -342,6 +364,7 @@ void bfq_init_entity(struct bfq_entity *entity, struct bfq_group *bfqg) | |||
342 | 364 | ||
343 | static void bfqg_stats_exit(struct bfqg_stats *stats) | 365 | static void bfqg_stats_exit(struct bfqg_stats *stats) |
344 | { | 366 | { |
367 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
345 | blkg_rwstat_exit(&stats->merged); | 368 | blkg_rwstat_exit(&stats->merged); |
346 | blkg_rwstat_exit(&stats->service_time); | 369 | blkg_rwstat_exit(&stats->service_time); |
347 | blkg_rwstat_exit(&stats->wait_time); | 370 | blkg_rwstat_exit(&stats->wait_time); |
@@ -353,10 +376,12 @@ static void bfqg_stats_exit(struct bfqg_stats *stats) | |||
353 | blkg_stat_exit(&stats->group_wait_time); | 376 | blkg_stat_exit(&stats->group_wait_time); |
354 | blkg_stat_exit(&stats->idle_time); | 377 | blkg_stat_exit(&stats->idle_time); |
355 | blkg_stat_exit(&stats->empty_time); | 378 | blkg_stat_exit(&stats->empty_time); |
379 | #endif | ||
356 | } | 380 | } |
357 | 381 | ||
358 | static int bfqg_stats_init(struct bfqg_stats *stats, gfp_t gfp) | 382 | static int bfqg_stats_init(struct bfqg_stats *stats, gfp_t gfp) |
359 | { | 383 | { |
384 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
360 | if (blkg_rwstat_init(&stats->merged, gfp) || | 385 | if (blkg_rwstat_init(&stats->merged, gfp) || |
361 | blkg_rwstat_init(&stats->service_time, gfp) || | 386 | blkg_rwstat_init(&stats->service_time, gfp) || |
362 | blkg_rwstat_init(&stats->wait_time, gfp) || | 387 | blkg_rwstat_init(&stats->wait_time, gfp) || |
@@ -371,6 +396,7 @@ static int bfqg_stats_init(struct bfqg_stats *stats, gfp_t gfp) | |||
371 | bfqg_stats_exit(stats); | 396 | bfqg_stats_exit(stats); |
372 | return -ENOMEM; | 397 | return -ENOMEM; |
373 | } | 398 | } |
399 | #endif | ||
374 | 400 | ||
375 | return 0; | 401 | return 0; |
376 | } | 402 | } |
@@ -887,6 +913,7 @@ static ssize_t bfq_io_set_weight(struct kernfs_open_file *of, | |||
887 | return bfq_io_set_weight_legacy(of_css(of), NULL, weight); | 913 | return bfq_io_set_weight_legacy(of_css(of), NULL, weight); |
888 | } | 914 | } |
889 | 915 | ||
916 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
890 | static int bfqg_print_stat(struct seq_file *sf, void *v) | 917 | static int bfqg_print_stat(struct seq_file *sf, void *v) |
891 | { | 918 | { |
892 | blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_stat, | 919 | blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_stat, |
@@ -991,6 +1018,7 @@ static int bfqg_print_avg_queue_size(struct seq_file *sf, void *v) | |||
991 | 0, false); | 1018 | 0, false); |
992 | return 0; | 1019 | return 0; |
993 | } | 1020 | } |
1021 | #endif /* CONFIG_DEBUG_BLK_CGROUP */ | ||
994 | 1022 | ||
995 | struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node) | 1023 | struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node) |
996 | { | 1024 | { |
@@ -1029,15 +1057,6 @@ struct cftype bfq_blkcg_legacy_files[] = { | |||
1029 | 1057 | ||
1030 | /* statistics, covers only the tasks in the bfqg */ | 1058 | /* statistics, covers only the tasks in the bfqg */ |
1031 | { | 1059 | { |
1032 | .name = "bfq.time", | ||
1033 | .private = offsetof(struct bfq_group, stats.time), | ||
1034 | .seq_show = bfqg_print_stat, | ||
1035 | }, | ||
1036 | { | ||
1037 | .name = "bfq.sectors", | ||
1038 | .seq_show = bfqg_print_stat_sectors, | ||
1039 | }, | ||
1040 | { | ||
1041 | .name = "bfq.io_service_bytes", | 1060 | .name = "bfq.io_service_bytes", |
1042 | .private = (unsigned long)&blkcg_policy_bfq, | 1061 | .private = (unsigned long)&blkcg_policy_bfq, |
1043 | .seq_show = blkg_print_stat_bytes, | 1062 | .seq_show = blkg_print_stat_bytes, |
@@ -1047,6 +1066,16 @@ struct cftype bfq_blkcg_legacy_files[] = { | |||
1047 | .private = (unsigned long)&blkcg_policy_bfq, | 1066 | .private = (unsigned long)&blkcg_policy_bfq, |
1048 | .seq_show = blkg_print_stat_ios, | 1067 | .seq_show = blkg_print_stat_ios, |
1049 | }, | 1068 | }, |
1069 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
1070 | { | ||
1071 | .name = "bfq.time", | ||
1072 | .private = offsetof(struct bfq_group, stats.time), | ||
1073 | .seq_show = bfqg_print_stat, | ||
1074 | }, | ||
1075 | { | ||
1076 | .name = "bfq.sectors", | ||
1077 | .seq_show = bfqg_print_stat_sectors, | ||
1078 | }, | ||
1050 | { | 1079 | { |
1051 | .name = "bfq.io_service_time", | 1080 | .name = "bfq.io_service_time", |
1052 | .private = offsetof(struct bfq_group, stats.service_time), | 1081 | .private = offsetof(struct bfq_group, stats.service_time), |
@@ -1067,18 +1096,10 @@ struct cftype bfq_blkcg_legacy_files[] = { | |||
1067 | .private = offsetof(struct bfq_group, stats.queued), | 1096 | .private = offsetof(struct bfq_group, stats.queued), |
1068 | .seq_show = bfqg_print_rwstat, | 1097 | .seq_show = bfqg_print_rwstat, |
1069 | }, | 1098 | }, |
1099 | #endif /* CONFIG_DEBUG_BLK_CGROUP */ | ||
1070 | 1100 | ||
1071 | /* the same statictics which cover the bfqg and its descendants */ | 1101 | /* the same statictics which cover the bfqg and its descendants */ |
1072 | { | 1102 | { |
1073 | .name = "bfq.time_recursive", | ||
1074 | .private = offsetof(struct bfq_group, stats.time), | ||
1075 | .seq_show = bfqg_print_stat_recursive, | ||
1076 | }, | ||
1077 | { | ||
1078 | .name = "bfq.sectors_recursive", | ||
1079 | .seq_show = bfqg_print_stat_sectors_recursive, | ||
1080 | }, | ||
1081 | { | ||
1082 | .name = "bfq.io_service_bytes_recursive", | 1103 | .name = "bfq.io_service_bytes_recursive", |
1083 | .private = (unsigned long)&blkcg_policy_bfq, | 1104 | .private = (unsigned long)&blkcg_policy_bfq, |
1084 | .seq_show = blkg_print_stat_bytes_recursive, | 1105 | .seq_show = blkg_print_stat_bytes_recursive, |
@@ -1088,6 +1109,16 @@ struct cftype bfq_blkcg_legacy_files[] = { | |||
1088 | .private = (unsigned long)&blkcg_policy_bfq, | 1109 | .private = (unsigned long)&blkcg_policy_bfq, |
1089 | .seq_show = blkg_print_stat_ios_recursive, | 1110 | .seq_show = blkg_print_stat_ios_recursive, |
1090 | }, | 1111 | }, |
1112 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
1113 | { | ||
1114 | .name = "bfq.time_recursive", | ||
1115 | .private = offsetof(struct bfq_group, stats.time), | ||
1116 | .seq_show = bfqg_print_stat_recursive, | ||
1117 | }, | ||
1118 | { | ||
1119 | .name = "bfq.sectors_recursive", | ||
1120 | .seq_show = bfqg_print_stat_sectors_recursive, | ||
1121 | }, | ||
1091 | { | 1122 | { |
1092 | .name = "bfq.io_service_time_recursive", | 1123 | .name = "bfq.io_service_time_recursive", |
1093 | .private = offsetof(struct bfq_group, stats.service_time), | 1124 | .private = offsetof(struct bfq_group, stats.service_time), |
@@ -1132,6 +1163,7 @@ struct cftype bfq_blkcg_legacy_files[] = { | |||
1132 | .private = offsetof(struct bfq_group, stats.dequeue), | 1163 | .private = offsetof(struct bfq_group, stats.dequeue), |
1133 | .seq_show = bfqg_print_stat, | 1164 | .seq_show = bfqg_print_stat, |
1134 | }, | 1165 | }, |
1166 | #endif /* CONFIG_DEBUG_BLK_CGROUP */ | ||
1135 | { } /* terminate */ | 1167 | { } /* terminate */ |
1136 | }; | 1168 | }; |
1137 | 1169 | ||
@@ -1147,18 +1179,6 @@ struct cftype bfq_blkg_files[] = { | |||
1147 | 1179 | ||
1148 | #else /* CONFIG_BFQ_GROUP_IOSCHED */ | 1180 | #else /* CONFIG_BFQ_GROUP_IOSCHED */ |
1149 | 1181 | ||
1150 | void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq, | ||
1151 | unsigned int op) { } | ||
1152 | void bfqg_stats_update_io_remove(struct bfq_group *bfqg, unsigned int op) { } | ||
1153 | void bfqg_stats_update_io_merged(struct bfq_group *bfqg, unsigned int op) { } | ||
1154 | void bfqg_stats_update_completion(struct bfq_group *bfqg, uint64_t start_time, | ||
1155 | uint64_t io_start_time, unsigned int op) { } | ||
1156 | void bfqg_stats_update_dequeue(struct bfq_group *bfqg) { } | ||
1157 | void bfqg_stats_set_start_empty_time(struct bfq_group *bfqg) { } | ||
1158 | void bfqg_stats_update_idle_time(struct bfq_group *bfqg) { } | ||
1159 | void bfqg_stats_set_start_idle_time(struct bfq_group *bfqg) { } | ||
1160 | void bfqg_stats_update_avg_queue_size(struct bfq_group *bfqg) { } | ||
1161 | |||
1162 | void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq, | 1182 | void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq, |
1163 | struct bfq_group *bfqg) {} | 1183 | struct bfq_group *bfqg) {} |
1164 | 1184 | ||