Received: from mnm [127.0.0.1] by localhost with POP3 (fetchmail-5.9.0) for akpm@localhost (single-drop); Mon, 05 May 2003 21:15:59 -0700 (PDT) Received: from digeo-e2k04.digeo.com ([192.168.2.24]) by pao-ex01.pao.digeo.com with Microsoft SMTPSVC(5.0.2195.5329); Mon, 5 May 2003 21:13:32 -0700 Received: from digeo-nav01.digeo.com ([192.168.1.233]) by digeo-e2k04.digeo.com with Microsoft SMTPSVC(5.0.2195.5329); Mon, 5 May 2003 21:13:32 -0700 Received: from packet.digeo.com ([192.168.17.15]) by digeo-nav01.digeo.com (SAVSMTP 3.0.0.44) with SMTP id M2003050521153913486 for ; Mon, 05 May 2003 21:15:39 -0700 Received: from didi (cpe-203-51-35-173.nsw.bigpond.net.au [203.51.35.173]) by packet.digeo.com (8.12.8/8.12.8) with ESMTP id h464DSkR015137 for ; Mon, 5 May 2003 21:13:29 -0700 (PDT) Received: from npiggin by didi with local (Exim 3.36 #1 (Debian)) id 19CtpX-0001Kf-00 for ; Tue, 06 May 2003 14:13:27 +1000 Date: Tue, 6 May 2003 14:13:27 +1000 From: Nick Piggin To: akpm@digeo.com Subject: [PATCH] AS seek distance Message-ID: <20030506041327.GA5017@didi> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="/04w6evG8XlLl3ft" Content-Disposition: inline User-Agent: Mutt/1.5.4i Sender: Nick Piggin X-Scanned-By: MIMEDefang 2.30 (www . roaringpenguin . com / mimedefang) Return-Path: piggin@cyberone.com.au X-OriginalArrivalTime: 06 May 2003 04:13:32.0026 (UTC) FILETIME=[DAE0F5A0:01C31385] X-Spam-Status: No, hits=-6.4 required=6.0 tests=USER_AGENT_MUTT autolearn=ham version=2.53 X-Spam-Level: X-Spam-Checker-Version: SpamAssassin 2.53 (1.174.2.15-2003-03-30-exp) --/04w6evG8XlLl3ft Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi Andrew, This patch monitors each process's seek distance, and will stop anticipation if we get a request closer than we're likely to get from the process we're waiting on. It does alright on tests. Gives OraSim a bit of improvement. It should really be calculating the _time_ each seeks are taking. That is quite difficult though, because we also need to take into account the time it takes to actually transfer the request. I might work on this. The patch also undoes the restriction that only requests from the same process may seek backward. This does not seem to hurt fairness on my tests. It is about trying to close the gap between AS and DL for TCQ. Nick --/04w6evG8XlLl3ft Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=as-seek-2 --- linux/drivers/block/as-iosched.c.orig 2003-05-06 13:29:40.000000000 +1000 +++ linux/drivers/block/as-iosched.c 2003-05-06 13:57:56.000000000 +1000 @@ -88,6 +88,11 @@ struct as_io_context { int last_data_dir; unsigned long dir_after_read[2]; int mean_dir_after_read; + /* Layout pattern */ + sector_t last_request_pos; + sector_t seek_total; + sector_t seek_samples; + sector_t seek_mean; }; /* Bits in as_io_context.state */ @@ -254,6 +259,9 @@ static struct as_io_context *get_as_io_c ret->dir_after_read[READ] = 0; ret->dir_after_read[WRITE] = 0; ret->mean_dir_after_read = READ; + ret->seek_total = 0; + ret->seek_samples = 0; + ret->seek_mean = 0; tsk->as_io_context = ret; } } @@ -455,9 +463,10 @@ as_find_arq_rb(struct as_data *ad, secto * IO Scheduler proper */ -#define MAXBACK (512 * 1024) /* Maximum distance a process can seek backward - from a previous request it has made. No - seeking backward between processes allowed */ +#define MAXBACK (1024 * 1024) /* + * Maximum distance the disk will go backward + * for a request. + */ /* * as_choose_req selects the preferred one of two requests of the same data_dir @@ -487,13 +496,11 @@ as_choose_req(struct as_data *ad, struct /* * Strict one way elevator _except_ in the case where we allow * short backward seeks which are biased as twice the cost of a - * similar forward seek. Only for reads and only between reads - * from the same process! + * similar forward seek. */ if (s1 >= last) d1 = s1 - last; else if (data_dir == READ - && ad->as_io_context == arq1->as_io_context && s1+maxback >= last) d1 = (last - s1)*2; else { @@ -504,7 +511,6 @@ as_choose_req(struct as_data *ad, struct if (s2 >= last) d2 = s2 - last; else if (data_dir == READ - && ad->as_io_context == arq2->as_io_context && s2+maxback >= last) d2 = (last - s2)*2; else { @@ -724,30 +730,46 @@ static int as_can_break_anticipation(str /* request from same process */ return 1; } - if (aic && !test_bit(AS_TASK_RUNNING, &aic->state)) { + + if (!aic) + return 0; + + if (!test_bit(AS_TASK_RUNNING, &aic->state)) { /* process anticipated on has exitted */ return 1; } - if (aic && atomic_read(&aic->nr_queued) > 0) { + if (atomic_read(&aic->nr_queued) > 0) { /* process has more requests queued */ return 1; } - if (aic && atomic_read(&aic->nr_dispatched) > 0) { + if (atomic_read(&aic->nr_dispatched) > 0) { /* process has more requests dispatched */ return 1; } - if (aic && aic->ttime_mean > ad->antic_expire) { + if (aic->ttime_mean > ad->antic_expire) { /* the process thinks too much between requests */ return 1; } - if (aic && aic->mean_dir_after_read != READ) { + if (aic->mean_dir_after_read != READ) { /* next request from this process will probably be a write */ return 1; } + + if (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; + } return 0; } @@ -793,9 +815,11 @@ static int as_can_anticipate(struct as_d * updates @aic->ttime_mean based on that. It is called when a new * request is queued. */ -static void as_update_iohist(struct as_io_context *aic, int data_dir) +static void as_update_iohist(struct as_io_context *aic, struct request *rq) { + int data_dir = rq_data_dir(rq); unsigned long thinktime; + sector_t seek_dist; if (aic == NULL) return; @@ -816,6 +840,24 @@ 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) + / 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 */ @@ -1187,7 +1229,7 @@ static void as_add_request(struct as_dat if (arq->as_io_context) { atomic_inc(&arq->as_io_context->nr_queued); - as_update_iohist(arq->as_io_context, data_dir); + as_update_iohist(arq->as_io_context, arq->request); } as_add_arq_rb(ad, arq); --/04w6evG8XlLl3ft--