#include #include #include #include #include #include #include #include #include #include #include #include extern char *optarg; extern int optind; #ifndef O_DIRECT #define O_DIRECT 0x00080000 #endif int main(int argc, char **argv) { int c, i, fd, ifd, ofd; int mode, count, nrep, reps, seek, dofsync, gprof, rv; char *file, *ifile, *ofile, *buf, *cp; size_t size; struct timeval tv1, tv2; int mib[3]; int gprof_state, sz; int value; int direct, trunc, touch, openflags, pgsz; size_t actual; pgsz = getpagesize(); sz = sizeof(gprof_state); file = NULL; ifile = NULL; ifd = 0; ofile = NULL; ofd = 0; mode = 0; count = 300; size = 1024 * 1024; seek = 0; nrep = 1; dofsync = 0; direct = 0; gprof = 0; value = 'x'; trunc = 0; touch = 0; actual = 0; while ((c = getopt(argc, argv, "rwdc:s:n:k:flpv:tTo:i:")) != -1) { switch (c) { case 'r': mode = 1; break; case 'w': mode = 2; break; case 'd': direct = 1; break; case 'c': count = strtol(optarg, NULL, 0); break; case 'n': nrep = strtol(optarg, NULL, 0); break; case 's': size = strtol(optarg, NULL, 0); break; case 'k': seek = strtol(optarg, NULL, 0); break; case 'f': dofsync = 1; break; case 'l': if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) { err(1, "mlockall"); } break; case 'p': gprof = 1; break; case 'v': value = *optarg; break; case 't': trunc = 1; break; case 'T': touch = 1; break; case 'i': ifile = optarg; break; case 'o': ofile = optarg; break; default: errx(1, "bogus option `%c'", c); } } if (optind == argc) { errx(1, "must specify a file"); } file = argv[optind]; if (mode == 0) { errx(1, "must use one of `-r' or `-w'"); } openflags = (mode == 1) ? O_RDONLY : (O_WRONLY|O_CREAT); if (trunc) { openflags |= O_TRUNC; } if (direct) { openflags |= O_DIRECT; } fd = open(file, openflags, 0666); if (fd < 0) { err(1, "open"); } if (ifile) { ifd = open(ifile, O_RDONLY); if (ifd < 0) { err(1, "open ifile"); } } if (ofile) { ofd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (ofd < 0) { err(1, "open ofile"); } } buf = malloc(size); if (buf == NULL) { err(1, "malloc"); } memset(buf, value, size); if (gprof) { mib[0] = CTL_KERN; mib[1] = KERN_PROF; mib[2] = GPROF_STATE; gprof_state = GMON_PROF_ON; if (sysctl(mib, 3, NULL, NULL, &gprof_state, sz) < 0) { err(1, "sysctl gprof on"); } } if (gettimeofday(&tv1, NULL) < 0) { err(1, "gettimeofday 1"); } reps = nrep; while (reps--) { if (mode == 1) { for (i = 0; i < count; i++) { rv = read(fd, buf, size); if (rv < 0) { err(1, "read"); } if (rv == 0) { fprintf(stderr, "read hit EOF\n"); break; } actual += rv; if (ofile) { (void) write(ofd, buf, rv); } if (touch) { for (cp = buf; cp < buf + size; cp += pgsz) { *cp = 1; } } if (seek && lseek(fd, seek, SEEK_CUR) < 0) { err(1, "lseek"); } } } else { for (i = 0; i < count; i++) { if (ifile) { rv = read(ifd, buf, size); if (rv < 0) { err(1, "read ifile"); } } rv = write(fd, buf, size); if (rv < 0) { err(1, "write"); } if (touch) { for (cp = buf; cp < buf + size; cp += pgsz) { *cp = 1; } } actual += rv; if (seek && lseek(fd, seek, SEEK_CUR) < 0) { err(1, "lseek"); } } } if (dofsync) { rv = fsync(fd); if (rv < 0) { err(1, "fsync"); } } if (lseek(fd, 0, SEEK_SET) < 0) { err(1, "lseek"); } } if (gettimeofday(&tv2, NULL) < 0) { err(1, "gettimeofday 1"); } if (gprof) { gprof_state = GMON_PROF_OFF; if (sysctl(mib, 3, NULL, NULL, &gprof_state, sz) < 0) { err(1, "sysctl gprof off"); } } timersub(&tv2, &tv1, &tv2); printf("%lld bytes transferred in %ld.%03ld secs (%lld bytes/sec)\n", ((uint64_t)actual), tv2.tv_sec, tv2.tv_usec / 1000, (((uint64_t)actual * 1000000) / ((uint64_t)tv2.tv_sec * 1000000 + tv2.tv_usec))); exit(0); }