Though for a program like cp, this may qualify as a big diff.  :)

Continuing in my "make IO suck less" phase, cp would be a lot more 
efficient if it didn't bounce the disk heads around so much.  Instead of 
using a tiny 64k buffer, use an amount based on a small fraction of RAM.  

Index: utils.c
===================================================================
RCS file: /home/tedu/cvs/src/bin/cp/utils.c,v
retrieving revision 1.30
diff -u -r1.30 utils.c
--- utils.c     27 Oct 2009 23:59:21 -0000      1.30
+++ utils.c     6 Feb 2010 01:46:42 -0000
@@ -34,6 +34,7 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/time.h>
+#include <sys/sysctl.h>
 
 #include <err.h>
 #include <errno.h>
@@ -46,29 +47,75 @@
 
 #include "extern.h"
 
-int
-copy_file(FTSENT *entp, int dne)
+static void *
+allocbuf(size_t *sizep)
 {
-       static char *buf;
-       static char *zeroes;
-       struct stat to_stat, *fs;
-       int ch, checkch, from_fd, rcount, rval, to_fd, wcount;
-#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
-       char *p;
-#endif
-
-       if (!buf) {
-               buf = malloc(MAXBSIZE);
-               if (!buf)
-                       err(1, "malloc");
+       int mib[2];
+       uint64_t physmem;
+       void *buf;
+       size_t size = 0;
+       size_t oldlen;
+
+       mib[0] = CTL_HW;
+       mib[1] = HW_PHYSMEM64;
+       oldlen = sizeof(physmem);
+       if (sysctl(mib, 2, &physmem, &oldlen, NULL, 0) == 0) {
+               size = physmem / 512;
+               size -= size % MAXBSIZE;
        }
+       if (size < MAXBSIZE)
+               size = MAXBSIZE;
+       buf = malloc(size);
+       if (!buf)
+               err(1, "allocbuf(%ld)", size);
+
+       *sizep = size;
+       return buf;
+}
+
+static ssize_t
+writebuf(int to_fd, void *buf, ssize_t rcount, int skipholes)
+{
+       static void *zeroes;
+       ssize_t wcount = 0;
+       int amt = MAXBSIZE;
+       const char *bp = buf;
+       ssize_t left = rcount;
+
        if (!zeroes) {
-               zeroes = malloc(MAXBSIZE);
+               zeroes = calloc(1, amt);
                if (!zeroes)
-                       err(1, "malloc");
-               memset(zeroes, 0, MAXBSIZE);
+                       err(1, "calloc");
+       }
+       while (left > 0) {
+               amt = MIN(amt, rcount);
+               if (skipholes && memcmp(bp, zeroes, amt) == 0)
+                       wcount = lseek(to_fd, amt, SEEK_CUR) == -1 ? -1 : amt;
+               else
+                       wcount = write(to_fd, bp, amt);
+               if (wcount != amt)
+                       return -1;
+               bp += wcount;
+               left -= wcount;
        }
 
+       return rcount;
+}
+
+int
+copy_file(FTSENT *entp, int dne)
+{
+       static void *buf;
+       static size_t bufsize;
+       struct stat to_stat, *fs;
+       int ch, checkch, from_fd, rval, to_fd;
+       size_t rcount, wcount;
+       int skipholes = 0;
+       struct stat tosb;
+
+       if (!buf)
+               buf = allocbuf(&bufsize);
+
        if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
                warn("%s", entp->fts_path);
                return (1);
@@ -114,54 +161,21 @@
        }
 
        rval = 0;
-
-       /*
-        * Mmap and write if less than 8M (the limit is so we don't totally
-        * trash memory on big files.  This is really a minor hack, but it
-        * wins some CPU back.
-        */
-#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
-       if (fs->st_size <= 8 * 1048576) {
-               if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
-                   MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
-                       warn("mmap: %s", entp->fts_path);
-                       rval = 1;
-               } else {
-                       madvise(p, fs->st_size, MADV_SEQUENTIAL);
-                       if (write(to_fd, p, fs->st_size) != fs->st_size) {
-                               warn("%s", to.p_path);
-                               rval = 1;
-                       }
-                       /* Some systems don't unmap on close(2). */
-                       if (munmap(p, fs->st_size) < 0) {
-                               warn("%s", entp->fts_path);
-                               rval = 1;
-                       }
-               }
-       } else
-#endif
-       {
-               int skipholes = 0;
-               struct stat tosb;
-               if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
-                       skipholes = 1;
-               while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
-                       if (skipholes && memcmp(buf, zeroes, rcount) == 0)
-                               wcount = lseek(to_fd, rcount, SEEK_CUR) == -1 ? 
-1 : rcount;
-                       else
-                               wcount = write(to_fd, buf, rcount);
-                       if (rcount != wcount || wcount == -1) {
-                               warn("%s", to.p_path);
-                               rval = 1;
-                               break;
-                       }
-               }
-               if (skipholes && rcount >= 0)
-                       rcount = ftruncate(to_fd, fs->st_size);
-               if (rcount < 0) {
-                       warn("%s", entp->fts_path);
+       if (!fstat(to_fd, &tosb) && S_ISREG(tosb.st_mode))
+               skipholes = 1;
+       while ((rcount = read(from_fd, buf, bufsize)) > 0) {
+               wcount = writebuf(to_fd, buf, rcount, skipholes);
+               if (rcount != wcount) {
+                       warn("%s", to.p_path);
                        rval = 1;
+                       break;
                }
+       }
+       if (skipholes && rcount >= 0)
+               rcount = ftruncate(to_fd, fs->st_size);
+       if (rcount < 0) {
+               warn("%s", entp->fts_path);
+               rval = 1;
        }
 
        if (rval == 1) {

Reply via email to