aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorrado Zoccolo <czoccolo@gmail.com>2009-11-26 04:02:57 -0500
committerJens Axboe <jens.axboe@oracle.com>2009-11-26 04:02:57 -0500
commite459dd08f45d2aa68abb0c02f8ab045cf8a598b8 (patch)
treee5bba2c95dbbd93d2880fdc81e1ea7589625a6ed
parent75e7b634309ef4eabf8a93d36e58863f727fa209 (diff)
cfq-iosched: fix ncq detection code
CFQ's detection of queueing devices initially assumes a queuing device and detects if the queue depth reaches a certain threshold. However, it will reconsider this choice periodically. Unfortunately, if device is considered not queuing, CFQ will force a unit queue depth for some workloads, thus defeating the detection logic. This leads to poor performance on queuing hardware, since the idle window remains enabled. Given this premise, switching to hw_tag = 0 after we have proved at least once that the device is NCQ capable is not a good choice. The new detection code starts in an indeterminate state, in which CFQ behaves as if hw_tag = 1, and then, if for a long observation period we never saw large depth, we switch to hw_tag = 0, otherwise we stick to hw_tag = 1, without reconsidering it again. Signed-off-by: Corrado Zoccolo <czoccolo@gmail.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--block/cfq-iosched.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index c2ef5d17608c..47abd24617be 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -191,8 +191,14 @@ struct cfq_data {
191 */ 191 */
192 int rq_queued; 192 int rq_queued;
193 int hw_tag; 193 int hw_tag;
194 int hw_tag_samples; 194 /*
195 int rq_in_driver_peak; 195 * hw_tag can be
196 * -1 => indeterminate, (cfq will behave as if NCQ is present, to allow better detection)
197 * 1 => NCQ is present (hw_tag_est_depth is the estimated max depth)
198 * 0 => no NCQ
199 */
200 int hw_tag_est_depth;
201 unsigned int hw_tag_samples;
196 202
197 /* 203 /*
198 * idle window management 204 * idle window management
@@ -2518,8 +2524,11 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
2518{ 2524{
2519 struct cfq_queue *cfqq = cfqd->active_queue; 2525 struct cfq_queue *cfqq = cfqd->active_queue;
2520 2526
2521 if (rq_in_driver(cfqd) > cfqd->rq_in_driver_peak) 2527 if (rq_in_driver(cfqd) > cfqd->hw_tag_est_depth)
2522 cfqd->rq_in_driver_peak = rq_in_driver(cfqd); 2528 cfqd->hw_tag_est_depth = rq_in_driver(cfqd);
2529
2530 if (cfqd->hw_tag == 1)
2531 return;
2523 2532
2524 if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN && 2533 if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN &&
2525 rq_in_driver(cfqd) <= CFQ_HW_QUEUE_MIN) 2534 rq_in_driver(cfqd) <= CFQ_HW_QUEUE_MIN)
@@ -2538,13 +2547,10 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd)
2538 if (cfqd->hw_tag_samples++ < 50) 2547 if (cfqd->hw_tag_samples++ < 50)
2539 return; 2548 return;
2540 2549
2541 if (cfqd->rq_in_driver_peak >= CFQ_HW_QUEUE_MIN) 2550 if (cfqd->hw_tag_est_depth >= CFQ_HW_QUEUE_MIN)
2542 cfqd->hw_tag = 1; 2551 cfqd->hw_tag = 1;
2543 else 2552 else
2544 cfqd->hw_tag = 0; 2553 cfqd->hw_tag = 0;
2545
2546 cfqd->hw_tag_samples = 0;
2547 cfqd->rq_in_driver_peak = 0;
2548} 2554}
2549 2555
2550static void cfq_completed_request(struct request_queue *q, struct request *rq) 2556static void cfq_completed_request(struct request_queue *q, struct request *rq)
@@ -2951,7 +2957,7 @@ static void *cfq_init_queue(struct request_queue *q)
2951 cfqd->cfq_slice_async_rq = cfq_slice_async_rq; 2957 cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
2952 cfqd->cfq_slice_idle = cfq_slice_idle; 2958 cfqd->cfq_slice_idle = cfq_slice_idle;
2953 cfqd->cfq_latency = 1; 2959 cfqd->cfq_latency = 1;
2954 cfqd->hw_tag = 1; 2960 cfqd->hw_tag = -1;
2955 cfqd->last_end_sync_rq = jiffies; 2961 cfqd->last_end_sync_rq = jiffies;
2956 return cfqd; 2962 return cfqd;
2957} 2963}