Date: Fri, 5 Apr 1996 03:44:34 -0800 (PST) From: asami@cs.berkeley.edu (Satoshi Asami) To: davidg@root.com Cc: current@freebsd.org, nisha@cs.berkeley.edu, tege@matematik.su.se, dyson@freebsd.org, hasty@rah.star-gate.com Subject: Re: fast memory copy for large data sizes Message-ID: <199604051144.DAA24903@silvia.HIP.Berkeley.EDU> In-Reply-To: <199604051021.CAA00222@Root.COM> (message from David Greenman on Fri, 05 Apr 1996 02:21:48 -0800)
next in thread | previous in thread | raw e-mail | index | archive | help
By the way, if someone wants to try putting it into the kernel, here
is a patch to support.s. Change the two "cmpl $1024" lines if you
want to change the cutoff.
We've been running this on our -current system here for a couple of
days, it seems to be working fine. As I said, it pushed up the
maximum read bandwidth (through the filesystem) for our disk array
from 21MB/s to 23MB/s. (I didn't see much speed difference (only
about 100KB/s) for single disks though, the bottleneck is probably not
here in this case.)
I also wrote a small program to just issue multiple reads to the same
region of a file, and I got 37MB/s for the stock kernel and 49MB/s for
the modified version on the 133MHz Pentium (which is about the same as
what I got from the user-level code).
Here's the testing program. Sorry I didn't have time to clean it up,
it's kinda messy. But all you need to see is the loop that has
memcpy() and lseek() (no, the memcpy() is not called by default).
===
/* rawread.c: repeatedly read from same block over and over */
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <ufs/ffs/fs.h>
/* some constants */
#define True (1)
#define False (0)
#define Ok (0)
#define Error (1)
/* start of onfigurable parameters */
/* default buffer size */
#define BlockSize 8192
/* default size of file */
#define TotalSize 67108864
int removefile = True ;
int verbose = False ;
int writeonly = False ;
int randomize = False ;
int readonly = False ;
/* end of configurable parameters */
/* default name of temporary file */
#define TmpFile "disktest.tmp"
/* default line length */
#define LineLen 1024
char *myname ;
void *xmalloc(size_t size) ;
void usage(int retval) ;
void error(char *msg) ;
void remfile(void) ;
void flushoutput(void) ;
void cuechild(void) ;
int main(int argc, char **argv)
{
int i ;
char *filename ;
int blocksize = BlockSize ;
int totalsize = TotalSize ;
int iterations ;
void *buffer, *buffer2 ;
int fd ;
int count ;
struct timeval tv_start, tv_end ;
double elapsed ;
int docopy = False ;
myname = argv[0] ;
filename = argv[argc-1] ;
if (argc < 2) usage(Error) ;
for (i = 1 ; i < argc-1 ; i++) {
if (argv[i][0] == '-') { /* option */
if (!strcmp(argv[i], "-b")) {
if (i+1 == argc)
usage(Error) ;
blocksize = atoi(argv[i+1]) ;
if (blocksize <= 0)
usage(Error) ;
i++ ;
}
else if (!strcmp(argv[i], "-s")) {
if (i+1 == argc)
usage(Error) ;
totalsize = atoi(argv[i+1]) ;
if (totalsize <= 0)
usage(Error) ;
i++ ;
}
else if (!strcmp(argv[i], "-c"))
docopy = True ;
else if (!strcmp(argv[i], "-h"))
usage(Ok) ;
else
usage(Error) ;
}
else
usage(Error) ;
}
iterations = totalsize / blocksize ;
if (filename[0] == '-')
usage(Error);
buffer = xmalloc(blocksize) ;
if (docopy)
buffer2 = xmalloc(blocksize) ;
if ((fd = open(filename, O_RDONLY, 0)) < 0) {
fprintf(stderr, "file: %s\n", filename) ;
error("open") ;
}
gettimeofday(&tv_start, NULL) ;
for (count = 0 ; count < iterations ; count++) {
if (read(fd, buffer, blocksize) != blocksize)
error("read") ;
if (docopy)
memcpy(buffer2, buffer, blocksize) ;
lseek(fd, 0, SEEK_SET) ;
}
gettimeofday(&tv_end, NULL) ;
elapsed = tv_end.tv_sec-tv_start.tv_sec
+ ((double) tv_end.tv_usec-tv_start.tv_usec)/1000000 ;
if (verbose)
printf("%d reads of %d bytes in %f seconds\n",
count, blocksize, elapsed) ;
printf("%d bytes transferred in %d secs (%d bytes/sec) from \"%s\"\n",
totalsize, (int) elapsed, (int) (totalsize/elapsed), filename) ;
fflush(stdout) ;
close(fd) ;
return Ok ;
}
void usage(int retval)
{
fprintf(stderr, "usage: %s [-b bufsize] [-s size] [-c] filename\n",
myname) ;
exit(retval) ;
}
void *xmalloc(size_t size)
{
void *vp ;
if ((vp = malloc(size)) == NULL) {
fprintf(stderr, "panic: memory exausted with request size %d\n", size) ;
exit(Error) ;
}
return vp ;
}
void error(char *msg)
{
perror(msg) ;
exit(Error) ;
}
===
Use it as:
dd if=/dev/zero of=foo bs=1024 count=1024
rawread -b 1048576 -s 104857600 foo
The number after -b is the read request size and the one after -s is
the total size (it will repeat it 100 times in the above case).
Note that for small -b sizes, the copy will always be done within the
cache, so the resulting number may not reflect the real world
performance.
Here's the patch:
===
Index: support.s
===================================================================
RCS file: /usr/cvs/src/sys/i386/i386/support.s,v
retrieving revision 1.31
diff -u -r1.31 support.s
--- support.s 1995/12/28 23:14:40 1.31
+++ support.s 1996/04/04 06:27:15
@@ -463,6 +463,14 @@
/* bcopy(%esi, %edi, %ebx) */
3:
movl %ebx,%ecx
+ cmpl $1024,%ecx
+ jbe slow_copyout
+
+ call fastmove
+ jmp done_copyout
+
+ ALIGN_TEXT
+slow_copyout:
shrl $2,%ecx
cld
rep
@@ -510,6 +518,14 @@
cmpl $VM_MAXUSER_ADDRESS,%edx
ja copyin_fault
+ cmpl $1024,%ecx
+ jbe slow_copyin
+
+ call fastmove
+ jmp done_copyin
+
+ ALIGN_TEXT
+slow_copyin:
movb %cl,%al
shrl $2,%ecx /* copy longword-wise */
cld
@@ -520,6 +536,8 @@
rep
movsb
+ ALIGN_TEXT
+done_copyin:
popl %edi
popl %esi
xorl %eax,%eax
@@ -534,6 +552,70 @@
movl _curpcb,%edx
movl $0,PCB_ONFAULT(%edx)
movl $EFAULT,%eax
+ ret
+
+/* fastmove(src, dst, len)
+ src in %esi
+ dst in %edi
+ len in %ecx
+ uses %eax and %edx for tmp. storage
+ */
+ ALIGN_TEXT
+fastmove:
+ movl %cr0,%edx
+ movl $8, %eax /* CR0_TS */
+ not %eax
+ andl %eax,%edx /* clear CR0_TS */
+ movl %edx,%cr0
+
+ cmpl $63,%ecx
+ jbe L57
+
+ subl $108,%esp
+ fsave (%esp)
+
+ ALIGN_TEXT
+L58:
+ fildq 0(%esi)
+ fildq 8(%esi)
+ fildq 16(%esi)
+ fildq 24(%esi)
+ fildq 32(%esi)
+ fildq 40(%esi)
+ fildq 48(%esi)
+ fildq 56(%esi)
+ fxch %st(7)
+ fistpq 0(%edi)
+ fxch %st(5)
+ fistpq 8(%edi)
+ fxch %st(3)
+ fistpq 16(%edi)
+ fxch %st(1)
+ fistpq 24(%edi)
+ fistpq 32(%edi)
+ fistpq 40(%edi)
+ fistpq 48(%edi)
+ fistpq 56(%edi)
+ addl $-64,%ecx
+ addl $64,%esi
+ addl $64,%edi
+ cmpl $63,%ecx
+ ja L58
+
+ frstor (%esp)
+ addl $108,%esp
+
+ ALIGN_TEXT
+L57:
+ cld
+ rep
+ movsb
+
+ andl $8,%edx
+ movl %cr0,%eax
+ orl %edx, %eax /* reset CR0_TS to the original value */
+ movl %eax,%cr0
+
ret
/*
===
Enjoy,
Satoshi
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199604051144.DAA24903>
