Patch from Nick Piggin What I'm trying to do now is predict if the next request will be a read or write. 25-akpm/drivers/block/as-iosched.c | 66 ++++++++++++++++++++++++++----------- 1 files changed, 48 insertions(+), 18 deletions(-) diff -puN drivers/block/as-iosched.c~as-predict-data-direction drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-predict-data-direction Tue Mar 18 18:14:52 2003 +++ 25-akpm/drivers/block/as-iosched.c Tue Mar 18 18:14:52 2003 @@ -40,6 +40,7 @@ struct ant_stats { int queued_request; int dispatched_request; int big_thinktime; + int bad_ddir; int ant_delay_hist[100]; /* milliseconds */ @@ -101,9 +102,14 @@ struct as_io_context { atomic_t nr_dispatched; /* number of requests gone to the drivers */ /* IO History tracking */ + /* Thinktime */ unsigned long last_end_request; unsigned long thinktime[MAX_THINKTIME]; unsigned long mean_thinktime; + /* Read / write pattern */ + int last_data_dir; + unsigned long dir_after_read[2]; + int mean_dir_after_read; }; /* Bits in as_io_context.state */ @@ -759,6 +765,11 @@ static int as_can_break_anticipation(str ant_stats.big_thinktime++; return 1; } + + if (aic && aic->mean_dir_after_read != READ) { + ant_stats.bad_ddir++; + return 1; + } return 0; } @@ -804,7 +815,7 @@ static int as_can_anticipate(struct as_d * updates @aic->mean_thinktime based on that. It is called when a new * request is queued. */ -static void as_update_iohist(struct as_io_context *aic) +static void as_update_iohist(struct as_io_context *aic, int data_dir) { unsigned i; unsigned long thinktime; @@ -815,20 +826,38 @@ static void as_update_iohist(struct as_i return; if (test_bit(AS_TASK_IORUNNING, &aic->state)) { - thinktime = jiffies - aic->last_end_request; - thinktime = min(thinktime, MAX_THINKTIME-1); - aic->thinktime[thinktime] += 256; /* fixed point: 1.0 == 1<<8 */ - - for (i = 0; i < MAX_THINKTIME; i++) { - unsigned long tt = aic->thinktime[i]; - total += i*tt; - num += tt; + if (data_dir == READ) { + /* Calculate read -> read thinktime */ + thinktime = jiffies - aic->last_end_request; + thinktime = min(thinktime, MAX_THINKTIME-1); + /* fixed point: 1.0 == 1<<8 */ + aic->thinktime[thinktime] += 256; + + for (i = 0; i < MAX_THINKTIME; i++) { + unsigned long tt = aic->thinktime[i]; + total += i*tt; + num += tt; + + aic->thinktime[i] = (tt>>1) + (tt>>2); + } + /* fixed point factor is cancelled here */ + if (num) + aic->mean_thinktime = (total+128) / num; + } + + /* Calculate read/write pattern */ + if (aic->last_data_dir == READ) { + aic->dir_after_read[data_dir] += 256; + + if (aic->dir_after_read[READ]*4 >= + aic->dir_after_read[WRITE]*5) + aic->mean_dir_after_read = READ; + else + aic->mean_dir_after_read = WRITE; - aic->thinktime[i] = (tt>>1) + (tt>>2); /* 75% decay */ + aic->dir_after_read[READ] = (aic->dir_after_read[READ]>>1) + (aic->dir_after_read[READ]>>2); + aic->dir_after_read[WRITE] = (aic->dir_after_read[WRITE]>>1) + (aic->dir_after_read[WRITE]>>2);; } - /* fixed point factor is cancelled here */ - if (num) - aic->mean_thinktime = total / num; } } @@ -897,15 +926,17 @@ static void as_update_arq(struct as_data */ static void as_complete_arq(struct as_data *ad, struct as_rq *arq) { - if (!arq->as_io_context) + struct as_io_context *aic = arq->as_io_context; + if (!aic) return; if (rq_data_dir(arq->request) == READ) { set_bit(AS_TASK_IORUNNING, &arq->as_io_context->state); - arq->as_io_context->last_end_request = jiffies; + aic->last_end_request = jiffies; } + aic->last_data_dir = rq_data_dir(arq->request); - if (ad->as_io_context == arq->as_io_context) { + if (ad->as_io_context == aic) { ad->antic_start = jiffies; ad->aic_finished = 1; if (ad->antic_status == ANTIC_WAIT_REQ) { @@ -1221,8 +1252,7 @@ static void as_add_request(struct as_dat if (arq->as_io_context) { atomic_inc(&arq->as_io_context->nr_queued); - if (data_dir == READ) - as_update_iohist(arq->as_io_context); + as_update_iohist(arq->as_io_context, data_dir); } as_add_arq_rb(ad, arq); _