Re: File read-ahead and Linux-1.3.85

Gerard Roudier (groudier@iplus.fr)
Tue, 9 Apr 1996 01:01:33 +0000 (GMT)


Matti,

On Mon, 8 Apr 1996, Matti E Aarnio wrote:

> > Linux-1.3.85 also does
> ....
> > - file read-ahead code update
>
> This should have speeded up the system, right ?
> (Such claim was made by the author of that patch..)

I am sure that you did not try my previous patch.
My patch was experimental but worked fine.
Linux patch for asynchronous read-ahead is quite aesthetic but quite bad.

>
> -------Sequential Output-------- ---Sequential Input-- --Random--
> -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
> Machine MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU /sec %CPU
> Lnx1380 100 3221 60.4 2973 19.9 1150 13.9 2300 44.1 2844 12.9 45.9 2.3
> Lnx1384 180 2395 43.4 2714 17.2 1339 16.7 2519 47.2 3253 14.6 69.2 2.9
> Lnx1385 180 2520 44.9 3204 19.8 1258 16.1 2721 56.6 3220 16.0 70.1 3.0
>
> This machine is a 266 MHz Alpha-XL with integrated NCR 53C810, and
> Seagate ST31230N SCSI-disk. At the last two tests the system had
> 128 MB memory, while with the first one there was propably 32 MB memory.
>
> My point, either we are limited by the disk, or perhaps the NCR-driver
> is not as good as it could be... The read-ahead does not help noticeably.
> ...
> > Now, go test it out to see if I broke something else while the above got
> > fixed..
> > Linus
>
> /Matti Aarnio <mea@utu.fi>
>

I have done some tests with 1.3.85 and 1.3.84 patched.
P90/24MB/IBMS12/NCR53C810/BSD driver
(I skipped seekers)

Here are the results of those tests with Bonnie:
------------------------------------------------

Messages "XXXXXX ...." are some statistics printed by the driver about
xfer sizes.

Here is the output I get with 1.3.85 unpatched:
-----------------------------------------------
Writing with putc()...
XXXXXXXXXX - Xfer length min=1024 max=124928 average=96327
done
Rewriting...
XXXXXXXXXX - Xfer length min=1024 max=124928 average=14494
done
Writing intelligently...
XXXXXXXXXX - Xfer length min=1024 max=124928 average=111884
done
Reading with getc()...
XXXXXXXXXX - Xfer length min=1024 max=24576 average=4164
done
Reading intelligently...
XXXXXXXXXX - Xfer length min=1024 max=16384 average=7973
done

Here is the output I get with 1.3.84 patched for asynchronous read-ahead:
-------------------------------------------------------------------------

Writing with putc()...
XXXXXXXXXX - Xfer length min=1024 max=124928 average=95868
done
Rewriting...
XXXXXXXXXX - Xfer length min=1024 max=124928 average=33426
done
Writing intelligently...
XXXXXXXXXX - Xfer length min=1024 max=124928 average=112278
done
Reading with getc()...
XXXXXXXXXX - Xfer length min=1024 max=36864 average=31538
done
Reading intelligently...
XXXXXXXXXX - Xfer length min=1024 max=36864 average=28550
done

-------Sequential Output-------- ---Sequential Input-- --Random--
-Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU
1.3.85 200 3015 89.3 3308 36.8 1256 24.5 2383 87.0 3597 28.3
1.3.84+P 200 3044 90.8 3491 39.0 1549 30.4 2855 88.8 3867 30.0

1.3.85 : linux 1.3.85 with Linus's interpretation of asynchronous read-ahead.
1.3.84+P : linux 1.3.84 with my patch for asynchronous read-ahead.

What is wrong with 1.3.85:
- CPU load for getc() (1k Read)
- Average Xfer length with getc()
- Speed for getc()
- Rewrite
- Average Xfer length for read block (8k)
- Speed for read block

Here is the patch against linux-1.3.84 I used for this test:
------------------------------------------------------------
The previous one gives about the same performances.
I invite you to try one of those patches.

---------------------------------- CUT HERE -------------------------------
--- linux/mm/filemap.c.00 Fri Apr 5 23:00:30 1996
+++ linux/mm/filemap.c Mon Apr 8 20:37:48 1996
@@ -296,10 +296,14 @@
* of the logic when it comes to error handling etc.
*/
#define MAX_READAHEAD (PAGE_SIZE*8)
+#define MIN_READAHEAD (PAGE_SIZE)
int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int error, read;
unsigned long pos, page_cache;
+#ifndef ONLY_SYNCHRONOUS_READ_AHEAD
+ int try_async;
+#endif

if (count <= 0)
return 0;
@@ -308,6 +312,41 @@
page_cache = 0;

pos = filp->f_pos;
+#ifndef ONLY_SYNCHRONOUS_READ_AHEAD
+ /*
+ * Dont beleive f_reada
+ */
+ if (pos <= filp->f_rapos && pos + filp->f_ralen >= filp->f_rapos) {
+ filp->f_reada = 1;
+ }
+ else if (pos+count < MIN_READAHEAD || !filp->f_rapos ||
+ pos > filp->f_rapos) {
+ filp->f_reada = 0;
+ }
+
+ if (filp->f_reada) {
+ try_async = 1;
+ filp->f_ramax += filp->f_ramax;
+ }
+ else {
+ try_async = 0;
+ filp->f_rapos = 0;
+ filp->f_ralen = 0;
+ filp->f_ramax = 0;
+ }
+
+ /*
+ * Compute a good value for read-ahead max
+ */
+ if (filp->f_ramax < count)
+ filp->f_ramax = count & PAGE_MASK;
+
+ if (filp->f_ramax < MIN_READAHEAD)
+ filp->f_ramax = MIN_READAHEAD;
+ else if (filp->f_ramax > MAX_READAHEAD)
+ filp->f_ramax = MAX_READAHEAD;
+#endif
+
for (;;) {
struct page *page;
unsigned long offset, addr, nr;
@@ -350,6 +389,8 @@
if (nr > count)
nr = count;

+#ifdef ONLY_SYNCHRONOUS_READ_AHEAD
+/* SYNCHRONOUS only read-ahead code */
/*
* We may want to do read-ahead.. Do this only
* if we're waiting for the current page to be
@@ -373,6 +414,68 @@
__wait_on_page(page);
}
unlocked_page:
+#else /* ASYNCHRONOUS read-ahead code */
+{
+ unsigned long max_ahead, ahead;
+ unsigned long rapos, ppos;
+
+ ppos = pos & PAGE_MASK;
+
+ /* Do some synchronous read-ahead */
+ if (page->locked) {
+ max_ahead = filp->f_ramax;
+ rapos = ppos;
+ }
+ /* Do some asynchronous read-ahead */
+ else {
+ rapos = filp->f_rapos & PAGE_MASK;
+ if (rapos) rapos -= PAGE_SIZE;
+
+ if (try_async == 1 && pos <= filp->f_rapos &&
+ pos + filp->f_ralen >= filp->f_rapos) {
+ struct page *a_page;
+
+ max_ahead = filp->f_ramax + PAGE_SIZE;
+
+ if (rapos < inode->i_size) {
+ a_page = find_page(inode, rapos);
+ if (a_page) {
+ if (a_page->locked)
+ max_ahead = 0;
+ a_page->count--;
+ }
+ }
+ else
+ max_ahead = 0;
+ try_async = 2;
+ }
+ else {
+ max_ahead = 0;
+ }
+ }
+
+ ahead = 0;
+ while (ahead < max_ahead) {
+ ahead += PAGE_SIZE;
+ page_cache = try_to_read_ahead(inode, rapos + ahead, page_cache);
+ }
+
+ if (ahead > 0) {
+ filp->f_ralen = ahead;
+ /* Force unplug device in order to start asynchronous */
+ if (try_async == 2) {
+ schedule();
+ try_async = 1;
+ }
+ }
+ filp->f_rapos = rapos + ahead + PAGE_SIZE;
+
+ if (page->locked) {
+ __wait_on_page(page);
+ }
+}
+#endif
+
if (!page->uptodate)
goto read_page;
if (nr > inode->i_size - pos)
--- linux/include/linux/fs.h.00 Wed Mar 27 00:50:36 1996
+++ linux/include/linux/fs.h Sat Apr 6 13:32:53 1996
@@ -321,6 +321,12 @@
unsigned short f_flags;
unsigned short f_count;
off_t f_reada;
+
+/* Added for asynchronous read-ahead patch */
+ loff_t f_rapos; /* Last read-ahead position */
+ unsigned long f_ralen; /* Length of previous read-ahead */
+ unsigned long f_ramax; /* Current max read-ahead (futur use) */
+
struct file *f_next, *f_prev;
int f_owner; /* pid or -pgrp where SIGIO should be sent */
struct inode * f_inode;
---------------------------------- CUT HERE -------------------------------

Best Regards, Gerard.