Patch from Nick Piggin <piggin@cyberone.com.au>

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);

_