home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.unix
- From: lm@slovax.Eng.Sun.COM (Larry McVoy)
- Subject: v26i061: lmdd - Trivial disk I/O performance tester - like dd
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: lm@slovax.Eng.Sun.COM (Larry McVoy)
- Posting-Number: Volume 26, Issue 61
- Archive-Name: lmdd
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: lmdd.1 Makefile lmdd.c ddperf
- # Wrapped by vixie@cognition.pa.dec.com on Sat Jun 13 17:03:23 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'lmdd.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lmdd.1'\"
- else
- echo shar: Extracting \"'lmdd.1'\" \(2809 characters\)
- sed "s/^X//" >'lmdd.1' <<'END_OF_FILE'
- X.\" @(#)lmdd.1 1.1 2/27/92
- X.TH LMDD 1
- X.SH NAME
- lmdd \- move io for performance and debugging tests
- X.SH SYNOPSIS
- X.B lmdd
- X[
- X.IB option = value
- X] .\|.\|.
- X.SH DESCRIPTION
- X.B lmdd
- copies a specified input file to a specified output with possible
- conversions. This program is primarily useful for timing I/O since it
- prints out the timing statistics after completing.
- X.SH OPTIONS
- X.TP 15
- X.BI if= name
- Input file is taken from
- X.IR name ;
- standard input is default.
- X.I internal
- is a special file that acts like Sun's
- X.IR /dev/zero ,
- i.e., it provides a buffer of zeros without doing a system call to get them.
- X.TP
- X.BI of= name
- Output file is taken from
- X.IR name ;
- standard output is default.
- X.I internal
- is a special file that acts like
- X.IR /dev/null ,
- without doing a system call to get rid of the data.
- X.TP
- X.BI bs= n
- Input and output block size
- X.I n
- bytes (default 8192). Note that this is different from dd(1), it has
- a 512 byte default. Also note that the block size can be followed
- by 'k' or 'm' to indicate kilo bytes (*1024) or megabytes (*1024*1024),
- respectively.
- X.TP
- X.BI ipat= n
- If
- X.B n
- is non zero, expect a known pattern in the file (see opat). Mismatches
- will be displayed as "ERROR: off=%d want=%x got=%x". The pattern is
- a sequence of 4 byte integers with the first 0, second 1, and so on.
- The default is not to check for the pattern.
- X.TP
- X.BI opat= n
- If
- X.B n
- is non zero, generate a known pattern on the output stream. Used for
- debugging file system correctness.
- The default is not to generate the pattern.
- X.TP
- X.BI mismatch= n
- If
- X.B n
- is non zero, stop at the first mismatched value. Used with ipat.
- X.TP
- X.BI skip= n
- Skip
- X.IR n ""
- input blocks before starting copy.
- X.TP
- X.BI fsync= n
- If
- X.I n
- is non-zero, call fsync(2) on the output file before exiting or printing
- timing statistics.
- X.TP
- X.BI sync= n
- If
- X.I n
- is non-zero, call sync(2) before exiting or printing
- timing statistics.
- X.TP
- X.BI flush= n
- If
- X.I n
- is non-zero and mmap(2) is available, call msync(2) to invalidate the
- output file. This flushes the file to disk so that you don't have
- unmount/mount. It is not as good as mount/unmount because it just
- flushes file pages - it misses the indirect blocks which are still
- cached.
- X.TP
- X.BI rusage= n
- If
- X.I n
- is non-zero, print rusage statistics as well as timing statistics.
- X.TP
- X.BI count= n
- Copy only
- X.IR n ""
- input records.
- X.SH EXAMPLES
- X.LP
- This is the most common usage, the intent is to measure disk performance.
- The disk is a spare partition mounted on /spare.
- X.sp
- X.nf
- X.in +4
- X# mount /spare
- X# lmdd if=internal of=/spare/XXX count=1000 fsync=1
- X7.81 MB in 3.78 seconds (2.0676 MB/sec)
- X
- X: Flush cache
- X# umount /spare
- X# mount /spare
- X
- X# lmdd if=/spare/XXX of=internal
- X7.81 MB in 2.83 seconds (2.7611 MB/sec)
- X.in
- X.sp
- X.fi
- X.SH AUTHOR
- Larry McVoy, lm@sun.com
- X.br
- Not copyrighted.
- END_OF_FILE
- if test 2809 -ne `wc -c <'lmdd.1'`; then
- echo shar: \"'lmdd.1'\" unpacked with wrong size!
- fi
- # end of 'lmdd.1'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(315 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- DESTROOT=
- DESTPATH=$(DESTROOT)/usr/local
- X
- all: lmdd ddperf
- X
- lmdd: lmdd.o
- X cc -o lmdd lmdd.o
- X
- ddperf: ddperf.sh
- X cp ddperf.sh ddperf
- X chmod +x ddperf
- X
- install:
- X install -c -s lmdd $(DESTPATH)/bin/lmdd
- X install -c lmdd.1 $(DESTPATH)/man/man1/lmdd.1
- X
- X# we don't install ddperf because it has no man page (vixie)
- X
- END_OF_FILE
- if test 315 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'lmdd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lmdd.c'\"
- else
- echo shar: Extracting \"'lmdd.c'\" \(6270 characters\)
- sed "s/^X//" >'lmdd.c' <<'END_OF_FILE'
- static char sccsid[] = "@(#)lmdd.c 1.7";
- X
- X/*
- X * lmdd, lm@sun.com (Larry McVoy)
- X *
- X * Uncopyrighted, do whatever you want with it.
- X *
- X * defaults:
- X * bs=8k
- X * count=forever
- X * if=stdin
- X * of=stdout
- X * ipat=0
- X * opat=0
- X * mismatch=0
- X * rusage=0
- X * flush=0
- X * shorthands:
- X * recognizes 'k' or 'm' at the end of a number for 1024 & 1024^2
- X * recognizes "internal" as an internal /dev/zero /dev/null file.
- X */
- X#include <signal.h>
- X#include <sys/types.h>
- X#include <sys/time.h>
- X#ifndef SVR4
- X#include <sys/resource.h>
- X#endif
- X#define FLUSH
- X#ifdef FLUSH
- X#include <unistd.h>
- X#include <sys/mman.h>
- X#include <sys/stat.h>
- X#endif
- X#define STARTUP (.11) /* XXX - about how long before it starts
- X * working. So time matches w/ rusage. This is
- X * close on a 20Mhz SS. */
- X#define uchar unsigned char
- X
- int out, Fsync, Sync, Flush, ru, c;/* done needs it */
- char *cmds[] = {
- X "if", /* input file */
- X "of", /* output file */
- X "ipat", /* check input for pattern */
- X "opat", /* generate pattern on output */
- X "mismatch", /* stop at first mismatch */
- X "bs", /* block size */
- X "count", /* number of blocks */
- X "skip", /* skip this number of blocks on input */
- X "fsync", /* fsync output before exit */
- X "sync", /* sync output before exit */
- X "rusage", /* dump rusage stats */
- X#ifdef FLUSH
- X "flush", /* map in out and invalidate (flush) */
- X#endif
- X 0,
- X};
- X
- main(ac, av)
- X char **av;
- X{
- X uint *buf;
- X int misses, mismatch, outpat, inpat, bs, in, gotcnt, count;
- X int skip;
- X extern char *valloc();
- X void done();
- X int i;
- X
- X for (i = 1; i < ac; ++i) {
- X chkarg(av[i]);
- X }
- X misses = mismatch = getarg("mismatch=", ac, av);
- X inpat = getarg("ipat=", ac, av);
- X outpat = getarg("opat=", ac, av);
- X in = getfile("if=", ac, av);
- X if (in == -1)
- X in = 0;
- X out = getfile("of=", ac, av);
- X if (out == -1)
- X out = 1;
- X bs = getarg("bs=", ac, av);
- X if (bs < 0)
- X bs = 8192;
- X Fsync = getarg("fsync=", ac, av);
- X Sync = getarg("sync=", ac, av);
- X ru = getarg("rusage=", ac, av);
- X count = getarg("count=", ac, av);
- X Flush = getarg("flush=", ac, av);
- X if (count < 0)
- X gotcnt = 0;
- X else
- X gotcnt = 1;
- X c = 0;
- X skip = getarg("skip=", ac, av);
- X
- X if (inpat != -1 || outpat != -1 && (bs & 3)) {
- X printf("Block size must be word aligned\n");
- X exit(1);
- X }
- X if (!(buf = (uint *) valloc((unsigned) bs))) {
- X perror("valloc");
- X exit(1);
- X }
- X bzero((char *) buf, bs);
- X
- X signal(SIGINT, done);
- X if (skip > 0)
- X lseek(in, skip * bs, 0);
- X start();
- X for (;;) {
- X register x;
- X
- X if (gotcnt && count-- <= 0)
- X done();
- X if (in >= 0)
- X x = read(in, buf, bs);
- X else
- X x = bs;
- X if (x <= 0)
- X done();
- X if (inpat != -1) {
- X register foo, cnt;
- X
- X for (foo = 0, cnt = x >> 2; cnt--; foo++) {
- X if (buf[foo] != (uint) (c + foo)) {
- X printf("ERROR: off=%d want=%x got=%x\n",
- X c + foo, c + foo, buf[foo]);
- X if (mismatch != -1 && --misses == 0)
- X done();
- X }
- X }
- X }
- X if (outpat != -1) {
- X register foo, cnt;
- X
- X for (foo = 0, cnt = x >> 2; cnt--; foo++)
- X buf[foo] = c + foo;
- X }
- X if (out >= 0)
- X if (write(out, buf, x) != x)
- X done();
- X c += x >> 2;
- X }
- X}
- X
- chkarg(arg)
- X char *arg;
- X{
- X int i;
- X char *a, *b;
- X
- X for (i = 0; cmds[i]; ++i) {
- X for (a = arg, b = cmds[i]; *a && *b && *a == *b; a++, b++)
- X ;
- X if (*a == '=')
- X return (0);
- X }
- X printf("Bad arg: %s\n", arg);
- X exit(1);
- X}
- X
- void
- done()
- X{
- X close(1);
- X open("/dev/tty", 1);
- X if (Sync > 0)
- X sync();
- X if (Fsync > 0)
- X fsync(out);
- X if (Flush > 0)
- X flush(out);
- X stop();
- X#ifndef SVR4
- X if (ru != -1)
- X rusage();
- X#endif
- X ptime(c << 2);
- X exit(0);
- X}
- X
- X#define secs(tv) (tv.tv_sec + tv.tv_usec / 1000000.0)
- X
- X#ifndef SVR4
- rusage()
- X{
- X struct rusage r;
- X double timespent();
- X double idle;
- X
- X getrusage(RUSAGE_SELF, &r);
- X idle = timespent() - (secs(r.ru_stime) + secs(r.ru_utime));
- X idle = idle / timespent() * 100;
- X printf("sys=%g user=%g stalled=%.0f%% rd=%d wr=%d min=%d maj=%d\n",
- X secs(r.ru_stime), secs(r.ru_utime),
- X idle, r.ru_inblock, r.ru_oublock,
- X r.ru_minflt, r.ru_majflt);
- X}
- X
- X#endif
- X
- getarg(s, ac, av)
- X char *s;
- X char **av;
- X{
- X register len, i;
- X
- X len = strlen(s);
- X
- X for (i = 1; i < ac; ++i)
- X if (!strncmp(av[i], s, len)) {
- X register bs = atoi(&av[i][len]);
- X
- X if (rindex(&av[i][len], 'k'))
- X bs *= 1024;
- X else if (rindex(&av[i][len], 'm'))
- X bs *= (1024 * 1024);
- X return (bs);
- X }
- X return (-1);
- X}
- X
- char *output;
- X
- getfile(s, ac, av)
- X char *s;
- X char **av;
- X{
- X register ret, len, i;
- X
- X len = strlen(s);
- X
- X for (i = 1; i < ac; ++i) {
- X if (!strncmp(av[i], s, len)) {
- X if (av[i][0] == 'o') {
- X if (!strcmp("of=internal", av[i]))
- X return (-2);
- X ret = creat(&av[i][len], 0644);
- X if (ret == -1)
- X error(&av[i][len]);
- X output = &av[i][len];
- X return (ret);
- X } else {
- X if (!strcmp("if=internal", av[i]))
- X return (-2);
- X ret = open(&av[i][len], 0);
- X if (ret == -1)
- X error(&av[i][len]);
- X return (ret);
- X }
- X }
- X }
- X return (-1);
- X}
- X
- X#ifdef FLUSH
- flush()
- X{
- X int fd;
- X struct stat sb;
- X caddr_t where;
- X
- X if (output == NULL || (fd = open(output, 2)) == -1)
- X return (warning("No output file"));
- X if (fstat(fd, &sb) == -1 || sb.st_size == 0)
- X return (warning(output));
- X where = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- X msync(where, sb.st_size, MS_INVALIDATE);
- X /* XXX - didn't unmap */
- X}
- X#endif
- X
- X/*
- X * utilities for timing
- X */
- X#include "stdio.h"
- X#include "sys/types.h"
- X#include "sys/time.h"
- X
- static struct timeval t1, t2;
- X
- warning(s)
- X char *s;
- X{
- X perror(s);
- X return (-1);
- X}
- X
- error(s)
- X char *s;
- X{
- X perror(s);
- X exit(1);
- X}
- X
- start() {
- X gettimeofday(&t1, (struct timezone *) 0);
- X}
- X
- stop() {
- X gettimeofday(&t2, (struct timezone *) 0);
- X}
- X
- ptime(bytes) {
- X ptransfer(bytes, &t1, &t2);
- X}
- double
- timespent()
- X{
- X struct timeval td;
- X
- X tvsub(&td, &t2, &t1);
- X return (td.tv_sec + (td.tv_usec / 1000000.) + STARTUP);
- X}
- X
- ptransfer(bytes, t0, t1)
- X struct timeval *t0, *t1;
- X{
- X struct timeval td;
- X float s, bs;
- X
- X tvsub(&td, t1, t0);
- X s = td.tv_sec + (td.tv_usec / 1000000.);
- X#define nz(x) ((x) == 0 ? 1 : (x))
- X#define MB (1024*1024.0)
- X bs = bytes / nz(s);
- X printf("%.2f MB in %.2f seconds (%.4f MB/sec)\n", bytes / MB, s, bs / MB);
- X}
- X
- tvsub(tdiff, t1, t0)
- X struct timeval *tdiff, *t1, *t0;
- X{
- X
- X tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
- X tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
- X if (tdiff->tv_usec < 0)
- X tdiff->tv_sec--, tdiff->tv_usec += 1000000;
- X}
- END_OF_FILE
- if test 6270 -ne `wc -c <'lmdd.c'`; then
- echo shar: \"'lmdd.c'\" unpacked with wrong size!
- fi
- # end of 'lmdd.c'
- fi
- if test -f 'ddperf' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ddperf'\"
- else
- echo shar: Extracting \"'ddperf'\" \(371 characters\)
- sed "s/^X//" >'ddperf' <<'END_OF_FILE'
- X#!/bin/sh
- X
- X#
- X# usage: ddperf mount_point
- X#
- X# test FSR, FSW
- X#
- doit()
- X{
- X umount $D
- X mount $D
- X $*
- X}
- X
- if [ X$1 != X ]
- then D=$1
- else D=/home
- fi
- X
- if [ X$2 != X ]
- then C=$2
- else C=1k
- fi
- X
- echo WRITES
- for i in 1 2 3 4
- do
- X lmdd if=internal of=$D/XXX count=$C rusage=1 fsync=1
- done
- echo READS
- for i in 1 2 3 4
- do
- X doit lmdd of=internal if=$D/XXX count=$C rusage=1 fsync=1
- done
- END_OF_FILE
- if test 371 -ne `wc -c <'ddperf'`; then
- echo shar: \"'ddperf'\" unpacked with wrong size!
- fi
- # end of 'ddperf'
- fi
- echo shar: End of shell archive.
- exit 0
-