aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2006-07-28 03:48:51 -0400
committerJens Axboe <axboe@nelson.home.kernel.dk>2006-09-30 14:29:39 -0400
commit53b03744e5699832e6c5b04f2ec506d8b0c50c38 (patch)
tree7205d972bf6f25be3a3f2c360130b269dadcb3b2
parentb5deef901282628d88c784f4c9d2f0583ec3b355 (diff)
[PATCH] cfq-iosched: Kill O(N) runtime of cfq_resort_rr_list()
Currently it scales with number of processes in that priority group, which is potentially not very nice as it's called quite often. Basically we always need to do tail inserts, except for the case of a new process. So just mark/detect a queue as such. Signed-off-by: Jens Axboe <axboe@suse.de>
-rw-r--r--block/cfq-iosched.c53
1 files changed, 22 insertions, 31 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 0452108a932e..c6e649f3cae7 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -152,7 +152,6 @@ struct cfq_queue {
152 unsigned long slice_start; 152 unsigned long slice_start;
153 unsigned long slice_end; 153 unsigned long slice_end;
154 unsigned long slice_left; 154 unsigned long slice_left;
155 unsigned long service_last;
156 155
157 /* number of requests that are on the dispatch list */ 156 /* number of requests that are on the dispatch list */
158 int on_dispatch[2]; 157 int on_dispatch[2];
@@ -174,6 +173,7 @@ enum cfqq_state_flags {
174 CFQ_CFQQ_FLAG_fifo_expire, 173 CFQ_CFQQ_FLAG_fifo_expire,
175 CFQ_CFQQ_FLAG_idle_window, 174 CFQ_CFQQ_FLAG_idle_window,
176 CFQ_CFQQ_FLAG_prio_changed, 175 CFQ_CFQQ_FLAG_prio_changed,
176 CFQ_CFQQ_FLAG_queue_new,
177}; 177};
178 178
179#define CFQ_CFQQ_FNS(name) \ 179#define CFQ_CFQQ_FNS(name) \
@@ -198,6 +198,7 @@ CFQ_CFQQ_FNS(must_dispatch);
198CFQ_CFQQ_FNS(fifo_expire); 198CFQ_CFQQ_FNS(fifo_expire);
199CFQ_CFQQ_FNS(idle_window); 199CFQ_CFQQ_FNS(idle_window);
200CFQ_CFQQ_FNS(prio_changed); 200CFQ_CFQQ_FNS(prio_changed);
201CFQ_CFQQ_FNS(queue_new);
201#undef CFQ_CFQQ_FNS 202#undef CFQ_CFQQ_FNS
202 203
203static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); 204static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
@@ -350,7 +351,7 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
350static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) 351static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
351{ 352{
352 struct cfq_data *cfqd = cfqq->cfqd; 353 struct cfq_data *cfqd = cfqq->cfqd;
353 struct list_head *list, *entry; 354 struct list_head *list;
354 355
355 BUG_ON(!cfq_cfqq_on_rr(cfqq)); 356 BUG_ON(!cfq_cfqq_on_rr(cfqq));
356 357
@@ -375,31 +376,26 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
375 } 376 }
376 377
377 /* 378 /*
378 * if queue was preempted, just add to front to be fair. busy_rr 379 * If this queue was preempted or is new (never been serviced), let
379 * isn't sorted, but insert at the back for fairness. 380 * it be added first for fairness but beind other new queues.
381 * Otherwise, just add to the back of the list.
380 */ 382 */
381 if (preempted || list == &cfqd->busy_rr) { 383 if (preempted || cfq_cfqq_queue_new(cfqq)) {
382 if (preempted) 384 struct list_head *n = list;
383 list = list->prev; 385 struct cfq_queue *__cfqq;
384 386
385 list_add_tail(&cfqq->cfq_list, list); 387 while (n->next != list) {
386 return; 388 __cfqq = list_entry_cfqq(n->next);
387 } 389 if (!cfq_cfqq_queue_new(__cfqq))
390 break;
388 391
389 /* 392 n = n->next;
390 * sort by when queue was last serviced 393 }
391 */
392 entry = list;
393 while ((entry = entry->prev) != list) {
394 struct cfq_queue *__cfqq = list_entry_cfqq(entry);
395 394
396 if (!__cfqq->service_last) 395 list = n;
397 break;
398 if (time_before(__cfqq->service_last, cfqq->service_last))
399 break;
400 } 396 }
401 397
402 list_add(&cfqq->cfq_list, entry); 398 list_add_tail(&cfqq->cfq_list, list);
403} 399}
404 400
405/* 401/*
@@ -591,13 +587,12 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
591 if (cfq_cfqq_wait_request(cfqq)) 587 if (cfq_cfqq_wait_request(cfqq))
592 del_timer(&cfqd->idle_slice_timer); 588 del_timer(&cfqd->idle_slice_timer);
593 589
594 if (!preempted && !cfq_cfqq_dispatched(cfqq)) { 590 if (!preempted && !cfq_cfqq_dispatched(cfqq))
595 cfqq->service_last = now;
596 cfq_schedule_dispatch(cfqd); 591 cfq_schedule_dispatch(cfqd);
597 }
598 592
599 cfq_clear_cfqq_must_dispatch(cfqq); 593 cfq_clear_cfqq_must_dispatch(cfqq);
600 cfq_clear_cfqq_wait_request(cfqq); 594 cfq_clear_cfqq_wait_request(cfqq);
595 cfq_clear_cfqq_queue_new(cfqq);
601 596
602 /* 597 /*
603 * store what was left of this slice, if the queue idled out 598 * store what was left of this slice, if the queue idled out
@@ -1297,13 +1292,13 @@ retry:
1297 hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]); 1292 hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
1298 atomic_set(&cfqq->ref, 0); 1293 atomic_set(&cfqq->ref, 0);
1299 cfqq->cfqd = cfqd; 1294 cfqq->cfqd = cfqd;
1300 cfqq->service_last = 0;
1301 /* 1295 /*
1302 * set ->slice_left to allow preemption for a new process 1296 * set ->slice_left to allow preemption for a new process
1303 */ 1297 */
1304 cfqq->slice_left = 2 * cfqd->cfq_slice_idle; 1298 cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
1305 cfq_mark_cfqq_idle_window(cfqq); 1299 cfq_mark_cfqq_idle_window(cfqq);
1306 cfq_mark_cfqq_prio_changed(cfqq); 1300 cfq_mark_cfqq_prio_changed(cfqq);
1301 cfq_mark_cfqq_queue_new(cfqq);
1307 cfq_init_prio_data(cfqq); 1302 cfq_init_prio_data(cfqq);
1308 } 1303 }
1309 1304
@@ -1672,12 +1667,8 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
1672 if (!cfq_class_idle(cfqq)) 1667 if (!cfq_class_idle(cfqq))
1673 cfqd->last_end_request = now; 1668 cfqd->last_end_request = now;
1674 1669
1675 if (!cfq_cfqq_dispatched(cfqq)) { 1670 if (!cfq_cfqq_dispatched(cfqq) && cfq_cfqq_on_rr(cfqq))
1676 if (cfq_cfqq_on_rr(cfqq)) { 1671 cfq_resort_rr_list(cfqq, 0);
1677 cfqq->service_last = now;
1678 cfq_resort_rr_list(cfqq, 0);
1679 }
1680 }
1681 1672
1682 if (sync) 1673 if (sync)
1683 RQ_CIC(rq)->last_end_request = now; 1674 RQ_CIC(rq)->last_end_request = now;