home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / sys / sun / admin / 6016 < prev    next >
Encoding:
Text File  |  1992-09-01  |  28.4 KB  |  854 lines

  1. Newsgroups: comp.sys.sun.admin
  2. Path: sparky!uunet!mcsun!Germany.EU.net!news.uni-bielefeld.de!techfak.uni-bielefeld.de!malte
  3. From: malte@techfak.uni-bielefeld.de (Malte Uhl)
  4. Subject: Re: Format.dat for Fujitsu M2266SA .
  5. Sender: news@unibi.uni-bielefeld.de (News Administrator)
  6. Message-ID: <1992Sep1.152633.24901@unibi.uni-bielefeld.de>
  7. Date: Tue, 1 Sep 92 15:26:33 GMT
  8. References: <3028@accucx.cc.ruu.nl> <1992Aug31.041349.4224@cssc-syd.tansu.com.au> <1992Aug31.113553.13293@unibi.uni-bielefeld.de> <1992Sep1.105302.6829@cbnewsi.cb.att.com>
  9. Nntp-Posting-Host: dahlie.techfak.uni-bielefeld.de
  10. Organization: Universitaet Bielefeld, Technische Fakultaet.
  11. Keywords: format.dat ; FUJITSU ; M2266SA
  12. Lines: 840
  13.  
  14. In article <1992Sep1.105302.6829@cbnewsi.cb.att.com>, adh@cbnewsi.cb.att.com (andrew.d.hay) writes:
  15. |> "I tried the FAQ one here, but using the bonnie diskio test the factory
  16. |> "supplied format entry gives the best performance.
  17. |> "
  18. |> 
  19. |> i'd like to know more about this diskio test thing...
  20. |> 
  21.  
  22. This was surely posted in some comp.whatever.sources group, but here it is
  23. again:
  24. It compiles cleanly under a BSD variant, and with little tweaking under
  25. SYSV and Solaris 2.
  26.  
  27. -------------------------------------------------------------------------------
  28.  
  29. From: Tim Bray <tbray@watsol.waterloo.edu>
  30.  
  31. Here is a benchmark named 'bonnie'; my own creation, it has since been
  32. written up in Unix Today, is under investigation by DR Labs, and has
  33. been around the usenet a couple of times.  I'm currently collating
  34. results from around the world.  If you decide to keep this one around,
  35. I'll send those in as they become available.
  36.  
  37. This is the original posting from comp.arch
  38. --------------------------------------------------
  39. A couple of months back, I posted a program named fsx, which purported to
  40. benchmark performance of various aspects of Unix filesystems.  I got a *lot*
  41. of mail from people, which fell into the following equivalence classes:
  42.  
  43.  1. Thank you
  44.  2. Here are the numbers for our new whizbang mark X
  45.  3. Not bad, but you forgot Y
  46.  4. The whole idea is totally bankrupt because of Z
  47.  5. There's an obvious bug in your program (this was true; there was an
  48.     obvious bug, thankfully of the blow-you-up rather than distort-the-results
  49.     type.  Amazing, the number of systems it worked on).
  50.  
  51. Eventually, I was convinced that it was worthwhile to go back and work on
  52. improving it.  Herewith the results, containing:
  53.  
  54. 1. Changes from the first version of the program.
  55. 2. Summary of discussion following that posting, and some soapboxing,
  56. 3. A summary of a few results; not nearly as good as the first summary,
  57.    even though the program is better; the reason is explained, and a proposal
  58.    made for the future.
  59. 4. The source code
  60. 5. The source code for an ancillary program contributed by someone out there.
  61.  
  62. 1. CHANGES
  63.  
  64. The name's changed.  Someone at DEC not only stole the name fsx from me, but
  65. did it some years before I invented it.  The nerve.  It's now called Bonnie,
  66. because it plays with bottlenecks.
  67.  
  68. The obvious bug is fixed.
  69.  
  70. It no longer uses BUFSIZ.  I thought using BUFSIZ was sort of defensible,
  71. since it's not unreasonable to use that in an application and expect that to
  72. be a pretty good size for filesystem I/O, but I succumbed to the shouting-down
  73. on this one.
  74.  
  75. There's a few more tweaks aimed at defeating compiler optimizers.
  76.  
  77. The seek testing, in attempt to further improve its cache-busting
  78. effectiveness, takes a multiprocess approach now.
  79.  
  80. The output format is better.
  81.  
  82. 2. DISCUSSION AND PREACHING
  83.  
  84. From the feedback to the last posting:
  85.  
  86. From: mo@messy.UUCP (Michael O'Dell)
  87. >Note: the combination of disk and controllers used for these tests
  88. >can make a LOT of difference in the performance.
  89. >Your mileage can vary an astonishing amount.
  90. Right, that's why it exists.
  91.  
  92. From: haas@frith.uucp (Paul R. Haas)
  93. >Remember, this sort of benchmark result is worthless if you don't report
  94. >the model, operating system version, disk controller, disk drive
  95. >type, and configuration information (asynch, or synch SCSI, block size,
  96. >etc...).
  97. Amen, amen, amen.
  98.  
  99. From: mash@mips.COM (John Mashey)
  100. >If there is enough CPU performance to seek the disk
  101. >at full speed, it is irrelevant how much faster it is: the benchmark
  102. >doesn't get faster.  Put another way, on single-threaded kinds of benchmarks,
  103. >the only thing that counts is whatever is the bottleneck.
  104. Right on.  Bonnie still shows CPU-limited I/O on a few classes of bottleneck,
  105. even on fast systems.  I suspect this will be less and less the case as time
  106. goes by, but it's interesting.
  107.  
  108. >3) However, note that the random benchmark doesn't read the same amount of
  109. >data on each machine, as it uses BUFSIZ from stdio.h, and that
  110. OK, OK, OK.
  111.  
  112. > a) Even trying hard, (and Tim was) it is hard to do I/O benchmarks without
  113. > weird quirks.  In particular, you are constantly fighting to outsmart the
  114. > UNIX buffer cache (or whatever it uses).
  115. Right.  And that's why it would be foolish and wrong to try to distill
  116. Bonnie's results into a single number & call it an fs-stone or something.  All
  117. you can do is try to establish deterministic limits for certain capabilities
  118. in certain environments.  Which is much better than operating in a vacuum.  I
  119. claim that Bonnie does a good enough job of this to be useful.
  120.  
  121. From: lm@snafu.Sun.COM (Larry McVoy)
  122. >Another comment on Tim's test and I/O tests in general  (check out Hennessy
  123. >& Patterson's chapter on I/O - they say this better than I do):  the
  124. >performance of I/O is going to be limited by the slowest part of the path,
  125. >be it memory, processor, software, I/O bus, or I/O device.
  126. >
  127. >That said, it's my belief that the IBM numbers are apples to oranges.  The
  128. >drives that IBM puts in the 6000 are *FAST*.
  129. Yes and No.  The first comment is correct.  The second is questionable; IBM is
  130. selling boxes with fairly similar functionality in a fairly similar price
  131. range to everybody else.  Bonnie's results suggest that this machine achieves
  132. remarkable I/O performance.  Where are the apples & oranges?
  133.  
  134. From: cdinges@estevax (Hr Dinges Clemens )
  135. >Proposal:
  136. >'fsx' should be expanded for measuring the reorganization features
  137. >of the filesystem, espec. the effects of a certain number of predefined file 
  138. >creation/write/deletion operations that simulate the use of the filesystem.
  139. >A known effect (SysV filesystems) is the disordering of the freelist 
  140. >entries which might greatly affect the performance of sequential filesystem 
  141. >operations (see below).
  142. >In other words, benchmarking with 'fsx' should always be done like that:
  143. >1. Generate a fresh filesystem; 2. simulate the use of the filesystem; 
  144. >3. run the benchmark.
  145. >To illustrate the effects of freelist disordering we ran fsx with and 
  146. >without a (very) simple freelist scrambler on the XENIX V/386 2.3.2
  147. >filesystem.
  148. Good idea.  The code of the scrambler is appended.  I would point out Bonnie
  149. might also provide a metric for the effects of many other tunable and
  150. hard-wired filesystem parameters.
  151.  
  152. From: kcollins@convex1.convex.com (Kirby L. Collins)
  153. >What we've found is that on large systems UNIX filesystem performance is
  154. >usually CPU bound.  This has several interesting ramifications.
  155. You bet.  It's sort of disappointing that this is still the case given the
  156. iron we're using now.
  157.  
  158. 3. SUMMARIES AND PROPOSALS
  159.  
  160. Here are some Bonnie results.  Unfortunately, it's end of term here, and I
  161. had great trouble finding machines with hundreds of Mb free, and even more
  162. important, with unloaded CPUs.  Therefore, I deliberately omit all details of
  163. disk type, OS version and so on, along with discussion.  These are mostly
  164. there to provide a sample of Bonnie output and perhaps provoke thought.  
  165.  
  166. I don't have time to run this any more.  That is a job for the vendors and for
  167. SPEC and so on.  However, I will cheerfully act as a clearinghouse for Bonnie
  168. results, bugfixes, improvements and so on, and if lots of results come in,
  169. will post them occasionally.
  170.  
  171.               -------Sequential Output-------- ---Sequential Input-- --Random--
  172.               -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
  173. Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
  174. Sun4/260   78   285 90.9   650 26.4   305 20.0   282 95.5   803 28.3  38.5 15.2
  175. Mips M2k  180   387 44.0   442  6.1   360  5.4   416 48.1  1701 14.8  26.3  3.1
  176. Sequent    95   140 97.8  1017 66.2   251 17.7   122 95.7   713 34.9  31.0 15.9
  177. 4M i386    25   130 90.5   199 26.1   179 46.1   121 93.5   400 59.7  10.5 23.8
  178. NeXT      125   241 94.7   347 39.3   253 31.7   246 94.8   772 49.6  27.7 20.8
  179. VAX 8650  200   208 89.0   232  8.3   143  7.4   197 65.0   373  8.6  17.3  4.6
  180.  
  181. 4. SOURCE CODE 
  182.  
  183. ---bonnie.c starts---------------
  184. /*
  185.  * This is a file system benchmark which attempts to study bottlenecks -
  186.  * it is named 'Bonnie' for semi-obvious reasons.
  187.  *
  188.  * Specifically, these are the types of filesystem activity that have been
  189.  * observed to be bottlenecks in I/O-intensive applications, in particular
  190.  * the text database work done in connection with the New Oxford English
  191.  * Dictionary Project at the University of Waterloo.
  192.  * 
  193.  * It performs a series of tests on a file of known size.  By default, that
  194.  * size is 100 Mb (but that's not enough - see below).  For each test, Bonnie 
  195.  * reports the bytes processed per elapsed second, per CPU second, and the 
  196.  * % CPU usage (user and system).
  197.  * 
  198.  * In each case, an attempt is made to keep optimizers from noticing it's 
  199.  * all bogus.  The idea is to make sure that these are real transfers to/from
  200.  * user space to the physical disk.  The tests are:
  201.  * 
  202.  * 1. Sequential Output
  203.  * 
  204.  * 1.1 Per-Character.  The file is written using the putc() stdio macro.
  205.  * The loop that does the writing should be small enough to fit into any
  206.  * reasonable I-cache.  The CPU overhead here is that required to do the
  207.  * stdio code plus the OS file space allocation.
  208.  * 
  209.  * 1.2 Block.  The file is created using write(2).  The CPU overhead
  210.  * should be just the OS file space allocation.
  211.  * 
  212.  * 1.3 Rewrite.  Each BUFSIZ of the file is read with read(2), dirtied, and
  213.  * rewritten with write(2), requiring an lseek(2).  Since no space
  214.  * allocation is done, and the I/O is well-localized, this should test the
  215.  * effectiveness of the filesystem cache and the speed of data transfer.
  216.  * 
  217.  * 2. Sequential Input
  218.  * 
  219.  * 2.1 Per-Character.  The file is read using the getc() stdio macro.  Once
  220.  * again, the inner loop is small.  This should exercise only stdio and
  221.  * sequential input.
  222.  * 
  223.  * 2.2 Block.  The file is read using read(2).  This should be a very pure
  224.  * test of sequential input performance.
  225.  * 
  226.  * 3. Random Seeks
  227.  * 
  228.  * This test runs SeekProcCount processes in parallel, doing a total of
  229.  * 4000 lseek()s to locations in the file specified by random() in bsd systems,
  230.  * drand48() on sysV systems.  In each case, the block is read with read(2).  
  231.  * In 10% of cases, it is dirtied and written back with write(2).
  232.  *
  233.  * The idea behind the SeekProcCount processes is to make sure there's always 
  234.  * a seek queued up.
  235.  * 
  236.  * AXIOM: For any unix filesystem, the effective number of lseek(2) calls
  237.  * per second declines asymptotically to near 30, once the effect of
  238.  * caching is defeated.
  239.  * 
  240.  * The size of the file has a strong nonlinear effect on the results of
  241.  * this test.  Many Unix systems that have the memory available will make
  242.  * aggressive efforts to cache the whole thing, and report random I/O rates
  243.  * in the thousands per second, which is ridiculous.  As an extreme
  244.  * example, an IBM RISC 6000 with 64 Mb of memory reported 3,722 per second
  245.  * on a 50 Mb file.  Some have argued that bypassing the cache is artificial
  246.  * since the cache is just doing what it's designed to.  True, but in any 
  247.  * application that requires rapid random access to file(s) significantly
  248.  * larger than main memory which is running on a system which is doing
  249.  * significant other work, the caches will inevitably max out.  There is
  250.  * a hard limit hiding behind the cache which has been observed by the
  251.  * author to be of significant import in many situations - what we are trying
  252.  * to do here is measure that number.
  253.  *
  254.  * COPYRIGHT NOTICE: 
  255.  * Copyright (c) Tim Bray, 1990.
  256.  * Everybody is hereby granted rights to use, copy, and modify this program, 
  257.  *  provided only that this copyright notice and the disclaimer below
  258.  *  are preserved without change.
  259.  * DISCLAIMER:
  260.  * This program is provided AS IS with no warranty of any kind, and
  261.  * The author makes no representation with respect to the adequacy of this
  262.  *  program for any particular purpose or with respect to its adequacy to 
  263.  *  produce any particular result, and
  264.  * The author shall not be liable for loss or damage arising out of
  265.  *  the use of this program regardless of how sustained, and
  266.  * In no event shall the author be liable for special, direct, indirect
  267.  *  or consequential damage, loss, costs or fees or expenses of any
  268.  *  nature or kind.
  269.  */
  270.  
  271. #include <stdio.h>
  272. #include <fcntl.h>
  273. #include <sys/types.h>
  274. #include <sys/time.h>
  275. #ifdef SysV
  276. #include <limits.h>
  277. #include <sys/times.h>
  278. #else
  279. #include <sys/resource.h>
  280. #endif
  281.  
  282. #define IntSize (4)
  283.  
  284. /*
  285.  * N.B. in seeker_reports, CPU appears and Start/End time, but not Elapsed,
  286.  *  so position 1 is re-used; icky data coupling.
  287.  */
  288. #define CPU (0)
  289. #define Elapsed (1)
  290. #define StartTime (1)
  291. #define EndTime (2)
  292. #define Seeks (4000)
  293. #define UpdateSeek (10)
  294. #define SeekProcCount (3)
  295. #define Chunk (8192)
  296.  
  297. static double cpu_so_far();
  298. static void   doseek();
  299. static void   get_delta_t();
  300. static void   io_error();
  301. static void   newfile();
  302. #ifdef SysV
  303. static long   random();
  304. static void   srandom();
  305. #endif
  306. static void   report();
  307. static double time_so_far();
  308. static void   timestamp();
  309. static void   usage();
  310.  
  311. typedef enum
  312. {
  313.   Putc,
  314.   ReWrite,
  315.   FastWrite,
  316.   Getc,
  317.   FastRead,
  318.   Lseek,
  319.   TestCount
  320. } tests_t;
  321.  
  322. static int    basetime;
  323. static double delta[(int) TestCount][2];
  324. static char * machine = "";
  325. static double last_cpustamp = 0.0;
  326. static double last_timestamp = 0.0;
  327.  
  328. main(argc, argv)
  329.   int    argc;
  330.   char * argv[];
  331. {
  332.   int    buf[Chunk / IntSize];
  333.   int    bufindex;
  334.   int    chars[256];
  335.   int    child;
  336.   char * dir;
  337.   int    fd;
  338.   double first_start;
  339.   double last_stop;
  340.   int    lseek_count = 0;
  341.   char   name[Chunk];
  342.   int    next;
  343.   int    seek_control[2];
  344.   int    seek_feedback[2];
  345.   char   seek_tickets[Seeks + SeekProcCount];
  346.   double seeker_report[3];
  347.   int    size;
  348.   FILE * stream;
  349.   int    words;
  350.  
  351.   fd = -1;
  352.   basetime = (int) time((time_t *) NULL);
  353.   size = 100;
  354.   dir = ".";
  355.  
  356.   for (next = 1; next < argc - 1; next++)
  357.     if (argv[next][0] == '-')
  358.     { /* option? */
  359.       if (strcmp(argv[next] + 1, "d") == 0)
  360.         dir = argv[next + 1];
  361.       else if (strcmp(argv[next] + 1, "s") == 0)
  362.         size = atoi(argv[next + 1]);
  363.       else if (strcmp(argv[next] + 1, "m") == 0)
  364.         machine = argv[next + 1];
  365.       else
  366.         usage();
  367.       next++;
  368.     } /* option? */
  369.     else
  370.       usage();
  371.  
  372.   if (size < 1)
  373.     usage();
  374.   size *= (1024 * 1024);
  375.   sprintf(name, "%s/Bonnie.%d", dir, getpid());
  376.   fprintf(stderr, "File '%s', size: %d\n", name, size);
  377.  
  378.   /* Fill up a file, writing it a char at a time with the stdio putc() call */
  379.   fprintf(stderr, "Writing with putc()...");
  380.   newfile(name, &fd, &stream, 1);
  381.   timestamp();
  382.   for (words = 0; words < size; words++)
  383.     if (putc(words & 0x7f, stream) == EOF)
  384.       io_error("putc");
  385.   
  386.   /*
  387.    * note that we always close the file before measuring time, in an
  388.    *  effort to force as much of the I/O out as we can
  389.    */
  390.   if (fclose(stream) == -1)
  391.     io_error("fclose after putc");
  392.   get_delta_t(Putc);
  393.   fprintf(stderr, "done\n");
  394.  
  395.   /* Now read & rewrite it using block I/O.  Dirty one word in each block */
  396.   newfile(name, &fd, &stream, 0);
  397.   if (lseek(fd, (off_t) 0, 0) == (off_t) -1)
  398.     io_error("lseek(2) before rewrite");
  399.   fprintf(stderr, "Rewriting...");
  400.   timestamp();
  401.   bufindex = 0;
  402.   if ((words = read(fd, (char *) buf, Chunk)) == -1)
  403.     io_error("rewrite read");
  404.   while (words == Chunk)
  405.   { /* while we can read a block */
  406.     if (bufindex == Chunk / IntSize)
  407.       bufindex = 0;
  408.     buf[bufindex++]++;
  409.     if (lseek(fd, (off_t) -words, 1) == -1)
  410.       io_error("relative lseek(2)");
  411.     if (write(fd, (char *) buf, words) == -1)
  412.       io_error("re write(2)");
  413.     if ((words = read(fd, (char *) buf, Chunk)) == -1)
  414.       io_error("rwrite read");
  415.   } /* while we can read a block */
  416.   if (close(fd) == -1)
  417.     io_error("close after rewrite");
  418.   get_delta_t(ReWrite);
  419.   fprintf(stderr, "done\n");
  420.  
  421.   /* Write the whole file from scratch, again, with block I/O */
  422.   newfile(name, &fd, &stream, 1);
  423.   fprintf(stderr, "Writing intelligently...");
  424.   for (words = 0; words < Chunk / IntSize; words++)
  425.     buf[words] = 0;
  426.   timestamp();
  427.   for (words = bufindex = 0; words < (size / Chunk); words++)
  428.   { /* for each word */
  429.     if (bufindex == (Chunk / IntSize))
  430.       bufindex = 0;
  431.     buf[bufindex++]++;
  432.     if (write(fd, (char *) buf, Chunk) == -1)
  433.       io_error("write(2)");
  434.   } /* for each word */
  435.   if (close(fd) == -1)
  436.     io_error("close after fast write");
  437.   get_delta_t(FastWrite);
  438.   fprintf(stderr, "done\n");
  439.  
  440.   /* read them all back with getc() */
  441.   newfile(name, &fd, &stream, 0);
  442.   for (words = 0; words < 256; words++)
  443.     chars[words] = 0;
  444.   fprintf(stderr, "Reading with getc()...");
  445.   timestamp();
  446.   for (words = 0; words < size; words++)
  447.   { /* for each byte */
  448.     if ((next = getc(stream)) == EOF)
  449.       io_error("getc(3)");
  450.  
  451.     /* just to fool optimizers */
  452.     chars[next]++;
  453.   } /* for each byte */
  454.   if (fclose(stream) == -1)
  455.     io_error("fclose after getc");
  456.   get_delta_t(Getc);
  457.   fprintf(stderr, "done\n");
  458.  
  459.   /* use the frequency count */
  460.   for (words = 0; words < 256; words++)
  461.     sprintf((char *) buf, "%d", chars[words]);
  462.  
  463.   /* Now suck it in, Chunk at a time, as fast as we can */
  464.   newfile(name, &fd, &stream, 0);
  465.   if (lseek(fd, (off_t) 0, 0) == -1)
  466.     io_error("lseek before read");
  467.   fprintf(stderr, "Reading intelligently...");
  468.   timestamp();
  469.   do
  470.   { /* per block */
  471.     if ((words = read(fd, (char *) buf, Chunk)) == -1)
  472.       io_error("read(2)");
  473.     chars[buf[abs(buf[0]) % (Chunk / IntSize)] & 0x7f]++;
  474.   } /* per block */
  475.   while (words);
  476.   if (close(fd) == -1)
  477.     io_error("close after read");
  478.   get_delta_t(FastRead);
  479.   fprintf(stderr, "done\n");
  480.  
  481.   /* use the frequency count */
  482.   for (words = 0; words < 256; words++)
  483.     sprintf((char *) buf, "%d", chars[words]);
  484.  
  485.   /*
  486.    * Now test random seeks; first, set up for communicating with children.
  487.    * The object of the game is to do "Seeks" lseek() calls as quickly
  488.    *  as possible.  So we'll farm them out among SeekProcCount processes.
  489.    *  We'll control them by writing 1-byte tickets down a pipe which
  490.    *  the children all read.  We write "Seeks" bytes with val 1, whichever
  491.    *  child happens to get them does it and the right number of seeks get
  492.    *  done.
  493.    * The idea is that since the write() of the tickets is probably
  494.    *  atomic, the parent process likely won't get scheduled while the
  495.    *  children are seeking away.  If you draw a picture of the likely
  496.    *  timelines for three children, it seems likely that the seeks will
  497.    *  overlap very nicely with the process scheduling with the effect
  498.    *  that there will *always* be a seek() outstanding on the file.
  499.    * Question: should the file be opened *before* the fork, so that
  500.    *  all the children are lseeking on the same underlying file object?
  501.    */
  502.   if (pipe(seek_feedback) == -1 || pipe(seek_control) == -1)
  503.     io_error("pipe");
  504.   for (next = 0; next < Seeks; next++)
  505.     seek_tickets[next] = 1;
  506.   for ( ; next < (Seeks + SeekProcCount); next++)
  507.     seek_tickets[next] = 0;
  508.  
  509.   /* launch some parallel seek processes */
  510.   for (next = 0; next < SeekProcCount; next++)
  511.   { /* for each seek proc */
  512.     if ((child = fork()) == -1)
  513.       io_error("fork");
  514.     else if (child == 0)
  515.     { /* child process */
  516.  
  517.       /* set up and wait for the go-ahead */
  518.       close(seek_feedback[0]);
  519.       close(seek_control[1]);
  520.       newfile(name, &fd, &stream, 0);
  521.       srandom(getpid());
  522.       fprintf(stderr, "Seeker %d...", next + 1);
  523.  
  524.       /* wait for the go-ahead */
  525.       if (read(seek_control[0], seek_tickets, 1) != 1)
  526.     io_error("read ticket");
  527.       timestamp();
  528.       seeker_report[StartTime] = time_so_far();
  529.  
  530.       /* loop until we read a 0 ticket back from our parent */
  531.       while(seek_tickets[0])
  532.       { /* until Mom says stop */
  533.         doseek((long) (random() % size), fd,
  534.       ((lseek_count++ % UpdateSeek) == 0));
  535.     if (read(seek_control[0], seek_tickets, 1) != 1)
  536.       io_error("read ticket");
  537.       } /* until Mom says stop */
  538.       if (close(fd) == -1)
  539.         io_error("close after seek");
  540.  
  541.       /* report to parent */
  542.       get_delta_t(Lseek);
  543.       seeker_report[EndTime] = time_so_far();
  544.       seeker_report[CPU] = delta[(int) Lseek][CPU];
  545.       if (write(seek_feedback[1], seeker_report, sizeof(seeker_report))
  546.           != sizeof(seeker_report))
  547.         io_error("pipe write");
  548.       exit(0);
  549.     } /* child process */
  550.   } /* for each seek proc */
  551.  
  552.   /*
  553.    * Back in the parent; in an effort to ensure the children get an even
  554.    *  start, wait a few seconds for them to get scheduled, open their
  555.    *  files & so on.
  556.    */
  557.   close(seek_feedback[1]);
  558.   close(seek_control[0]);
  559.   sleep(5);
  560.   fprintf(stderr, "start 'em...");
  561.   if (write(seek_control[1], seek_tickets, sizeof(seek_tickets)) 
  562.       != sizeof(seek_tickets))
  563.     io_error("write tickets");
  564.   
  565.   /* read back from children */
  566.   for (next = 0; next < SeekProcCount; next++)
  567.   { /* for each child */
  568.     if (read(seek_feedback[0], (char *) seeker_report, sizeof(seeker_report))
  569.         != sizeof(seeker_report))
  570.       io_error("pipe read");
  571.  
  572.     /*
  573.      * each child writes back its CPU, start & end times.  The elapsed time 
  574.      *  to do all the seeks is the time the first child started until the 
  575.      *  time the last child stopped
  576.      */
  577.     delta[(int) Lseek][CPU] += seeker_report[CPU];
  578.     if (next == 0)
  579.     { /* first time */
  580.       first_start = seeker_report[StartTime];
  581.       last_stop = seeker_report[EndTime];
  582.     } /* first time */
  583.     else
  584.     { /* not first time */
  585.       first_start = (first_start < seeker_report[StartTime]) ?
  586.     first_start : seeker_report[StartTime]; 
  587.       last_stop = (last_stop > seeker_report[EndTime]) ?
  588.     last_stop : seeker_report[EndTime]; 
  589.     } /* not first time */
  590.     if (wait(&child) == -1)
  591.       io_error("wait");
  592.     fprintf(stderr, "done...");
  593.   } /* for each child */
  594.   fprintf(stderr, "\n");
  595.   delta[(int) Lseek][Elapsed] = last_stop - first_start;
  596.  
  597.   report(size);
  598.   unlink(name);
  599. }
  600.  
  601. static void
  602. report(size)
  603.   int   size;
  604. {
  605.   printf("              ");
  606.   printf(
  607.     "-------Sequential Output-------- ---Sequential Input-- --Random--\n");
  608.   printf("              ");
  609.   printf(
  610.     "-Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---\n");
  611.   printf("Machine    MB ");
  612.   printf("K/sec %%CPU K/sec %%CPU K/sec %%CPU K/sec %%CPU K/sec ");
  613.   printf("%%CPU  /sec %%CPU\n");
  614.  
  615.   printf("%-8.8s %4d ", machine, size / (1024 * 1024));
  616.   printf("%5d %4.1f %5d %4.1f %5d %4.1f ",
  617.     (int) (((double) size) / (delta[(int) Putc][Elapsed] * 1024.0)),
  618.     delta[(int) Putc][CPU] / delta[(int) Putc][Elapsed] * 100.0,
  619.     (int) (((double) size) / (delta[(int) FastWrite][Elapsed] * 1024.0)),
  620.     delta[(int) FastWrite][CPU] / delta[(int) FastWrite][Elapsed] * 100.0,
  621.     (int) (((double) size) / (delta[(int) ReWrite][Elapsed] * 1024.0)),
  622.     delta[(int) ReWrite][CPU] / delta[(int) ReWrite][Elapsed] * 100.0);
  623.   printf("%5d %4.1f %5d %4.1f ",
  624.     (int) (((double) size) / (delta[(int) Getc][Elapsed] * 1024.0)),
  625.     delta[(int) Getc][CPU] / delta[(int) Getc][Elapsed] * 100.0,
  626.     (int) (((double) size) / (delta[(int) FastRead][Elapsed] * 1024.0)),
  627.     delta[(int) FastRead][CPU] / delta[(int) FastRead][Elapsed] * 100.0);
  628.   printf("%5.1f %4.1f\n",
  629.     ((double) Seeks) / delta[(int) Lseek][Elapsed],
  630.     delta[(int) Lseek][CPU] / delta[(int) Lseek][Elapsed] * 100.0);
  631. }
  632.  
  633. static void
  634. newfile(name, fd, stream, create)
  635.   char *   name;
  636.   int *    fd;
  637.   FILE * * stream;
  638.   int      create;
  639. {
  640.   if (create)
  641.   { /* create from scratch */
  642.     if (unlink(name) == -1 && *fd != -1)
  643.       io_error("unlink");
  644.     *fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0777);
  645.   } /* create from scratch */
  646.   else
  647.     *fd = open(name, O_RDWR, 0777);
  648.  
  649.   if (*fd == -1)
  650.     io_error(name);
  651.   *stream = fdopen(*fd, "r+");
  652.   if (*stream == NULL)
  653.     io_error("fdopen");
  654. }
  655.  
  656. static void
  657. usage()
  658. {
  659.   fprintf(stderr,
  660.     "usage: Bonnie [-d scratch-dir] [-s size-in-Mb] [-m machine-label]\n");
  661.   exit(1);
  662. }
  663.  
  664. static void
  665. timestamp()
  666. {
  667.   last_timestamp = time_so_far();
  668.   last_cpustamp = cpu_so_far();
  669. }
  670.  
  671. static void 
  672. get_delta_t(test)
  673.   tests_t test;
  674. {
  675.   int which = (int) test;
  676.  
  677.   delta[which][Elapsed] = time_so_far() - last_timestamp;
  678.   delta[which][CPU] = cpu_so_far() - last_cpustamp;
  679. }
  680.  
  681. static double 
  682. cpu_so_far()
  683. {
  684. #ifdef SysV
  685.   struct tms tms;
  686.  
  687.   if (times(&tms) == -1)
  688.     io_error("times");
  689.   return ((double) tms.tms_utime) / ((double) CLK_TCK) +
  690.     ((double) tms.tms_stime) / ((double) CLK_TCK);
  691.  
  692. #else
  693.   struct rusage rusage;
  694.  
  695.   getrusage(RUSAGE_SELF, &rusage);
  696.   return
  697.     ((double) rusage.ru_utime.tv_sec) +
  698.       (((double) rusage.ru_utime.tv_usec) / 1000000.0) +
  699.         ((double) rusage.ru_stime.tv_sec) +
  700.           (((double) rusage.ru_stime.tv_usec) / 1000000.0);
  701. #endif
  702. }
  703.  
  704. static double
  705. time_so_far()
  706. {
  707. #ifdef SysV
  708.   int        val;
  709.   struct tms tms;
  710.  
  711.   if ((val = times(&tms)) == -1)
  712.     io_error("times");
  713.  
  714.   return ((double) val) / ((double) CLK_TCK);
  715.  
  716. #else
  717.   struct timeval tp;
  718.  
  719.   if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
  720.     io_error("gettimeofday");
  721.   return ((double) (tp.tv_sec - basetime)) +
  722.     (((double) tp.tv_usec) / 1000000.0);
  723. #endif
  724. }
  725.  
  726. static void
  727. io_error(message)
  728.   char * message;
  729. {
  730.   char buf[Chunk];
  731.  
  732.   sprintf(buf, "Bonnie: drastic I/O error (%s)", message);
  733.   perror(buf);
  734.   exit(1);
  735. }
  736.  
  737. /*
  738.  * Do a typical-of-something random I/O.  Any serious application that
  739.  *  has a random I/O bottleneck is going to be smart enough to operate
  740.  *  in a page mode, and not stupidly pull individual words out at
  741.  *  odd offsets.  To keep the cache from getting too clever, some
  742.  *  pages must be updated.  However an application that updated each of
  743.  *  many random pages that it looked at is hard to imagine.  
  744.  * However, it would be wrong to put the update percentage in as a
  745.  *  parameter - the effect is too nonlinear.  Need a profile
  746.  *  of what Oracle or Ingres or some such actually does.
  747.  * Be warned - there is a *sharp* elbow in this curve - on a 1-Mb file,
  748.  *  most substantial unix systems show >2000 random I/Os per second -
  749.  *  obviously they've cached the whole thing and are just doing buffer
  750.  *  copies.  
  751.  */
  752. static void 
  753. doseek(where, fd, update)
  754.   long where;
  755.   int  fd;
  756.   int  update;
  757. {
  758.   int   buf[Chunk / IntSize];
  759.   off_t probe;
  760.   int   size;
  761.  
  762.   probe = (where / Chunk) * Chunk;
  763.   if (lseek(fd, probe, 0) != probe)
  764.     io_error("lseek in doseek");
  765.   if ((size = read(fd, (char *) buf, Chunk)) == -1)
  766.     io_error("read in doseek");
  767.  
  768.   /* every so often, update a block */
  769.   if (update)
  770.   { /* update this block */
  771.  
  772.     /* touch a word */
  773.     buf[((int) random() % (size/IntSize - 2)) + 1]--;
  774.     if (lseek(fd, (long) probe, 0) != probe)
  775.       io_error("lseek in doseek update");
  776.     if (write(fd, (char *) buf, size) == -1)
  777.       io_error("write in doseek");
  778.   } /* update this block */
  779. }
  780.   
  781. #ifdef SysV
  782. static char randseed[32];
  783.  
  784. static void
  785. srandom(seed)
  786.   int seed;
  787. {
  788.   sprintf(randseed, "%06d", seed);
  789. }
  790.  
  791. static long
  792. random()
  793. {
  794.   return nrand48(randseed);
  795. }
  796. #endif
  797.  
  798.  
  799. ---Clemens Dinges' FS scrambler code--
  800. void main(int argc, char * argv[])
  801. {
  802.    static char name[] = "/mnt/h.";
  803.    int    fd_lst [10];
  804.    int    buf[7<<10];
  805.    int    size = 50;
  806.    int    lv,lvv,lvvv;
  807.  
  808.    for (lv = 1; lv < argc; lv++)
  809.       if (argv[lv][0] == '-')
  810.          { /* option? */
  811.          if ((strcmp(argv[lv] + 1, "s") == 0) && (lv < argc-1))
  812.             size = atoi(argv[++lv]);
  813.          else
  814.             usage();
  815.          } /* option? */
  816.       else
  817.          usage();
  818.    if (size < 1)
  819.       usage();
  820.    size <<=20;
  821.  
  822.    name[6] = '0';
  823.    for (lv=0; lv < 10; lv++)  {
  824.       fd_lst[lv] = open(name,O_RDWR|O_CREAT,0777);
  825.       name[6]++;
  826.    }
  827.    lvv = 0;
  828.    while (lvv < size) { 
  829.       for (lv=0; lv < 10; lv++) {
  830.          write(fd_lst[lv],buf,(lvvv = (random() % (7<<10))));
  831.          lvv += lvvv;
  832.       }
  833.    }
  834.    name[6] = '0';
  835.    for (lv=0; lv < 10; lv++) 
  836.       close(fd_lst[lv]);
  837.       unlink(name);
  838.       name[6]++;
  839.    }
  840.  
  841.    /* then umount ... */
  842. }
  843. -- 
  844. Clemens N. Dinges, Siemens AG, AUT E 25, PO Box 3220, D-8520 Erlangen, Germany
  845. UUCP:             ...!mcsun!unido!estevax!cdinges
  846.  
  847.  
  848.  
  849. --
  850.     | Wes Morgan, not speaking for | {any major site}!ukma!ukecc!morgan | 
  851.     | the University of Kentucky's |        morgan@engr.uky.edu         |
  852.     | Engineering Computing Center |   morgan%engr.uky.edu@UKCC.BITNET  | 
  853.      Lint is the compiler's only means of dampening the programmer's ego.
  854.