Tar wastes CPU
Dave Martindale
dave at onfcanim.UUCP
Thu Jun 19 13:02:56 AEST 1986
Description:
The tar tape utility distributed with 4.2BSD (and all the other
versions I know of) copies all of the data going to and from
the tape from one buffer to another. This is wasteful.
It also does its filesystem I/O 512 bytes at a time.
If you are handling lots of little files, the copying is only
a small part of the total time, but when handling large files
it predominates. For example, writing and reading a single
24.6Mb file gives these timings:
write read
old: 15.2u 99.8s 4:46 20.7u 202.0s 6:34
new: 0.6u 37.3s 3:29 1.1u 57.5s 3:48
These were measured using a 50 IPS 6250 BPI tape drive on the
Unibus and Eagle/Emulex/Massbus disk on a 780. With a faster
tape drive, the difference in real time would likely be more
dramatic.
Not only do you get your data faster, but there is more left
of your VAX while doing it. (We use tar tapes for images,
and have two tape drives reading at once sometimes. Quite
a difference).
Fix:
Make the following changes. The diffs are relative to the
tar.c on the 4.2BSD distribution tape, which probably hasn't
changed too much since v7. The major part of this is adding
routines to read and write files directly into/out of the tape
buffer. It also takes care not to copy data it is going to
throw away while skipping a file.
Most of the rest of the changes just make tar pass lint.
(You lint something after working on it, don't you?)
Dave Martindale
watmath!onfcanim!dave
=================================================================
*** otar.c Wed Jun 18 20:51:57 1986
--- tar.c Wed Jun 18 22:51:26 1986
***************
*** 14,19
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#define TBLOCK 512
#define NBLOCK 20
--- 14,20 -----
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
+ extern errno;
#define TBLOCK 512
#define NBLOCK 20
***************
*** 81,86
FILE *tfile;
char tname[] = "/tmp/tarXXXXXX";
char *usefile;
char magtape[] = "/dev/rmt8";
char *malloc();
--- 82,88 -----
FILE *tfile;
char tname[] = "/tmp/tarXXXXXX";
+ char *mktemp();
char *usefile;
char magtape[] = "/dev/rmt8";
char *malloc();
***************
*** 85,91
char magtape[] = "/dev/rmt8";
char *malloc();
char *sprintf();
- char *strcat();
char *rindex();
char *getcwd();
char *getwd();
--- 87,92 -----
char magtape[] = "/dev/rmt8";
char *malloc();
char *sprintf();
char *rindex();
char *strcpy();
char *getcwd();
***************
*** 87,92
char *sprintf();
char *strcat();
char *rindex();
char *getcwd();
char *getwd();
--- 88,94 -----
char *malloc();
char *sprintf();
char *rindex();
+ char *strcpy();
char *getcwd();
char *getwd();
***************
*** 219,225
if (!rflag && !xflag && !tflag)
usage();
! tbuf = (union hblock *)malloc(nblock*TBLOCK);
if (tbuf == NULL) {
fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
nblock);
--- 221,227 -----
if (!rflag && !xflag && !tflag)
usage();
! tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK);
if (tbuf == NULL) {
fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
nblock);
***************
*** 247,253
mt = dup(1);
nblock = 1;
} else if ((mt = open(usefile, 2)) < 0) {
! if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) {
fprintf(stderr,
"tar: cannot open %s\n", usefile);
done(1);
--- 249,256 -----
mt = dup(1);
nblock = 1;
} else if ((mt = open(usefile, 2)) < 0) {
! if (errno != ENOENT || cflag == 0 ||
! (mt = creat(usefile, 0666)) < 0) {
fprintf(stderr,
"tar: cannot open %s\n", usefile);
done(1);
***************
*** 388,394
passtape()
{
long blocks;
- char buf[TBLOCK];
if (dblock.dbuf.linkflag == '1')
return;
--- 391,396 -----
passtape()
{
long blocks;
if (dblock.dbuf.linkflag == '1')
return;
***************
*** 397,403
blocks /= TBLOCK;
while (blocks-- > 0)
! readtape(buf);
}
putfile(longname, shortname, parent)
--- 399,405 -----
blocks /= TBLOCK;
while (blocks-- > 0)
! readtape((char *)0);
}
putfile(longname, shortname, parent)
***************
*** 407,414
{
int infile = 0;
long blocks;
! char buf[TBLOCK];
! register char *cp, *cp2;
struct direct *dp;
DIR *dirp;
int i, j;
--- 409,416 -----
{
int infile = 0;
long blocks;
! char buf[NAMSIZ+64];
! register char *cp;
struct direct *dp;
DIR *dirp;
long i;
***************
*** 411,417
register char *cp, *cp2;
struct direct *dp;
DIR *dirp;
! int i, j;
char newparent[NAMSIZ+64];
extern int errno;
--- 413,419 -----
register char *cp;
struct direct *dp;
DIR *dirp;
! long i;
char newparent[NAMSIZ+64];
extern int errno;
***************
*** 438,444
return;
if (checkw('r', longname) == 0)
return;
! if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
return;
switch (stbuf.st_mode & S_IFMT) {
--- 440,446 -----
return;
if (checkw('r', longname) == 0)
return;
! if (Fflag && checkf(shortname, (int)stbuf.st_mode, Fflag) == 0)
return;
switch (stbuf.st_mode & S_IFMT) {
***************
*** 476,484
while ((dp = readdir(dirp)) != NULL && !term) {
if (dp->d_ino == 0)
continue;
! if (!strcmp(".", dp->d_name) ||
! !strcmp("..", dp->d_name))
! continue;
strcpy(cp, dp->d_name);
i = telldir(dirp);
closedir(dirp);
--- 478,487 -----
while ((dp = readdir(dirp)) != NULL && !term) {
if (dp->d_ino == 0)
continue;
! if (*dp->d_name == '.')
! if (!strcmp(".", dp->d_name) ||
! !strcmp("..", dp->d_name))
! continue;
strcpy(cp, dp->d_name);
i = telldir(dirp);
closedir(dirp);
***************
*** 532,537
if (strlen(longname) >= NAMSIZ) {
fprintf(stderr, "tar: %s: file name too long\n",
longname);
return;
}
strcpy(dblock.dbuf.name, longname);
--- 535,541 -----
if (strlen(longname) >= NAMSIZ) {
fprintf(stderr, "tar: %s: file name too long\n",
longname);
+ close(infile);
return;
}
strcpy(dblock.dbuf.name, longname);
***************
*** 536,542
}
strcpy(dblock.dbuf.name, longname);
if (stbuf.st_nlink > 1) {
! struct linkbuf *lp;
int found = 0;
for (lp = ihead; lp != NULL; lp = lp->nextp)
--- 540,546 -----
}
strcpy(dblock.dbuf.name, longname);
if (stbuf.st_nlink > 1) {
! register struct linkbuf *lp;
int found = 0;
for (lp = ihead; lp != NULL; lp = lp->nextp)
***************
*** 583,594
sprintf(dblock.dbuf.chksum, "%6o", checksum());
writetape((char *)&dblock);
! while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) {
! writetape(buf);
! blocks--;
! }
! close(infile);
! if (blocks != 0 || i != 0)
fprintf(stderr, "tar: %s: file changed size\n",
longname);
while (--blocks >= 0)
--- 587,593 -----
sprintf(dblock.dbuf.chksum, "%6o", checksum());
writetape((char *)&dblock);
! if (writefile((long)stbuf.st_size, infile))
fprintf(stderr, "tar: %s: file changed size\n",
longname);
close(infile);
***************
*** 591,598
if (blocks != 0 || i != 0)
fprintf(stderr, "tar: %s: file changed size\n",
longname);
! while (--blocks >= 0)
! putempty();
break;
default:
--- 590,596 -----
if (writefile((long)stbuf.st_size, infile))
fprintf(stderr, "tar: %s: file changed size\n",
longname);
! close(infile);
break;
default:
***************
*** 606,612
char *argv[];
{
long blocks, bytes;
- char buf[TBLOCK];
char **cp;
int ofile;
--- 604,609 -----
char *argv[];
{
long blocks, bytes;
char **cp;
int ofile;
***************
*** 634,640
s = dblock.dbuf.name;
else
s++;
! if (checkf(s, stbuf.st_mode, Fflag) == 0) {
passtape();
continue;
}
--- 631,637 -----
s = dblock.dbuf.name;
else
s++;
! if (checkf(s, (int)stbuf.st_mode, Fflag) == 0) {
passtape();
continue;
}
***************
*** 680,686
dblock.dbuf.name, dblock.dbuf.linkname);
continue;
}
! if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
fprintf(stderr, "tar: %s - cannot create\n",
dblock.dbuf.name);
passtape();
--- 677,684 -----
dblock.dbuf.name, dblock.dbuf.linkname);
continue;
}
! if ((ofile = creat(dblock.dbuf.name,
! (int)stbuf.st_mode&0xfff)) < 0) {
fprintf(stderr, "tar: %s - cannot create\n",
dblock.dbuf.name);
passtape();
***************
*** 691,714
if (vflag)
fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n",
dblock.dbuf.name, bytes, blocks);
! for (; blocks-- > 0; bytes -= TBLOCK) {
! readtape(buf);
! if (bytes > TBLOCK) {
! if (write(ofile, buf, TBLOCK) < 0) {
! fprintf(stderr,
! "tar: %s: HELP - extract write error\n",
! dblock.dbuf.name);
! done(2);
! }
! continue;
! }
! if (write(ofile, buf, (int) bytes) < 0) {
! fprintf(stderr,
! "tar: %s: HELP - extract write error\n",
! dblock.dbuf.name);
! done(2);
! }
! }
close(ofile);
if (mflag == 0) {
struct timeval tv[2];
--- 689,695 -----
if (vflag)
fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n",
dblock.dbuf.name, bytes, blocks);
! readfile(bytes, ofile);
close(ofile);
if (mflag == 0) {
struct timeval tv[2];
***************
*** 712,717
close(ofile);
if (mflag == 0) {
struct timeval tv[2];
tv[0].tv_sec = time(0);
tv[0].tv_usec = 0;
--- 693,699 -----
close(ofile);
if (mflag == 0) {
struct timeval tv[2];
+ time_t time();
tv[0].tv_sec = time((time_t *)0);
tv[0].tv_usec = 0;
***************
*** 713,719
if (mflag == 0) {
struct timeval tv[2];
! tv[0].tv_sec = time(0);
tv[0].tv_usec = 0;
tv[1].tv_sec = stbuf.st_mtime;
tv[1].tv_usec = 0;
--- 695,701 -----
struct timeval tv[2];
time_t time();
! tv[0].tv_sec = time((time_t *)0);
tv[0].tv_usec = 0;
tv[1].tv_sec = stbuf.st_mtime;
tv[1].tv_usec = 0;
***************
*** 720,726
utimes(dblock.dbuf.name, tv);
}
if (pflag)
! chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
}
}
--- 702,708 -----
utimes(dblock.dbuf.name, tv);
}
if (pflag)
! chmod(dblock.dbuf.name, (int)(stbuf.st_mode & 07777));
}
}
***************
*** 757,764
char *ctime();
pmode(st);
! printf("%3d/%1d", st->st_uid, st->st_gid);
! printf("%7D", st->st_size);
cp = ctime(&st->st_mtime);
printf(" %-12.12s %-4.4s ", cp+4, cp+20);
}
--- 739,746 -----
char *ctime();
pmode(st);
! printf("%3d/%-2d", st->st_uid, st->st_gid);
! printf("%9D", st->st_size);
cp = ctime(&st->st_mtime);
printf(" %-12.12s %-4.4s ", cp+4, cp+20);
}
***************
*** 793,799
register int **mp;
for (mp = &m[0]; mp < &m[9];)
! select(*mp++, st);
}
select(pairp, st)
--- 775,781 -----
register int **mp;
for (mp = &m[0]; mp < &m[9];)
! mselect(*mp++, st);
}
mselect(pairp, st)
***************
*** 796,802
select(*mp++, st);
}
! select(pairp, st)
int *pairp;
struct stat *st;
{
--- 778,784 -----
mselect(*mp++, st);
}
! mselect(pairp, st)
int *pairp;
struct stat *st;
{
***************
*** 841,847
}
chown(name, stbuf.st_uid, stbuf.st_gid);
if (pflag && cp[1] == '\0')
! chmod(name, stbuf.st_mode & 0777);
}
*cp = '/';
}
--- 823,829 -----
}
chown(name, stbuf.st_uid, stbuf.st_gid);
if (pflag && cp[1] == '\0')
! chmod(name, (int)(stbuf.st_mode & 0777));
}
*cp = '/';
}
***************
*** 866,871
term++;
}
onterm()
{
signal(SIGTERM, SIG_IGN);
--- 848,854 -----
term++;
}
+ #ifdef notdef
onterm()
{
signal(SIGTERM, SIG_IGN);
***************
*** 871,876
signal(SIGTERM, SIG_IGN);
term++;
}
tomodes(sp)
register struct stat *sp;
--- 854,860 -----
signal(SIGTERM, SIG_IGN);
term++;
}
+ #endif
tomodes(sp)
register struct stat *sp;
***************
*** 892,899
register char *cp;
for (cp = dblock.dbuf.chksum;
! cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
! *cp = ' ';
i = 0;
for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
i += *cp;
--- 876,883 -----
register char *cp;
for (cp = dblock.dbuf.chksum;
! cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; )
! *cp++ = ' ';
i = 0;
for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; )
i += *cp++;
***************
*** 895,902
cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
*cp = ' ';
i = 0;
! for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
! i += *cp;
return (i);
}
--- 879,886 -----
cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; )
*cp++ = ' ';
i = 0;
! for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; )
! i += *cp++;
return (i);
}
***************
*** 914,920
response()
{
! char c;
c = getchar();
if (c != '\n')
--- 898,904 -----
response()
{
! int c;
c = getchar();
if (c != '\n')
***************
*** 985,991
daddr_t
lookup(s)
! char *s;
{
register i;
daddr_t a;
--- 969,975 -----
daddr_t
lookup(s)
! register char *s;
{
register i;
***************
*** 988,994
char *s;
{
register i;
- daddr_t a;
for(i=0; s[i]; i++)
if (s[i] == ' ')
--- 972,977 -----
register char *s;
{
register i;
for(i=0; s[i]; i++)
if (s[i] == ' ')
***************
*** 993,1000
for(i=0; s[i]; i++)
if (s[i] == ' ')
break;
! a = bsrch(s, i, low, high);
! return (a);
}
daddr_t
--- 976,982 -----
for(i=0; s[i]; i++)
if (s[i] == ' ')
break;
! return bsrch(s, i, low, high);
}
daddr_t
***************
*** 1044,1050
}
cmp(b, s, n)
! char *b, *s;
{
register i;
--- 1026,1032 -----
}
cmp(b, s, n)
! register char *b, *s;
{
register i;
***************
*** 1062,1068
readtape(buffer)
char *buffer;
{
! register int i;
if (recno >= nblock || first == 0) {
if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
--- 1044,1050 -----
readtape(buffer)
char *buffer;
{
! register int want, i;
if (recno >= nblock || first == 0) {
want = TBLOCK*nblock;
***************
*** 1065,1077
register int i;
if (recno >= nblock || first == 0) {
! if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
! fprintf(stderr, "tar: tape read error\n");
! done(3);
! }
! if (first == 0) {
! if ((i % TBLOCK) != 0) {
! fprintf(stderr, "tar: tape blocksize error\n");
done(3);
}
i /= TBLOCK;
--- 1047,1079 -----
register int want, i;
if (recno >= nblock || first == 0) {
! want = TBLOCK*nblock;
! if ((i = bread(mt, (char *)tbuf, want)) != want) {
! if (i > 0) {
! if (first == 0) {
! if ((i % TBLOCK) != 0) {
! fprintf(stderr,
! "tar: tape blocksize error\n");
! done(3);
! }
! i /= TBLOCK;
! if (i != nblock) {
! if (vflag)
! fprintf(stderr,
! "tar: blocksize = %d\n", i);
! nblock = i;
! }
! } else {
!
! fprintf(stderr,
! "tar: short read, got %d wanted %d\n",
! i, want);
! done(3);
! }
! } else {
! fprintf(stderr, "tar: %s\n",
! i < 0 ? "tape read error" :
! "unexpected EOF");
done(3);
}
}
***************
*** 1074,1084
fprintf(stderr, "tar: tape blocksize error\n");
done(3);
}
- i /= TBLOCK;
- if (i != nblock) {
- fprintf(stderr, "tar: blocksize = %d\n", i);
- nblock = i;
- }
}
recno = 0;
}
--- 1076,1081 -----
"unexpected EOF");
done(3);
}
}
recno = 0;
}
***************
*** 1083,1089
recno = 0;
}
first = 1;
! bcopy((char *)&tbuf[recno++], buffer, TBLOCK);
return (TBLOCK);
}
--- 1080,1088 -----
recno = 0;
}
first = 1;
! if (buffer != (char *)0)
! bcopy((char *)&tbuf[recno], buffer, TBLOCK);
! recno++;
return (TBLOCK);
}
***************
*** 1087,1092
return (TBLOCK);
}
writetape(buffer)
char *buffer;
{
--- 1086,1130 -----
return (TBLOCK);
}
+ readfile(bytes, file)
+ long bytes;
+ int file;
+ {
+ register int i, avail, nbytes;
+ register char *where;
+
+ where = (char *)&tbuf[recno];
+ avail = (nblock - recno) * TBLOCK;
+ while (bytes > 0) {
+ if (avail <= 0) {
+ nbytes = TBLOCK*nblock;
+ if ((i = bread(mt, (char *)tbuf, nbytes)) != nbytes) {
+ if (i > 0)
+ fprintf(stderr,
+ "tar: short read, got %d wanted %d\n",
+ i, nbytes);
+ else
+ fprintf(stderr, "tar: %s\n",
+ i < 0 ? "tape read error" :
+ "unexpected EOF");
+ done(3);
+ }
+ avail = nbytes;
+ where = (char *)tbuf;
+ }
+ nbytes = avail;
+ if (bytes < nbytes)
+ nbytes = bytes;
+ if (write(file, where, (int)nbytes) != nbytes) {
+ perror(dblock.dbuf.name);
+ done(2);
+ }
+ bytes -= nbytes;
+ avail -= nbytes;
+ }
+ recno = nblock - (avail/TBLOCK);
+ }
+
writetape(buffer)
char *buffer;
{
***************
*** 1092,1098
{
first = 1;
if (recno >= nblock) {
! if (write(mt, tbuf, TBLOCK*nblock) < 0) {
fprintf(stderr, "tar: tape write error\n");
done(2);
}
--- 1130,1136 -----
{
first = 1;
if (recno >= nblock) {
! if (write(mt, (char *)tbuf, TBLOCK*nblock) < 0) {
fprintf(stderr, "tar: tape write error\n");
done(2);
}
***************
*** 1099,1104
recno = 0;
}
bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
if (recno >= nblock) {
if (write(mt, tbuf, TBLOCK*nblock) < 0) {
fprintf(stderr, "tar: tape write error\n");
--- 1137,1144 -----
recno = 0;
}
bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
+ #if 0
+ /* why is this being done again? -dmm */
if (recno >= nblock) {
if (write(mt, tbuf, TBLOCK*nblock) < 0) {
fprintf(stderr, "tar: tape write error\n");
***************
*** 1106,1111
}
recno = 0;
}
return (TBLOCK);
}
--- 1146,1152 -----
}
recno = 0;
}
+ #endif
return (TBLOCK);
}
***************
*** 1109,1114
return (TBLOCK);
}
backtape()
{
static int mtdev = 1;
--- 1150,1199 -----
return (TBLOCK);
}
+ writefile(bytes, file)
+ long bytes;
+ int file;
+ {
+ register int avail, nbytes, i;
+ register char *where;
+ int eof = 0;
+ char junk;
+
+ where = (char *)&tbuf[recno];
+ avail = (nblock - recno) * TBLOCK;
+ while (bytes > 0) {
+ if (avail <= 0) {
+ nbytes = TBLOCK*nblock;
+ if (write(mt, (char *)tbuf, nbytes) != nbytes) {
+ perror("tape write error");
+ done(2);
+ }
+ avail = nbytes;
+ where = (char *)tbuf;
+ }
+ nbytes = avail;
+ if (bytes < nbytes)
+ nbytes = bytes;
+ if (eof)
+ bzero(where, nbytes);
+ else if ((i = read(file, where, nbytes)) != nbytes) {
+ if (i < 0) {
+ perror(dblock.dbuf.name);
+ done(2);
+ }
+ eof = 1;
+ bzero(where + i, nbytes - i);
+ }
+ bytes -= nbytes;
+ avail -= nbytes;
+ }
+ recno = nblock - (avail/TBLOCK);
+
+ if (eof || read(file, &junk, sizeof(junk)) != 0)
+ return (1);
+ return (0);
+ }
+
backtape()
{
static int mtdev = 1;
***************
*** 1116,1122
struct mtget mtget;
if (mtdev == 1)
! mtdev = ioctl(mt, MTIOCGET, &mtget);
if (mtdev == 0) {
if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
fprintf(stderr, "tar: tape backspace error\n");
--- 1201,1207 -----
struct mtget mtget;
if (mtdev == 1)
! mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
if (mtdev == 0) {
if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
fprintf(stderr, "tar: tape backspace error\n");
***************
*** 1118,1124
if (mtdev == 1)
mtdev = ioctl(mt, MTIOCGET, &mtget);
if (mtdev == 0) {
! if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
fprintf(stderr, "tar: tape backspace error\n");
done(4);
}
--- 1203,1209 -----
if (mtdev == 1)
mtdev = ioctl(mt, MTIOCGET, (char *)&mtget);
if (mtdev == 0) {
! if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) {
fprintf(stderr, "tar: tape backspace error\n");
done(4);
}
***************
*** 1123,1129
done(4);
}
} else
! lseek(mt, (long) -TBLOCK*nblock, 1);
recno--;
}
--- 1208,1214 -----
done(4);
}
} else
! lseek(mt, (off_t) -TBLOCK*nblock, 1);
recno--;
}
***************
*** 1129,1135
flushtape()
{
! write(mt, tbuf, TBLOCK*nblock);
}
bread(fd, buf, size)
--- 1214,1223 -----
flushtape()
{
! if (write(mt, (char *)tbuf, TBLOCK*nblock) < 0) {
! fprintf(stderr, "tape write error");
! exit(2);
! }
}
bread(fd, buf, size)
More information about the Net.bugs.v7
mailing list