From: Nick Piggin This patch improves single threaded pgbench performance from about 40 to 65 TPS. It also does a few minor tweaks here and there. Performance for all my tests is as good or better with this patch. tiobench 256 seq read performance is still bad, though not due to this patch. I am fairly sure that the problem is due to that seek distance patch. The seek distance patch also allowed any readers to seek backwards, not just the process who had last made a read. This patch nearly tripled WimMark performance, but probably does 3 times worse in tiobench 256 sequential reads. tiobench 16 seq reads also aren't as good as they should be. drivers/block/as-iosched.c | 110 ++++++++++++++++++++++----------------------- 1 files changed, 55 insertions(+), 55 deletions(-) diff -puN drivers/block/as-iosched.c~as-proc-read-write drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-proc-read-write 2003-05-22 21:36:59.000000000 -0700 +++ 25-akpm/drivers/block/as-iosched.c 2003-05-22 21:36:59.000000000 -0700 @@ -514,9 +514,8 @@ as_choose_req(struct as_data *ad, struct */ if (s1 >= last) d1 = s1 - last; - else if (data_dir == READ - && s1+maxback >= last) - d1 = (last - s1)*2; + else if (s1+maxback >= last) + d1 = (last - s1)*2; else { r1_wrap = 1; d1 = 0; /* shut up, gcc */ @@ -524,9 +523,8 @@ as_choose_req(struct as_data *ad, struct if (s2 >= last) d2 = s2 - last; - else if (data_dir == READ - && s2+maxback >= last) - d2 = (last - s2)*2; + else if (s2+maxback >= last) + d2 = (last - s2)*2; else { r2_wrap = 1; d2 = 0; @@ -560,7 +558,7 @@ as_choose_req(struct as_data *ad, struct /* * as_find_next_arq finds the next request after @prev in elevator order. - * this with as_choose_arq form the basis for how the scheduler chooses + * this with as_choose_req form the basis for how the scheduler chooses * what request to process next. Anticipation works on top of this. */ static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *last) @@ -706,7 +704,7 @@ static int as_close_req(struct as_data * else return 1; - return (last <= next) && (next <= last + delta); + return (last - delta <= next) && (next <= last + delta); } /* @@ -726,7 +724,7 @@ static int as_can_break_anticipation(str { struct as_io_context *aic; - if (rq_data_dir(arq->request) == READ && as_close_req(ad, arq)) { + if (arq && rq_data_dir(arq->request) == READ && as_close_req(ad, arq)) { /* close request */ return 1; } @@ -740,7 +738,7 @@ static int as_can_break_anticipation(str } aic = ad->as_io_context; - if (aic == arq->as_io_context) { + if (arq && aic == arq->as_io_context) { /* request from same process */ return 1; } @@ -773,13 +771,12 @@ static int as_can_break_anticipation(str return 1; } - if (aic->seek_samples) { + if (arq && aic->seek_samples) { sector_t s; if (ad->last_sector[READ] < arq->request->sector) s = arq->request->sector - ad->last_sector[READ]; else s = ad->last_sector[READ] - arq->request->sector; - if (aic->seek_mean > s) /* this request is better than what we're expecting */ return 1; @@ -806,7 +803,7 @@ static int as_can_anticipate(struct as_d */ return 0; - if (arq && as_can_break_anticipation(ad, arq)) + if (as_can_break_anticipation(ad, arq)) /* * This request is a good candidate. Don't keep anticipating, * run it. @@ -838,8 +835,8 @@ static void as_update_iohist(struct as_i if (aic == NULL) return; - if (test_bit(AS_TASK_IORUNNING, &aic->state)) { - if (data_dir == READ) { + if (data_dir == READ) { + if (test_bit(AS_TASK_IORUNNING, &aic->state)) { /* Calculate read -> read thinktime */ thinktime = jiffies - aic->last_end_request; thinktime = min(thinktime, MAX_THINKTIME-1); @@ -854,43 +851,46 @@ static void as_update_iohist(struct as_i + (aic->ttime_samples>>2); aic->ttime_total = (aic->ttime_total>>1) + (aic->ttime_total>>2); - - /* Calculate read -> read seek distance */ - if (aic->last_request_pos < rq->sector) - seek_dist = rq->sector - aic->last_request_pos; - else - seek_dist = aic->last_request_pos - rq->sector; - aic->last_request_pos = rq->sector + rq->nr_sectors; - - aic->seek_samples += 256; - aic->seek_total += 256*seek_dist; - if (aic->seek_samples) { - aic->seek_mean = aic->seek_total + 128; - do_div(aic->seek_mean, aic->seek_samples); - } - aic->seek_samples = (aic->seek_samples>>1) - + (aic->seek_samples>>2); - aic->seek_total = (aic->seek_total>>1) - + (aic->seek_total>>2); - } - /* Calculate read/write pattern */ - if (aic->last_data_dir == READ) { - unsigned long rprob, wprob; - aic->dir_after_read[data_dir] += 256; - rprob = aic->dir_after_read[READ]; - wprob = aic->dir_after_read[WRITE]; - - if (rprob*4 >= wprob*5) - aic->mean_dir_after_read = READ; - else - aic->mean_dir_after_read = WRITE; + /* Calculate read -> read seek distance */ + if (aic->last_request_pos < rq->sector) + seek_dist = rq->sector - aic->last_request_pos; + else + seek_dist = aic->last_request_pos - rq->sector; + aic->last_request_pos = rq->sector + rq->nr_sectors; + + if (!aic->seek_samples) + seek_dist = 0; - aic->dir_after_read[READ] = (rprob>>1) + (rprob>>2); - aic->dir_after_read[WRITE] = (wprob>>1) + (wprob>>2);; + aic->seek_samples += 256; + aic->seek_total += 256*seek_dist; + if (aic->seek_samples) { + aic->seek_mean = aic->seek_total + 128; + do_div(aic->seek_mean, aic->seek_samples); } + aic->seek_samples = (aic->seek_samples>>1) + + (aic->seek_samples>>2); + aic->seek_total = (aic->seek_total>>1) + + (aic->seek_total>>2); + } + + /* Calculate read/write pattern */ + if (aic->last_data_dir == READ) { + unsigned long rprob, wprob; + aic->dir_after_read[data_dir] += 256; + rprob = aic->dir_after_read[READ]; + wprob = aic->dir_after_read[WRITE]; + + if (rprob*4 >= wprob*5) + aic->mean_dir_after_read = READ; + else + aic->mean_dir_after_read = WRITE; + + aic->dir_after_read[READ] = (rprob>>1) + (rprob>>2); + aic->dir_after_read[WRITE] = (wprob>>1) + (wprob>>2); } + aic->last_data_dir = data_dir; } /* @@ -910,10 +910,11 @@ static void as_update_arq(struct as_data * or does it come from the same process as the one we are anticipating * for? */ - if (ad->batch_data_dir == READ - && ad->antic_status != ANTIC_FINISHED - && as_can_break_anticipation(ad, arq)) - as_antic_stop(ad); + if (ad->antic_status == ANTIC_WAIT_REQ + || ad->antic_status == ANTIC_WAIT_NEXT) { + if (as_can_break_anticipation(ad, arq)) + as_antic_stop(ad); + } } /* @@ -940,7 +941,6 @@ static void as_completed_request(request set_bit(AS_TASK_IORUNNING, &aic->state); aic->last_end_request = jiffies; } - aic->last_data_dir = rq_data_dir(arq->request); if (ad->as_io_context == aic) { ad->antic_start = jiffies; @@ -1268,8 +1268,8 @@ as_insert_request(request_queue_t *q, st list_add_tail(&rq->queuelist, ad->dispatch); /* Stop anticipating - let this request get through */ - if (!list_empty(ad->dispatch) && rq_data_dir(rq) == READ - && (ad->antic_status == ANTIC_WAIT_REQ + if (!list_empty(ad->dispatch) + && (ad->antic_status == ANTIC_WAIT_REQ || ad->antic_status == ANTIC_WAIT_NEXT)) as_antic_stop(ad); @@ -1283,7 +1283,7 @@ as_insert_request(request_queue_t *q, st list_add(&rq->queuelist, insert_here); /* Stop anticipating - let this request get through */ - if (!list_empty(ad->dispatch) && rq_data_dir(rq) == READ + if (!list_empty(ad->dispatch) && (ad->antic_status == ANTIC_WAIT_REQ || ad->antic_status == ANTIC_WAIT_NEXT)) as_antic_stop(ad); _