diff options
author | Divyesh Shah <dpshah@google.com> | 2009-01-30 06:46:41 -0500 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-01-30 06:47:33 -0500 |
commit | 3a9a3f6cc55418dd1525e636dccbbe13c394f652 (patch) | |
tree | b23c46b8ecec0a338e4e81454e482f7dcd3ded0c | |
parent | bc58ba9468d94d62c56ab9b47173583ec140b165 (diff) |
cfq-iosched: Allow RT requests to pre-empt ongoing BE timeslice
This patch adds the ability to pre-empt an ongoing BE timeslice when a RT
request is waiting for the current timeslice to complete. This reduces the
wait time to disk for RT requests from an upper bound of 4 (current value
of cfq_quantum) to 1 disk request.
Applied Jens' suggeested changes to avoid the rb lookup and use !cfq_class_rt()
and retested.
Latency(secs) for the RT task when doing sequential reads from 10G file.
| only RT | RT + BE | RT + BE + this patch
small (512 byte) reads | 143 | 163 | 145
large (1Mb) reads | 142 | 158 | 146
Signed-off-by: Divyesh Shah <dpshah@google.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | block/cfq-iosched.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index e8525fa72823..664ebfd092ec 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -84,6 +84,11 @@ struct cfq_data { | |||
84 | */ | 84 | */ |
85 | struct cfq_rb_root service_tree; | 85 | struct cfq_rb_root service_tree; |
86 | unsigned int busy_queues; | 86 | unsigned int busy_queues; |
87 | /* | ||
88 | * Used to track any pending rt requests so we can pre-empt current | ||
89 | * non-RT cfqq in service when this value is non-zero. | ||
90 | */ | ||
91 | unsigned int busy_rt_queues; | ||
87 | 92 | ||
88 | int rq_in_driver; | 93 | int rq_in_driver; |
89 | int sync_flight; | 94 | int sync_flight; |
@@ -562,6 +567,8 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
562 | BUG_ON(cfq_cfqq_on_rr(cfqq)); | 567 | BUG_ON(cfq_cfqq_on_rr(cfqq)); |
563 | cfq_mark_cfqq_on_rr(cfqq); | 568 | cfq_mark_cfqq_on_rr(cfqq); |
564 | cfqd->busy_queues++; | 569 | cfqd->busy_queues++; |
570 | if (cfq_class_rt(cfqq)) | ||
571 | cfqd->busy_rt_queues++; | ||
565 | 572 | ||
566 | cfq_resort_rr_list(cfqd, cfqq); | 573 | cfq_resort_rr_list(cfqd, cfqq); |
567 | } | 574 | } |
@@ -581,6 +588,8 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
581 | 588 | ||
582 | BUG_ON(!cfqd->busy_queues); | 589 | BUG_ON(!cfqd->busy_queues); |
583 | cfqd->busy_queues--; | 590 | cfqd->busy_queues--; |
591 | if (cfq_class_rt(cfqq)) | ||
592 | cfqd->busy_rt_queues--; | ||
584 | } | 593 | } |
585 | 594 | ||
586 | /* | 595 | /* |
@@ -1005,6 +1014,20 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) | |||
1005 | goto expire; | 1014 | goto expire; |
1006 | 1015 | ||
1007 | /* | 1016 | /* |
1017 | * If we have a RT cfqq waiting, then we pre-empt the current non-rt | ||
1018 | * cfqq. | ||
1019 | */ | ||
1020 | if (!cfq_class_rt(cfqq) && cfqd->busy_rt_queues) { | ||
1021 | /* | ||
1022 | * We simulate this as cfqq timed out so that it gets to bank | ||
1023 | * the remaining of its time slice. | ||
1024 | */ | ||
1025 | cfq_log_cfqq(cfqd, cfqq, "preempt"); | ||
1026 | cfq_slice_expired(cfqd, 1); | ||
1027 | goto new_queue; | ||
1028 | } | ||
1029 | |||
1030 | /* | ||
1008 | * The active queue has requests and isn't expired, allow it to | 1031 | * The active queue has requests and isn't expired, allow it to |
1009 | * dispatch. | 1032 | * dispatch. |
1010 | */ | 1033 | */ |
@@ -1067,6 +1090,13 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1067 | if (RB_EMPTY_ROOT(&cfqq->sort_list)) | 1090 | if (RB_EMPTY_ROOT(&cfqq->sort_list)) |
1068 | break; | 1091 | break; |
1069 | 1092 | ||
1093 | /* | ||
1094 | * If there is a non-empty RT cfqq waiting for current | ||
1095 | * cfqq's timeslice to complete, pre-empt this cfqq | ||
1096 | */ | ||
1097 | if (!cfq_class_rt(cfqq) && cfqd->busy_rt_queues) | ||
1098 | break; | ||
1099 | |||
1070 | } while (dispatched < max_dispatch); | 1100 | } while (dispatched < max_dispatch); |
1071 | 1101 | ||
1072 | /* | 1102 | /* |
@@ -1801,6 +1831,12 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, | |||
1801 | if (rq_is_meta(rq) && !cfqq->meta_pending) | 1831 | if (rq_is_meta(rq) && !cfqq->meta_pending) |
1802 | return 1; | 1832 | return 1; |
1803 | 1833 | ||
1834 | /* | ||
1835 | * Allow an RT request to pre-empt an ongoing non-RT cfqq timeslice. | ||
1836 | */ | ||
1837 | if (cfq_class_rt(new_cfqq) && !cfq_class_rt(cfqq)) | ||
1838 | return 1; | ||
1839 | |||
1804 | if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq)) | 1840 | if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq)) |
1805 | return 0; | 1841 | return 0; |
1806 | 1842 | ||
@@ -1870,7 +1906,8 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1870 | /* | 1906 | /* |
1871 | * not the active queue - expire current slice if it is | 1907 | * not the active queue - expire current slice if it is |
1872 | * idle and has expired it's mean thinktime or this new queue | 1908 | * idle and has expired it's mean thinktime or this new queue |
1873 | * has some old slice time left and is of higher priority | 1909 | * has some old slice time left and is of higher priority or |
1910 | * this new queue is RT and the current one is BE | ||
1874 | */ | 1911 | */ |
1875 | cfq_preempt_queue(cfqd, cfqq); | 1912 | cfq_preempt_queue(cfqd, cfqq); |
1876 | cfq_mark_cfqq_must_dispatch(cfqq); | 1913 | cfq_mark_cfqq_must_dispatch(cfqq); |