aboutsummaryrefslogtreecommitdiffstats
path: root/block/cfq-iosched.c
diff options
context:
space:
mode:
authorDivyesh Shah <dpshah@google.com>2010-04-09 00:15:35 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-04-09 02:36:08 -0400
commit812df48d127365ffd0869aa139738f572a86759c (patch)
tree772ef559057cd432ad874cd429287e7a912b1bb3 /block/cfq-iosched.c
parentcdc1184cf4a7bd99f5473a91244197accc49146b (diff)
blkio: Add more debug-only per-cgroup stats
1) group_wait_time - This is the amount of time the cgroup had to wait to get a timeslice for one of its queues from when it became busy, i.e., went from 0 to 1 request queued. This is different from the io_wait_time which is the cumulative total of the amount of time spent by each IO in that cgroup waiting in the scheduler queue. This stat is a great way to find out any jobs in the fleet that are being starved or waiting for longer than what is expected (due to an IO controller bug or any other issue). 2) empty_time - This is the amount of time a cgroup spends w/o any pending requests. This stat is useful when a job does not seem to be able to use its assigned disk share by helping check if that is happening due to an IO controller bug or because the job is not submitting enough IOs. 3) idle_time - This is the amount of time spent by the IO scheduler idling for a given cgroup in anticipation of a better request than the exising ones from other queues/cgroups. All these stats are recorded using start and stop events. When reading these stats, we do not add the delta between the current time and the last start time if we're between the start and stop events. We avoid doing this to make sure that these numbers are always monotonically increasing when read. Since we're using sched_clock() which may use the tsc as its source, it may induce some inconsistency (due to tsc resync across cpus) if we included the current delta. Signed-off-by: Divyesh Shah<dpshah@google.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r--block/cfq-iosched.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 8e0b86a9111a..b6e095c7ef5e 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -886,7 +886,7 @@ static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
886} 886}
887 887
888static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg, 888static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
889 struct cfq_queue *cfqq) 889 struct cfq_queue *cfqq, bool forced)
890{ 890{
891 struct cfq_rb_root *st = &cfqd->grp_service_tree; 891 struct cfq_rb_root *st = &cfqd->grp_service_tree;
892 unsigned int used_sl, charge_sl; 892 unsigned int used_sl, charge_sl;
@@ -916,6 +916,7 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
916 cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime, 916 cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime,
917 st->min_vdisktime); 917 st->min_vdisktime);
918 blkiocg_update_timeslice_used(&cfqg->blkg, used_sl); 918 blkiocg_update_timeslice_used(&cfqg->blkg, used_sl);
919 blkiocg_set_start_empty_time(&cfqg->blkg, forced);
919} 920}
920 921
921#ifdef CONFIG_CFQ_GROUP_IOSCHED 922#ifdef CONFIG_CFQ_GROUP_IOSCHED
@@ -1528,6 +1529,12 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
1528 return cfqq == RQ_CFQQ(rq); 1529 return cfqq == RQ_CFQQ(rq);
1529} 1530}
1530 1531
1532static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
1533{
1534 del_timer(&cfqd->idle_slice_timer);
1535 blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg);
1536}
1537
1531static void __cfq_set_active_queue(struct cfq_data *cfqd, 1538static void __cfq_set_active_queue(struct cfq_data *cfqd,
1532 struct cfq_queue *cfqq) 1539 struct cfq_queue *cfqq)
1533{ 1540{
@@ -1547,7 +1554,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
1547 cfq_clear_cfqq_fifo_expire(cfqq); 1554 cfq_clear_cfqq_fifo_expire(cfqq);
1548 cfq_mark_cfqq_slice_new(cfqq); 1555 cfq_mark_cfqq_slice_new(cfqq);
1549 1556
1550 del_timer(&cfqd->idle_slice_timer); 1557 cfq_del_timer(cfqd, cfqq);
1551 } 1558 }
1552 1559
1553 cfqd->active_queue = cfqq; 1560 cfqd->active_queue = cfqq;
@@ -1558,12 +1565,12 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
1558 */ 1565 */
1559static void 1566static void
1560__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, 1567__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1561 bool timed_out) 1568 bool timed_out, bool forced)
1562{ 1569{
1563 cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out); 1570 cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out);
1564 1571
1565 if (cfq_cfqq_wait_request(cfqq)) 1572 if (cfq_cfqq_wait_request(cfqq))
1566 del_timer(&cfqd->idle_slice_timer); 1573 cfq_del_timer(cfqd, cfqq);
1567 1574
1568 cfq_clear_cfqq_wait_request(cfqq); 1575 cfq_clear_cfqq_wait_request(cfqq);
1569 cfq_clear_cfqq_wait_busy(cfqq); 1576 cfq_clear_cfqq_wait_busy(cfqq);
@@ -1585,7 +1592,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1585 cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid); 1592 cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
1586 } 1593 }
1587 1594
1588 cfq_group_served(cfqd, cfqq->cfqg, cfqq); 1595 cfq_group_served(cfqd, cfqq->cfqg, cfqq, forced);
1589 1596
1590 if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list)) 1597 if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
1591 cfq_del_cfqq_rr(cfqd, cfqq); 1598 cfq_del_cfqq_rr(cfqd, cfqq);
@@ -1604,12 +1611,13 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1604 } 1611 }
1605} 1612}
1606 1613
1607static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out) 1614static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out,
1615 bool forced)
1608{ 1616{
1609 struct cfq_queue *cfqq = cfqd->active_queue; 1617 struct cfq_queue *cfqq = cfqd->active_queue;
1610 1618
1611 if (cfqq) 1619 if (cfqq)
1612 __cfq_slice_expired(cfqd, cfqq, timed_out); 1620 __cfq_slice_expired(cfqd, cfqq, timed_out, forced);
1613} 1621}
1614 1622
1615/* 1623/*
@@ -1865,6 +1873,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
1865 sl = cfqd->cfq_slice_idle; 1873 sl = cfqd->cfq_slice_idle;
1866 1874
1867 mod_timer(&cfqd->idle_slice_timer, jiffies + sl); 1875 mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
1876 blkiocg_update_set_idle_time_stats(&cfqq->cfqg->blkg);
1868 cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu", sl); 1877 cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu", sl);
1869} 1878}
1870 1879
@@ -2176,7 +2185,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
2176 } 2185 }
2177 2186
2178expire: 2187expire:
2179 cfq_slice_expired(cfqd, 0); 2188 cfq_slice_expired(cfqd, 0, false);
2180new_queue: 2189new_queue:
2181 /* 2190 /*
2182 * Current queue expired. Check if we have to switch to a new 2191 * Current queue expired. Check if we have to switch to a new
@@ -2202,7 +2211,7 @@ static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
2202 BUG_ON(!list_empty(&cfqq->fifo)); 2211 BUG_ON(!list_empty(&cfqq->fifo));
2203 2212
2204 /* By default cfqq is not expired if it is empty. Do it explicitly */ 2213 /* By default cfqq is not expired if it is empty. Do it explicitly */
2205 __cfq_slice_expired(cfqq->cfqd, cfqq, 0); 2214 __cfq_slice_expired(cfqq->cfqd, cfqq, 0, true);
2206 return dispatched; 2215 return dispatched;
2207} 2216}
2208 2217
@@ -2218,7 +2227,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
2218 while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL) 2227 while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL)
2219 dispatched += __cfq_forced_dispatch_cfqq(cfqq); 2228 dispatched += __cfq_forced_dispatch_cfqq(cfqq);
2220 2229
2221 cfq_slice_expired(cfqd, 0); 2230 cfq_slice_expired(cfqd, 0, true);
2222 BUG_ON(cfqd->busy_queues); 2231 BUG_ON(cfqd->busy_queues);
2223 2232
2224 cfq_log(cfqd, "forced_dispatch=%d", dispatched); 2233 cfq_log(cfqd, "forced_dispatch=%d", dispatched);
@@ -2382,10 +2391,15 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
2382 cfqq->slice_dispatch >= cfq_prio_to_maxrq(cfqd, cfqq)) || 2391 cfqq->slice_dispatch >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
2383 cfq_class_idle(cfqq))) { 2392 cfq_class_idle(cfqq))) {
2384 cfqq->slice_end = jiffies + 1; 2393 cfqq->slice_end = jiffies + 1;
2385 cfq_slice_expired(cfqd, 0); 2394 cfq_slice_expired(cfqd, 0, false);
2386 } 2395 }
2387 2396
2388 cfq_log_cfqq(cfqd, cfqq, "dispatched a request"); 2397 cfq_log_cfqq(cfqd, cfqq, "dispatched a request");
2398 /*
2399 * This is needed since we don't exactly match the mod_timer() and
2400 * del_timer() calls in CFQ.
2401 */
2402 blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg);
2389 return 1; 2403 return 1;
2390} 2404}
2391 2405
@@ -2413,7 +2427,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
2413 orig_cfqg = cfqq->orig_cfqg; 2427 orig_cfqg = cfqq->orig_cfqg;
2414 2428
2415 if (unlikely(cfqd->active_queue == cfqq)) { 2429 if (unlikely(cfqd->active_queue == cfqq)) {
2416 __cfq_slice_expired(cfqd, cfqq, 0); 2430 __cfq_slice_expired(cfqd, cfqq, 0, false);
2417 cfq_schedule_dispatch(cfqd); 2431 cfq_schedule_dispatch(cfqd);
2418 } 2432 }
2419 2433
@@ -2514,7 +2528,7 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
2514 struct cfq_queue *__cfqq, *next; 2528 struct cfq_queue *__cfqq, *next;
2515 2529
2516 if (unlikely(cfqq == cfqd->active_queue)) { 2530 if (unlikely(cfqq == cfqd->active_queue)) {
2517 __cfq_slice_expired(cfqd, cfqq, 0); 2531 __cfq_slice_expired(cfqd, cfqq, 0, false);
2518 cfq_schedule_dispatch(cfqd); 2532 cfq_schedule_dispatch(cfqd);
2519 } 2533 }
2520 2534
@@ -3143,7 +3157,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
3143static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) 3157static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
3144{ 3158{
3145 cfq_log_cfqq(cfqd, cfqq, "preempt"); 3159 cfq_log_cfqq(cfqd, cfqq, "preempt");
3146 cfq_slice_expired(cfqd, 1); 3160 cfq_slice_expired(cfqd, 1, false);
3147 3161
3148 /* 3162 /*
3149 * Put the new queue at the front of the of the current list, 3163 * Put the new queue at the front of the of the current list,
@@ -3191,7 +3205,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
3191 if (cfq_cfqq_wait_request(cfqq)) { 3205 if (cfq_cfqq_wait_request(cfqq)) {
3192 if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE || 3206 if (blk_rq_bytes(rq) > PAGE_CACHE_SIZE ||
3193 cfqd->busy_queues > 1) { 3207 cfqd->busy_queues > 1) {
3194 del_timer(&cfqd->idle_slice_timer); 3208 cfq_del_timer(cfqd, cfqq);
3195 cfq_clear_cfqq_wait_request(cfqq); 3209 cfq_clear_cfqq_wait_request(cfqq);
3196 __blk_run_queue(cfqd->queue); 3210 __blk_run_queue(cfqd->queue);
3197 } else 3211 } else
@@ -3352,7 +3366,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
3352 * - when there is a close cooperator 3366 * - when there is a close cooperator
3353 */ 3367 */
3354 if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq)) 3368 if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq))
3355 cfq_slice_expired(cfqd, 1); 3369 cfq_slice_expired(cfqd, 1, false);
3356 else if (sync && cfqq_empty && 3370 else if (sync && cfqq_empty &&
3357 !cfq_close_cooperator(cfqd, cfqq)) { 3371 !cfq_close_cooperator(cfqd, cfqq)) {
3358 cfqd->noidle_tree_requires_idle |= !rq_noidle(rq); 3372 cfqd->noidle_tree_requires_idle |= !rq_noidle(rq);
@@ -3612,7 +3626,7 @@ static void cfq_idle_slice_timer(unsigned long data)
3612 cfq_clear_cfqq_deep(cfqq); 3626 cfq_clear_cfqq_deep(cfqq);
3613 } 3627 }
3614expire: 3628expire:
3615 cfq_slice_expired(cfqd, timed_out); 3629 cfq_slice_expired(cfqd, timed_out, false);
3616out_kick: 3630out_kick:
3617 cfq_schedule_dispatch(cfqd); 3631 cfq_schedule_dispatch(cfqd);
3618out_cont: 3632out_cont:
@@ -3655,7 +3669,7 @@ static void cfq_exit_queue(struct elevator_queue *e)
3655 spin_lock_irq(q->queue_lock); 3669 spin_lock_irq(q->queue_lock);
3656 3670
3657 if (cfqd->active_queue) 3671 if (cfqd->active_queue)
3658 __cfq_slice_expired(cfqd, cfqd->active_queue, 0); 3672 __cfq_slice_expired(cfqd, cfqd->active_queue, 0, false);
3659 3673
3660 while (!list_empty(&cfqd->cic_list)) { 3674 while (!list_empty(&cfqd->cic_list)) {
3661 struct cfq_io_context *cic = list_entry(cfqd->cic_list.next, 3675 struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,