diff options
author | ivoras <ivoras@FreeBSD.org> | 2008-10-30 14:05:57 +0000 |
---|---|---|
committer | ivoras <ivoras@FreeBSD.org> | 2008-10-30 14:05:57 +0000 |
commit | 1f332d86bf5e4cfc63df682d8859c4f4fac21026 (patch) | |
tree | 346118ee48560d0625d63c6017022305731d9dd9 /bin | |
parent | fbca48f8d5b2e879565c548e81b7c3da7d1b36dc (diff) | |
download | FreeBSD-src-1f332d86bf5e4cfc63df682d8859c4f4fac21026.zip FreeBSD-src-1f332d86bf5e4cfc63df682d8859c4f4fac21026.tar.gz |
Teach cat(1) and cp(1) to use a larger buffer if enough memory is present
in the system. A simple heuristics is used to detect what is "enough"
memory: if number of physmem pages is greater than 32k (equalling 128 MB
on machines with 4 kB pages).
Typical immediate result of these changes is reduction in context switches
and the goal is to increase efficiency by using large buffers:
before: /usr/bin/time -hlp cat file1 > file2
...
163 voluntary context switches
11194 involuntary context switches
after: /usr/bin/time -hlp ./cat file1 > file2
...
417 voluntary context switches
272 involuntary context switches
Reviewed by: hackers@ (no objections to earlier version of cat patch)
Approved by: gnn (mentor)
MFC after: 4 months
Diffstat (limited to 'bin')
-rw-r--r-- | bin/cat/cat.c | 23 | ||||
-rw-r--r-- | bin/cp/utils.c | 31 |
2 files changed, 50 insertions, 4 deletions
diff --git a/bin/cat/cat.c b/bin/cat/cat.c index 9acd68f..d338742 100644 --- a/bin/cat/cat.c +++ b/bin/cat/cat.c @@ -77,6 +77,17 @@ static void raw_cat(int); static int udom_open(const char *path, int flags); #endif +/* Memory strategy threshold, in pages: if physmem is larger then this, use a + * large buffer */ +#define PHYSPAGES_THRESHOLD (32*1024) + +/* Maximum buffer size in bytes - do not allow it to grow larger than this */ +#define BUFSIZE_MAX (2*1024*1024) + +/* Small (default) buffer size in bytes. It's inefficient for this to be + * smaller than MAXPHYS */ +#define BUFSIZE_SMALL (MAXPHYS) + int main(int argc, char *argv[]) { @@ -247,9 +258,17 @@ raw_cat(int rfd) if (buf == NULL) { if (fstat(wfd, &sbuf)) err(1, "%s", filename); - bsize = MAX(sbuf.st_blksize, 1024); + if (S_ISREG(sbuf.st_mode)) { + /* If there's plenty of RAM, use a large copy buffer */ + if (sysconf(_SC_PHYS_PAGES) > PHYSPAGES_THRESHOLD) + bsize = MIN(BUFSIZE_MAX, MAXPHYS*8); + else + bsize = BUFSIZE_SMALL; + } else + bsize = MAX(sbuf.st_blksize, + (blksize_t)sysconf(_SC_PAGESIZE)); if ((buf = malloc(bsize)) == NULL) - err(1, "buffer"); + err(1, "malloc() failure of IO buffer"); } while ((nr = read(rfd, buf, bsize)) > 0) for (off = 0; nr; nr -= nw, off += nw) diff --git a/bin/cp/utils.c b/bin/cp/utils.c index 03ddbbc..aaa12d6 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -57,10 +57,22 @@ __FBSDID("$FreeBSD$"); #define cp_pct(x, y) ((y == 0) ? 0 : (int)(100.0 * (x) / (y))) +/* Memory strategy threshold, in pages: if physmem is larger then this, use a + * large buffer */ +#define PHYSPAGES_THRESHOLD (32*1024) + +/* Maximum buffer size in bytes - do not allow it to grow larger than this */ +#define BUFSIZE_MAX (2*1024*1024) + +/* Small (default) buffer size in bytes. It's inefficient for this to be + * smaller than MAXPHYS */ +#define BUFSIZE_SMALL (MAXPHYS) + int copy_file(const FTSENT *entp, int dne) { - static char buf[MAXBSIZE]; + static char *buf = NULL; + static size_t bufsize; struct stat *fs; ssize_t wcount; size_t wresid; @@ -174,8 +186,23 @@ copy_file(const FTSENT *entp, int dne) } else #endif { + if (buf == NULL) { + /* + * Note that buf and bufsize are static. If + * malloc() fails, it will fail at the start + * and not copy only some files. + */ + if (sysconf(_SC_PHYS_PAGES) > + PHYSPAGES_THRESHOLD) + bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); + else + bufsize = BUFSIZE_SMALL; + buf = malloc(bufsize); + if (buf == NULL) + err(1, "Not enough memory"); + } wtotal = 0; - while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { + while ((rcount = read(from_fd, buf, bufsize)) > 0) { for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { wcount = write(to_fd, bufp, wresid); |