home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / lmdd < prev    next >
Encoding:
Text File  |  1992-06-12  |  12.1 KB  |  577 lines

  1. Newsgroups: comp.sources.unix
  2. From: lm@slovax.Eng.Sun.COM (Larry McVoy)
  3. Subject: v26i061: lmdd - Trivial disk I/O performance tester - like dd
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: lm@slovax.Eng.Sun.COM (Larry McVoy)
  8. Posting-Number: Volume 26, Issue 61
  9. Archive-Name: lmdd
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of shell archive."
  18. # Contents:  lmdd.1 Makefile lmdd.c ddperf
  19. # Wrapped by vixie@cognition.pa.dec.com on Sat Jun 13 17:03:23 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'lmdd.1' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'lmdd.1'\"
  23. else
  24. echo shar: Extracting \"'lmdd.1'\" \(2809 characters\)
  25. sed "s/^X//" >'lmdd.1' <<'END_OF_FILE'
  26. X.\" @(#)lmdd.1    1.1 2/27/92
  27. X.TH LMDD 1 
  28. X.SH NAME
  29. lmdd \- move io for performance and debugging tests
  30. X.SH SYNOPSIS
  31. X.B lmdd
  32. X[
  33. X.IB option = value
  34. X] .\|.\|.
  35. X.SH DESCRIPTION
  36. X.B lmdd
  37. copies a specified input file to a specified output with possible
  38. conversions.  This program is primarily useful for timing I/O since it
  39. prints out the timing statistics after completing.
  40. X.SH OPTIONS
  41. X.TP 15
  42. X.BI if= name
  43. Input file is taken from
  44. X.IR name ;
  45. standard input is default.
  46. X.I internal
  47. is a special file that acts like Sun's 
  48. X.IR /dev/zero ,
  49. i.e., it provides a buffer of zeros without doing a system call to get them.
  50. X.TP 
  51. X.BI of= name
  52. Output file is taken from
  53. X.IR name ;
  54. standard output is default.  
  55. X.I internal
  56. is a special file that acts like 
  57. X.IR /dev/null ,
  58. without doing a system call to get rid of the data.
  59. X.TP 
  60. X.BI bs= n
  61. Input and output block size
  62. X.I n
  63. bytes (default 8192).  Note that this is different from dd(1), it has
  64. a 512 byte default.   Also note that the block size can be followed
  65. by 'k' or 'm' to indicate kilo bytes (*1024) or megabytes (*1024*1024),
  66. respectively.
  67. X.TP 
  68. X.BI ipat= n
  69. If 
  70. X.B n
  71. is non zero, expect a known pattern in the file (see opat).  Mismatches
  72. will be displayed as "ERROR: off=%d want=%x got=%x".  The pattern is
  73. a sequence of 4 byte integers with the first 0, second 1, and so on.
  74. The default is not to check for the pattern.
  75. X.TP
  76. X.BI opat= n
  77. If 
  78. X.B n
  79. is non zero, generate a known pattern on the output stream.  Used for
  80. debugging file system correctness.
  81. The default is not to generate the pattern.
  82. X.TP 
  83. X.BI mismatch= n
  84. If 
  85. X.B n
  86. is non zero, stop at the first mismatched value.  Used with ipat.
  87. X.TP 
  88. X.BI skip= n
  89. Skip
  90. X.IR n ""
  91. input blocks before starting copy.
  92. X.TP 
  93. X.BI fsync= n
  94. If
  95. X.I n
  96. is non-zero, call fsync(2) on the output file before exiting or printing
  97. timing statistics.
  98. X.TP 
  99. X.BI sync= n
  100. If
  101. X.I n
  102. is non-zero, call sync(2) before exiting or printing
  103. timing statistics.
  104. X.TP 
  105. X.BI flush= n
  106. If
  107. X.I n
  108. is non-zero and mmap(2) is available, call msync(2) to invalidate the
  109. output file.  This flushes the file to disk so that you don't have
  110. unmount/mount.  It is not as good as mount/unmount because it just
  111. flushes file pages - it misses the indirect blocks which are still
  112. cached.
  113. X.TP 
  114. X.BI rusage= n
  115. If
  116. X.I n
  117. is non-zero, print rusage statistics as well as timing statistics.
  118. X.TP 
  119. X.BI count= n
  120. Copy only
  121. X.IR n ""
  122. input records.
  123. X.SH EXAMPLES
  124. X.LP
  125. This is the most common usage, the intent is to measure disk performance.
  126. The disk is a spare partition mounted on /spare.
  127. X.sp
  128. X.nf
  129. X.in +4
  130. X# mount /spare
  131. X# lmdd if=internal of=/spare/XXX count=1000 fsync=1
  132. X7.81 MB in 3.78 seconds (2.0676 MB/sec)
  133. X
  134. X: Flush cache
  135. X# umount /spare
  136. X# mount /spare
  137. X
  138. X# lmdd if=/spare/XXX of=internal 
  139. X7.81 MB in 2.83 seconds (2.7611 MB/sec)
  140. X.in
  141. X.sp
  142. X.fi
  143. X.SH AUTHOR
  144. Larry McVoy, lm@sun.com
  145. X.br
  146. Not copyrighted.
  147. END_OF_FILE
  148. if test 2809 -ne `wc -c <'lmdd.1'`; then
  149.     echo shar: \"'lmdd.1'\" unpacked with wrong size!
  150. fi
  151. # end of 'lmdd.1'
  152. fi
  153. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  154.   echo shar: Will not clobber existing file \"'Makefile'\"
  155. else
  156. echo shar: Extracting \"'Makefile'\" \(315 characters\)
  157. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  158. DESTROOT=
  159. DESTPATH=$(DESTROOT)/usr/local
  160. X
  161. all: lmdd ddperf
  162. X
  163. lmdd: lmdd.o
  164. X    cc -o lmdd lmdd.o
  165. X
  166. ddperf: ddperf.sh
  167. X    cp ddperf.sh ddperf
  168. X    chmod +x ddperf
  169. X
  170. install:
  171. X    install -c -s lmdd   $(DESTPATH)/bin/lmdd
  172. X    install -c    lmdd.1 $(DESTPATH)/man/man1/lmdd.1
  173. X
  174. X# we don't install ddperf because it has no man page (vixie)
  175. X
  176. END_OF_FILE
  177. if test 315 -ne `wc -c <'Makefile'`; then
  178.     echo shar: \"'Makefile'\" unpacked with wrong size!
  179. fi
  180. # end of 'Makefile'
  181. fi
  182. if test -f 'lmdd.c' -a "${1}" != "-c" ; then 
  183.   echo shar: Will not clobber existing file \"'lmdd.c'\"
  184. else
  185. echo shar: Extracting \"'lmdd.c'\" \(6270 characters\)
  186. sed "s/^X//" >'lmdd.c' <<'END_OF_FILE'
  187. static char sccsid[] = "@(#)lmdd.c    1.7";
  188. X
  189. X/*
  190. X * lmdd, lm@sun.com (Larry McVoy)
  191. X *
  192. X * Uncopyrighted, do whatever you want with it.
  193. X *
  194. X * defaults:
  195. X *    bs=8k
  196. X *    count=forever
  197. X *    if=stdin
  198. X *    of=stdout
  199. X *    ipat=0
  200. X *    opat=0
  201. X *    mismatch=0
  202. X *    rusage=0
  203. X *    flush=0
  204. X * shorthands:
  205. X *    recognizes 'k' or 'm' at the end of a number for 1024 & 1024^2
  206. X *    recognizes "internal" as an internal /dev/zero /dev/null file.
  207. X */
  208. X#include <signal.h>
  209. X#include <sys/types.h>
  210. X#include <sys/time.h>
  211. X#ifndef    SVR4
  212. X#include <sys/resource.h>
  213. X#endif
  214. X#define    FLUSH
  215. X#ifdef    FLUSH
  216. X#include <unistd.h>
  217. X#include <sys/mman.h>
  218. X#include <sys/stat.h>
  219. X#endif
  220. X#define    STARTUP        (.11)    /* XXX - about how long before it starts
  221. X                 * working.  So time matches w/ rusage. This is
  222. X                 * close on a 20Mhz SS. */
  223. X#define    uchar    unsigned char
  224. X
  225. int     out, Fsync, Sync, Flush, ru, c;/* done needs it */
  226. char   *cmds[] = {
  227. X    "if",            /* input file */
  228. X    "of",            /* output file */
  229. X    "ipat",            /* check input for pattern */
  230. X    "opat",            /* generate pattern on output */
  231. X    "mismatch",        /* stop at first mismatch */
  232. X    "bs",            /* block size */
  233. X    "count",        /* number of blocks */
  234. X    "skip",            /* skip this number of blocks on input */
  235. X    "fsync",        /* fsync output before exit */
  236. X    "sync",            /* sync output before exit */
  237. X    "rusage",        /* dump rusage stats */
  238. X#ifdef    FLUSH
  239. X    "flush",        /* map in out and invalidate (flush) */
  240. X#endif
  241. X    0,
  242. X};
  243. X
  244. main(ac, av)
  245. X    char  **av;
  246. X{
  247. X    uint  *buf;
  248. X    int     misses, mismatch, outpat, inpat, bs, in, gotcnt, count;
  249. X    int     skip;
  250. X    extern char *valloc();
  251. X    void    done();
  252. X    int     i;
  253. X
  254. X    for (i = 1; i < ac; ++i) {
  255. X        chkarg(av[i]);
  256. X    }
  257. X    misses = mismatch = getarg("mismatch=", ac, av);
  258. X    inpat = getarg("ipat=", ac, av);
  259. X    outpat = getarg("opat=", ac, av);
  260. X    in = getfile("if=", ac, av);
  261. X    if (in == -1)
  262. X        in = 0;
  263. X    out = getfile("of=", ac, av);
  264. X    if (out == -1)
  265. X        out = 1;
  266. X    bs = getarg("bs=", ac, av);
  267. X    if (bs < 0)
  268. X        bs = 8192;
  269. X    Fsync = getarg("fsync=", ac, av);
  270. X    Sync = getarg("sync=", ac, av);
  271. X    ru = getarg("rusage=", ac, av);
  272. X    count = getarg("count=", ac, av);
  273. X    Flush = getarg("flush=", ac, av);
  274. X    if (count < 0)
  275. X        gotcnt = 0;
  276. X    else
  277. X        gotcnt = 1;
  278. X    c = 0;
  279. X    skip = getarg("skip=", ac, av);
  280. X
  281. X    if (inpat != -1 || outpat != -1 && (bs & 3)) {
  282. X        printf("Block size must be word aligned\n");
  283. X        exit(1);
  284. X    }
  285. X    if (!(buf = (uint *) valloc((unsigned) bs))) {
  286. X        perror("valloc");
  287. X        exit(1);
  288. X    }
  289. X    bzero((char *) buf, bs);
  290. X
  291. X    signal(SIGINT, done);
  292. X    if (skip > 0)
  293. X        lseek(in, skip * bs, 0);
  294. X    start();
  295. X    for (;;) {
  296. X        register x;
  297. X
  298. X        if (gotcnt && count-- <= 0)
  299. X            done();
  300. X        if (in >= 0)
  301. X            x = read(in, buf, bs);
  302. X        else
  303. X            x = bs;
  304. X        if (x <= 0)
  305. X            done();
  306. X        if (inpat != -1) {
  307. X            register foo, cnt;
  308. X
  309. X            for (foo = 0, cnt = x >> 2; cnt--; foo++) {
  310. X                if (buf[foo] != (uint) (c + foo)) {
  311. X                    printf("ERROR: off=%d want=%x got=%x\n",
  312. X                        c + foo, c + foo, buf[foo]);
  313. X                    if (mismatch != -1 && --misses == 0)
  314. X                        done();
  315. X                }
  316. X            }
  317. X        }
  318. X        if (outpat != -1) {
  319. X            register foo, cnt;
  320. X
  321. X            for (foo = 0, cnt = x >> 2; cnt--; foo++)
  322. X                buf[foo] = c + foo;
  323. X        }
  324. X        if (out >= 0)
  325. X            if (write(out, buf, x) != x)
  326. X                done();
  327. X        c += x >> 2;
  328. X    }
  329. X}
  330. X
  331. chkarg(arg)
  332. X    char    *arg;
  333. X{
  334. X    int    i;
  335. X    char    *a, *b;
  336. X
  337. X    for (i = 0; cmds[i]; ++i) {
  338. X        for (a = arg, b = cmds[i]; *a && *b && *a == *b; a++, b++)
  339. X            ;
  340. X        if (*a == '=')
  341. X            return (0);
  342. X    }
  343. X    printf("Bad arg: %s\n", arg);
  344. X    exit(1);
  345. X}
  346. X
  347. void
  348. done()
  349. X{
  350. X    close(1);
  351. X    open("/dev/tty", 1);
  352. X    if (Sync > 0)
  353. X        sync();
  354. X    if (Fsync > 0)
  355. X        fsync(out);
  356. X    if (Flush > 0)
  357. X        flush(out);
  358. X    stop();
  359. X#ifndef    SVR4
  360. X    if (ru != -1)
  361. X        rusage();
  362. X#endif
  363. X    ptime(c << 2);
  364. X    exit(0);
  365. X}
  366. X
  367. X#define    secs(tv)    (tv.tv_sec + tv.tv_usec / 1000000.0)
  368. X
  369. X#ifndef    SVR4
  370. rusage()
  371. X{
  372. X    struct rusage r;
  373. X    double  timespent();
  374. X    double  idle;
  375. X
  376. X    getrusage(RUSAGE_SELF, &r);
  377. X    idle = timespent() - (secs(r.ru_stime) + secs(r.ru_utime));
  378. X    idle = idle / timespent() * 100;
  379. X    printf("sys=%g user=%g stalled=%.0f%% rd=%d wr=%d min=%d maj=%d\n",
  380. X        secs(r.ru_stime), secs(r.ru_utime),
  381. X        idle, r.ru_inblock, r.ru_oublock,
  382. X        r.ru_minflt, r.ru_majflt);
  383. X}
  384. X
  385. X#endif
  386. X
  387. getarg(s, ac, av)
  388. X    char   *s;
  389. X    char  **av;
  390. X{
  391. X    register len, i;
  392. X
  393. X    len = strlen(s);
  394. X
  395. X    for (i = 1; i < ac; ++i)
  396. X        if (!strncmp(av[i], s, len)) {
  397. X            register bs = atoi(&av[i][len]);
  398. X
  399. X            if (rindex(&av[i][len], 'k'))
  400. X                bs *= 1024;
  401. X            else if (rindex(&av[i][len], 'm'))
  402. X                bs *= (1024 * 1024);
  403. X            return (bs);
  404. X        }
  405. X    return (-1);
  406. X}
  407. X
  408. char    *output;
  409. X
  410. getfile(s, ac, av)
  411. X    char   *s;
  412. X    char  **av;
  413. X{
  414. X    register ret, len, i;
  415. X
  416. X    len = strlen(s);
  417. X
  418. X    for (i = 1; i < ac; ++i) {
  419. X        if (!strncmp(av[i], s, len)) {
  420. X            if (av[i][0] == 'o') {
  421. X                if (!strcmp("of=internal", av[i]))
  422. X                    return (-2);
  423. X                ret = creat(&av[i][len], 0644);
  424. X                if (ret == -1)
  425. X                    error(&av[i][len]);
  426. X                output = &av[i][len];
  427. X                return (ret);
  428. X            } else {
  429. X                if (!strcmp("if=internal", av[i]))
  430. X                    return (-2);
  431. X                ret = open(&av[i][len], 0);
  432. X                if (ret == -1)
  433. X                    error(&av[i][len]);
  434. X                return (ret);
  435. X            }
  436. X        }
  437. X    }
  438. X    return (-1);
  439. X}
  440. X
  441. X#ifdef    FLUSH
  442. flush()
  443. X{
  444. X    int    fd;
  445. X    struct    stat sb;
  446. X    caddr_t    where;
  447. X
  448. X    if (output == NULL || (fd = open(output, 2)) == -1) 
  449. X        return (warning("No output file"));
  450. X    if (fstat(fd, &sb) == -1 || sb.st_size == 0)
  451. X        return (warning(output));
  452. X    where = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  453. X    msync(where, sb.st_size, MS_INVALIDATE);
  454. X    /* XXX - didn't unmap */
  455. X}
  456. X#endif
  457. X
  458. X/*
  459. X * utilities for timing
  460. X */
  461. X#include "stdio.h"
  462. X#include "sys/types.h"
  463. X#include "sys/time.h"
  464. X
  465. static struct timeval t1, t2;
  466. X
  467. warning(s)
  468. X    char   *s;
  469. X{
  470. X    perror(s);
  471. X    return (-1);
  472. X}
  473. X
  474. error(s)
  475. X    char   *s;
  476. X{
  477. X    perror(s);
  478. X    exit(1);
  479. X}
  480. X
  481. start() {
  482. X    gettimeofday(&t1, (struct timezone *) 0);
  483. X}
  484. X
  485. stop() {
  486. X    gettimeofday(&t2, (struct timezone *) 0);
  487. X}
  488. X
  489. ptime(bytes) {
  490. X    ptransfer(bytes, &t1, &t2);
  491. X}
  492. double 
  493. timespent()
  494. X{
  495. X    struct timeval td;
  496. X
  497. X    tvsub(&td, &t2, &t1);
  498. X    return (td.tv_sec + (td.tv_usec / 1000000.) + STARTUP);
  499. X}
  500. X
  501. ptransfer(bytes, t0, t1)
  502. X    struct timeval *t0, *t1;
  503. X{
  504. X    struct timeval td;
  505. X    float   s, bs;
  506. X
  507. X    tvsub(&td, t1, t0);
  508. X    s = td.tv_sec + (td.tv_usec / 1000000.);
  509. X#define    nz(x)    ((x) == 0 ? 1 : (x))
  510. X#define    MB    (1024*1024.0)
  511. X    bs = bytes / nz(s);
  512. X    printf("%.2f MB in %.2f seconds (%.4f MB/sec)\n", bytes / MB, s, bs / MB);
  513. X}
  514. X
  515. tvsub(tdiff, t1, t0)
  516. X    struct timeval *tdiff, *t1, *t0;
  517. X{
  518. X
  519. X    tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  520. X    tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  521. X    if (tdiff->tv_usec < 0)
  522. X        tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  523. X}
  524. END_OF_FILE
  525. if test 6270 -ne `wc -c <'lmdd.c'`; then
  526.     echo shar: \"'lmdd.c'\" unpacked with wrong size!
  527. fi
  528. # end of 'lmdd.c'
  529. fi
  530. if test -f 'ddperf' -a "${1}" != "-c" ; then 
  531.   echo shar: Will not clobber existing file \"'ddperf'\"
  532. else
  533. echo shar: Extracting \"'ddperf'\" \(371 characters\)
  534. sed "s/^X//" >'ddperf' <<'END_OF_FILE'
  535. X#!/bin/sh
  536. X
  537. X#
  538. X# usage: ddperf mount_point
  539. X#
  540. X# test FSR, FSW
  541. X#
  542. doit()
  543. X{
  544. X    umount $D
  545. X    mount $D
  546. X    $*
  547. X}
  548. X
  549. if [ X$1 != X ]
  550. then    D=$1
  551. else    D=/home
  552. fi
  553. X
  554. if [ X$2 != X ]
  555. then    C=$2
  556. else    C=1k
  557. fi
  558. X
  559. echo WRITES
  560. for i in 1 2 3 4
  561. do     
  562. X    lmdd if=internal of=$D/XXX count=$C rusage=1 fsync=1
  563. done
  564. echo READS
  565. for i in 1 2 3 4
  566. do     
  567. X    doit lmdd of=internal if=$D/XXX count=$C rusage=1 fsync=1
  568. done
  569. END_OF_FILE
  570. if test 371 -ne `wc -c <'ddperf'`; then
  571.     echo shar: \"'ddperf'\" unpacked with wrong size!
  572. fi
  573. # end of 'ddperf'
  574. fi
  575. echo shar: End of shell archive.
  576. exit 0
  577.