Commit 82c8a4cc authored by Jens Axboe's avatar Jens Axboe Committed by Ingo Molnar

[PATCH] deadline ioscheduler cleanups

Some various small cleanups, optimizations, and fixes.

o Make fifo_batch=32 as default, from testing this appears a good
  default value. We still get good throughput, and latency is good.

o Reintroduce the merge_cleanup logic. We need it for deadline for
  rehashing requests when they have been merged.

o Cleanup last_merge logic. Move it to the new elv_merged_request(),
  this is where it really belongs. Doing it inside the io scheduler core
  can causes false positives, when the queue merge functions reject an
  otherwise good merge

o Have deadline_move_requests() account from last entry on the dispatch
  queue, if it is non-empty. It doesn't really matter what the last
  extracted sector was, if we are not right behind it.

o Clean/optimize deadline_move_requests()

o Account size of a request just a little bit. Streaming transfer isn't
  for free, it's just a lot cheaper than a seek.

o Make deadline_check_fifo() more readable.
parent 9b34eb70
......@@ -25,7 +25,7 @@
* front fifo request expires.
*/
static int read_expire = HZ / 2; /* 500ms start timeout */
static int fifo_batch = 64; /* 4 seeks, or 64 contig */
static int fifo_batch = 32; /* 4 seeks, or 64 contig */
static int seek_cost = 16; /* seek is 16 times more expensive */
/*
......@@ -162,9 +162,8 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
if (elv_rq_merge_ok(__rq, bio)) {
*req = __rq;
q->last_merge = &__rq->queuelist;
ret = ELEVATOR_BACK_MERGE;
goto out_ret;
goto out;
}
}
......@@ -191,23 +190,26 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
ret = elv_try_merge(__rq, bio);
if (ret != ELEVATOR_NO_MERGE) {
*req = __rq;
q->last_merge = &__rq->queuelist;
break;
}
}
}
out:
if (ret != ELEVATOR_NO_MERGE) {
struct deadline_rq *drq = RQ_DATA(*req);
deadline_del_rq_hash(drq);
deadline_add_rq_hash(dd, drq);
}
out_ret:
return ret;
}
static void deadline_merged_request(request_queue_t *q, struct request *req)
{
struct deadline_data *dd = q->elevator.elevator_data;
struct deadline_rq *drq = RQ_DATA(req);
deadline_del_rq_hash(drq);
deadline_add_rq_hash(dd, drq);
q->last_merge = &req->queuelist;
}
static void
deadline_merge_request(request_queue_t *q, struct request *req, struct request *next)
{
......@@ -255,8 +257,18 @@ static void deadline_move_requests(struct deadline_data *dd, struct request *rq)
sector_t last_sec = dd->last_sector;
int batch_count = dd->fifo_batch;
/*
* if dispatch is non-empty, disregard last_sector and check last one
*/
if (!list_empty(dd->dispatch)) {
struct request *__rq = list_entry_rq(dd->dispatch->prev);
last_sec = __rq->sector + __rq->nr_sectors;
}
do {
struct list_head *nxt = rq->queuelist.next;
int this_rq_cost;
/*
* take it off the sort and fifo list, move
......@@ -264,17 +276,23 @@ static void deadline_move_requests(struct deadline_data *dd, struct request *rq)
*/
deadline_move_to_dispatch(dd, rq);
/*
* if this is the last entry, don't bother doing accounting
*/
if (nxt == sort_head)
break;
this_rq_cost = dd->seek_cost;
if (rq->sector == last_sec)
batch_count--;
else
batch_count -= dd->seek_cost;
this_rq_cost = (rq->nr_sectors + 255) >> 8;
if (nxt == sort_head)
batch_count -= this_rq_cost;
if (batch_count <= 0)
break;
last_sec = rq->sector + rq->nr_sectors;
rq = list_entry_rq(nxt);
} while (batch_count > 0);
} while (1);
}
/*
......@@ -283,16 +301,17 @@ static void deadline_move_requests(struct deadline_data *dd, struct request *rq)
#define list_entry_fifo(ptr) list_entry((ptr), struct deadline_rq, fifo)
static inline int deadline_check_fifo(struct deadline_data *dd)
{
struct deadline_rq *drq;
if (!list_empty(&dd->read_fifo)) {
struct deadline_rq *drq = list_entry_fifo(dd->read_fifo.next);
if (list_empty(&dd->read_fifo))
return 0;
drq = list_entry_fifo(dd->read_fifo.next);
if (time_before(jiffies, drq->expires))
return 0;
/*
* drq is expired!
*/
if (time_after(jiffies, drq->expires))
return 1;
}
return 1;
return 0;
}
static struct request *deadline_next_request(request_queue_t *q)
......@@ -411,8 +430,9 @@ static int deadline_queue_empty(request_queue_t *q)
{
struct deadline_data *dd = q->elevator.elevator_data;
if (!list_empty(&q->queue_head) || !list_empty(&dd->sort_list[READ])
|| !list_empty(&dd->sort_list[WRITE]))
if (!list_empty(&dd->sort_list[WRITE]) ||
!list_empty(&dd->sort_list[READ]) ||
!list_empty(&q->queue_head))
return 0;
BUG_ON(!list_empty(&dd->read_fifo));
......@@ -544,6 +564,7 @@ module_init(deadline_slab_setup);
elevator_t iosched_deadline = {
.elevator_merge_fn = deadline_merge,
.elevator_merged_fn = deadline_merged_request,
.elevator_merge_req_fn = deadline_merge_request,
.elevator_next_req_fn = deadline_next_request,
.elevator_add_req_fn = deadline_add_request,
......
......@@ -250,6 +250,14 @@ int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio)
return ELEVATOR_NO_MERGE;
}
void elv_merged_request(request_queue_t *q, struct request *rq)
{
elevator_t *e = &q->elevator;
if (e->elevator_merged_fn)
e->elevator_merged_fn(q, rq);
}
void elv_merge_requests(request_queue_t *q, struct request *rq,
struct request *next)
{
......
......@@ -1606,6 +1606,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
req->biotail = bio;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
drive_stat_acct(req, nr_sectors, 0);
elv_merged_request(q, req);
attempt_back_merge(q, req);
goto out;
......@@ -1629,6 +1630,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
req->sector = req->hard_sector = sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
drive_stat_acct(req, nr_sectors, 0);
elv_merged_request(q, req);
attempt_front_merge(q, req);
goto out;
......
......@@ -6,6 +6,8 @@ typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
typedef void (elevator_merged_fn) (request_queue_t *, struct request *);
typedef struct request *(elevator_next_req_fn) (request_queue_t *);
typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *);
......@@ -19,6 +21,7 @@ typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
struct elevator_s
{
elevator_merge_fn *elevator_merge_fn;
elevator_merged_fn *elevator_merged_fn;
elevator_merge_req_fn *elevator_merge_req_fn;
elevator_next_req_fn *elevator_next_req_fn;
......@@ -42,6 +45,7 @@ extern void __elv_add_request(request_queue_t *, struct request *,
extern int elv_merge(request_queue_t *, struct request **, struct bio *);
extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *);
extern void elv_merged_request(request_queue_t *, struct request *);
extern void elv_remove_request(request_queue_t *, struct request *);
extern int elv_queue_empty(request_queue_t *);
extern inline struct list_head *elv_get_sort_head(request_queue_t *, struct request *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment