diff options
| author | Divyesh Shah <dpshah@google.com> | 2010-04-09 00:15:10 -0400 |
|---|---|---|
| committer | Jens Axboe <jens.axboe@oracle.com> | 2010-04-09 02:36:08 -0400 |
| commit | cdc1184cf4a7bd99f5473a91244197accc49146b (patch) | |
| tree | ecd572867bfa5a82fa4ed16d7303448c7ea7d24c /block | |
| parent | 812d402648f4fc1ab1091b2172a46fc1b367c724 (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.c | 98 | ||||
| -rw-r--r-- | block/blk-cgroup.h | 20 | ||||
| -rw-r--r-- | block/cfq-iosched.c | 11 |
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 | */ | ||
| 89 | static 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 | ||
| 108 | void 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 | } | ||
| 121 | EXPORT_SYMBOL_GPL(blkiocg_update_set_active_queue_stats); | ||
| 122 | #endif | ||
| 123 | |||
| 124 | void 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 | } | ||
| 135 | EXPORT_SYMBOL_GPL(blkiocg_update_request_add_stats); | ||
| 136 | |||
| 137 | void 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 | } | ||
| 147 | EXPORT_SYMBOL_GPL(blkiocg_update_request_remove_stats); | ||
| 148 | |||
| 84 | void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time) | 149 | void 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); | |||
| 376 | SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1); | 454 | SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1); |
| 377 | SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1); | 455 | SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1); |
| 378 | SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1); | 456 | SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1); |
| 457 | SHOW_FUNCTION_PER_GROUP(io_queued, BLKIO_STAT_QUEUED, 1); | ||
| 379 | #ifdef CONFIG_DEBUG_BLK_CGROUP | 458 | #ifdef CONFIG_DEBUG_BLK_CGROUP |
| 380 | SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0); | 459 | SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0); |
| 460 | SHOW_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]; |
