9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] Bonnie Benchmark
@ 1998-11-03 14:21 Franklin
  0 siblings, 0 replies; 5+ messages in thread
From: Franklin @ 1998-11-03 14:21 UTC (permalink / raw)



    Did anyone run Bonnie Benchmark
(http://www.portal.ca/~cjs/computer/benchmark/bonnie.c)  on Plan 9?

Franklin.







^ permalink raw reply	[flat|nested] 5+ messages in thread

* [9fans] Bonnie Benchmark
@ 1998-11-05  0:15 James
  0 siblings, 0 replies; 5+ messages in thread
From: James @ 1998-11-05  0:15 UTC (permalink / raw)


On Wed, 04 Nov 1998 16:03:33 -0800 I wrote:
< Interesting! I ran it on my cpu server, and got some different numbers.
< I imagine much of the difference is due to the wide-scsi (an NCR 53c875,
< using Nigel's driver). Also, I did not set any specific block size when
< I was creating the file system.

And as a side note... Here are the results from a P2/400 Linux box
with 128MB ram and an IDE drive...

bonnie -s 1
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            1  6321 98.8 75577 147.6 37539 110.0  5886 97.7 124422 121.5 15501.6 96.9
bonnie -s 2
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            2  6336 102.1 69745 68.1 31725 92.9  5729 97.9 125336 61.2 13833.9 96.8
bonnie -s 4
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            4  6319 100.3 68308 100.1 31169 106.5  5783 100.2 133433 130.3 13089.2 98.2
bonnie -s 8
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            8  6213 98.6 67784 99.3 33832 103.2  5747 100.3 132900 97.3 12539.6 97.2
bonnie -s 16
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           16  6244 99.9 66131 100.9 34100 99.9  5717 100.2 128472 94.1 1476.8 11.1
bonnie -s 32
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           32  5868 93.7 45987 66.0  2809 10.3  5283 93.5 126288 100.2 11155.8 83.7
bonnie -s 64
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           64  5637 90.8 29349 43.4  1918  6.0  2807 49.4 123903 96.4 10850.2 86.8




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [9fans] Bonnie Benchmark
@ 1998-11-05  0:07 G.David
  0 siblings, 0 replies; 5+ messages in thread
From: G.David @ 1998-11-05  0:07 UTC (permalink / raw)


>From: "James A. Robinson" <Jim.Robinson@Stanford.Edu>
>Interesting! I ran it on my cpu server, and got some different numbers.
>I imagine much of the difference is due to the wide-scsi (an NCR 53c875,
>using Nigel's driver). Also, I did not set any specific block size when
>I was creating the file system.

The main difference is that you are only writing to one hard drive,
your write numbers are about twice mine.

Also your 4k block size helps alot.

The other difference is:

>	File server
>		128 Mb RAM

You need to test up to -s 256 to blow the cache.




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [9fans] Bonnie Benchmark
@ 1998-11-05  0:03 James
  0 siblings, 0 replies; 5+ messages in thread
From: James @ 1998-11-05  0:03 UTC (permalink / raw)


Interesting! I ran it on my cpu server, and got some different numbers.
I imagine much of the difference is due to the wide-scsi (an NCR 53c875,
using Nigel's driver). Also, I did not set any specific block size when
I was creating the file system.

	File server
		Intel P2/233
		128 Mb RAM
		Diamond Fireport 40 PCI SCSI
		Seagate 9Gb 19171WC w/ SCA adapter
		3c509 ethernet 10BaseT
	
	Ethernet Hub 
		has smart routing, i.e., host-to-host routing
	
	CPU/Auth acting as terminal
		Intel P2/400
		256MB RAM
		3c509 ethernet 10BaseT

bonnie -s 1
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            1   747 16.1   775 12.9   399  8.6   752  5.9   775  3.0 107.0  4.7
bonnie -s 2
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            2   764 14.9   793 13.6   393  8.8   752  6.6   778  1.5 108.7  4.0
bonnie -s 4
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            4   778 16.3   801 15.1   393  7.9   748  5.3   771  1.3 107.4  3.7
bonnie -s 8
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            8   775 16.6   803 14.3   399  6.6   749  5.9   790  1.1 107.7  3.9
bonnie -s 16
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           16   779 16.0   805 14.7   401  8.5   749  6.1   788  1.4 107.3  3.9
bonnie -s 32
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           32   781 16.7   807 14.8   399  7.4   747  6.1   785  1.3 108.2  3.4
bonnie -s 64
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           64   777 17.0   807 14.9   400  8.1   748  6.2   788  1.2 107.2  3.6




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [9fans] Bonnie Benchmark
@ 1998-11-04 22:03 G.David
  0 siblings, 0 replies; 5+ messages in thread
From: G.David @ 1998-11-04 22:03 UTC (permalink / raw)


>Did anyone run Bonnie Benchmark
>(http://www.portal.ca/~cjs/computer/benchmark/bonnie.c)  on Plan 9?

Here is bonnie.  I ported the program (included at the end) to
Plan9, but didn't change it otherwise.

It is obvious what happens when the file size is greater than
the buffer cache, but it is interesting that the read performance
is impacted by the buffer flush continuing after the writes.
Look at the single character read times.  I didn't write the test,
I just ran it.

The rewrite behavior is really interesting.  The amount of
random IO created by the read ahead processes, the buffer flush
and the server processes is amazing.  Also, because of the
distributed nature of the system, this is the slowest of the
tests.

When the file fits in the buffer cache, ethernet performance
is the bottleneck.  The times for 1, 2, 4, 8 and 16 show that.

Otherwise, random disk IO is the killer.

Notice the seek times across all the sizes.  This test is made
up of multi-threaded random reads interspersed with 10% writes.

One last thing.  I have tuned my filesystem for many small
files and it uses 1k blocks.  For the type of IO that this
program is testing a 4k block size would be better.

The equipment of the test (not my best stuff, but it works):

File Server (with 1k block size)
Intel 486DX/100
32MB RAM
Two Adaptec 1542CF SCSI controllers
3C509 ethernet 10BaseT
Mirrored 2GB Micropolis narrow SCSI drives
(writes go to both drives, reads come from "closest")

Ethernet Hub (no other traffic at the time of the tests)

Terminal
Intel 486DX/100
32MB RAM
WD8003 ethernet 10BaseT


term% ./bonnie -s 1
File './bonnie.54', size: 1048576
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 2...Seeker 1...Seeker 3...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            1   393 44.6   556 27.2   224 12.7   323 44.5   494  8.7  93.0 25.5

term% ./bonnie -s 2
File './bonnie.58', size: 2097152
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 1...Seeker 3...Seeker 2...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            2   384 47.4   466 22.8   236 15.2   270 36.5   252  4.3  93.5 27.3

term% ./bonnie -s 4
File './bonnie.62', size: 4194304
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 3...Seeker 1...Seeker 2...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            4   387 40.1   461 21.1   204 13.2   333 36.7   492  7.9  94.2 24.9

term% ./bonnie -s 8
File './bonnie.66', size: 8388608
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 1...Seeker 2...Seeker 3...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
            8   351 43.5   514 26.9   236 15.4   310 41.4   485  7.9  91.8 27.5

term% ./bonnie -s 16
File './bonnie.70', size: 16777216
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 1...Seeker 2...Seeker 3...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           16   364 44.6   480 21.1   246 15.7   306 39.9   482  7.9  92.7 29.3

term% ./bonnie -s 32
File './bonnie.77', size: 33554432
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 1...Seeker 2...Seeker 3...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           32   336 41.8   347 13.8    52  3.2    70  7.6   370  5.8  94.1 21.0

term% ./bonnie -s 64
File './bonnie.81', size: 67108864
Writing with putc()...done
Rewriting...
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
start 'em...Seeker 1...Seeker 2...Seeker 3...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
           64   151 18.8   123  5.9    46  2.9   112 14.9   370  6.2  93.2 27.3


/*
 * This is a file system benchmark which attempts to study bottlenecks -
 * it is named 'bonnie' for semi-obvious reasons.
 *
 * Specifically, these are the types of filesystem activity that have been
 * observed to be bottlenecks in I/O-intensive applications, in particular
 * the text database work done in connection with the New Oxford English
 * Dictionary Project at the University of Waterloo.
 * 
 * It performs a series of tests on a file of known size.  By default, that
 * size is 100 Mb (but that's not enough - see below).  For each test, bonnie 
 * reports the bytes processed per elapsed second, per CPU second, and the 
 * % CPU usage (user and system).
 * 
 * In each case, an attempt is made to keep optimizers from noticing it's 
 * all bogus.  The idea is to make sure that these are real transfers to/from
 * user space to the physical disk.  The tests are:
 * 
 * 1. Sequential Output
 * 
 * 1.1 Per-Character.  The file is written using the putc() stdio macro.
 * The loop that does the writing should be small enough to fit into any
 * reasonable I-cache.  The CPU overhead here is that required to do the
 * stdio code plus the OS file space allocation.
 * 
 * 1.2 Block.  The file is created using write(2).  The CPU overhead
 * should be just the OS file space allocation.
 * 
 * 1.3 Rewrite.  Each BUFSIZ of the file is read with read(2), dirtied, and
 * rewritten with write(2), requiring an seek(2).  Since no space
 * allocation is done, and the I/O is well-localized, this should test the
 * effectiveness of the filesystem cache and the speed of data transfer.
 * 
 * 2. Sequential Input
 * 
 * 2.1 Per-Character.  The file is read using the getc() stdio macro.  Once
 * again, the inner loop is small.  This should exercise only stdio and
 * sequential input.
 * 
 * 2.2 Block.  The file is read using read(2).  This should be a very pure
 * test of sequential input performance.
 * 
 * 3. Random Seeks
 * 
 * This test runs SeekProcCount processes in parallel, doing a total of
 * 4000 seek()s to locations in the file specified by random() in bsd systems,
 * drand48() on sysV systems.  In each case, the block is read with read(2).  
 * In 10% of cases, it is dirtied and written back with write(2).
 *
 * The idea behind the SeekProcCount processes is to make sure there's always 
 * a seek queued up.
 * 
 * AXIOM: For any unix filesystem, the effective number of seek(2) calls
 * per second declines asymptotically to near 30, once the effect of
 * caching is defeated.
 * 
 * The size of the file has a strong nonlinear effect on the results of
 * this test.  Many Unix systems that have the memory available will make
 * aggressive efforts to cache the whole thing, and report random I/O rates
 * in the thousands per second, which is ridiculous.  As an extreme
 * example, an IBM RISC 6000 with 64 Mb of memory reported 3,722 per second
 * on a 50 Mb file.  Some have argued that bypassing the cache is artificial
 * since the cache is just doing what it's designed to.  True, but in any 
 * application that requires rapid random access to file(s) significantly
 * larger than main memory which is running on a system which is doing
 * significant other work, the caches will inevitably max out.  There is
 * a hard limit hiding behind the cache which has been observed by the
 * author to be of significant import in many situations - what we are trying
 * to do here is measure that number.
 *
 * COPYRIGHT NOTICE: 
 * Copyright (c) Tim Bray, 1990.
 * Everybody is hereby granted rights to use, copy, and modify this program, 
 *  provided only that this copyright notice and the disclaimer below
 *  are preserved without change.
 * DISCLAIMER:
 * This program is provided AS IS with no warranty of any kind, and
 * The author makes no representation with respect to the adequacy of this
 *  program for any particular purpose or with respect to its adequacy to 
 *  produce any particular result, and
 * The author shall not be liable for loss or damage arising out of
 *  the use of this program regardless of how sustained, and
 * In no event shall the author be liable for special, direct, indirect
 *  or consequential damage, loss, costs or fees or expenses of any
 *  nature or kind.
 */

#include <u.h>
#include <libc.h>
#include <bio.h>

typedef long time_t;
typedef long off_t;
typedef enum
{
  Putc,
  ReWrite,
  FastWrite,
  Getc,
  FastRead,
  Lseek,
  TestCount
} tests_t;

#define IntSize (4)

/*
 * N.B. in seeker_reports, CPU appears and Start/End time, but not Elapsed,
 *  so position 1 is re-used; icky data coupling.
 */
#define CPU (0)
#define Elapsed (1)
#define StartTime (1)
#define EndTime (2)
#define Seeks (4000)
#define UpdateSeek (10)
#define SeekProcCount (3)
#define Chunk (8192)

static double cpu_so_far(void);
static void doseek(long, int, int);
static void get_delta_t(tests_t);
static void io_error(char*);
static void newfile(char*, int*, Biobufhdr**, int, int);
static void report(int);
static double time_so_far(void);
static void   timestamp(void);
static void   usage(void);


static int    basetime;
static double delta[(int) TestCount][2];
static char * machine = "";
static double last_cpustamp = 0.0;
static double last_timestamp = 0.0;

void
main(int argc, char *argv[])
{
  int    buf[Chunk / IntSize];
  int    bufindex;
  int    chars[256];
  int    child;
  char * dir;
  int    fd;
  double first_start;
  double last_stop;
  int    seek_count = 0;
  char   name[Chunk];
  int    next;
  int    seek_control[2];
  char   seek_tickets[Seeks + SeekProcCount];
  double seeker_report[3];
  int    size;
  Biobufhdr *stream;
  int    words;

  fd = -1;
  basetime = (int) time((time_t *) 0);
  size = 100;
  dir = ".";

  for (next = 1; next < argc; next++)
    if (argv[next][0] == '-')
    { /* option? */
      switch (argv[next][1]) {
      case 'd':
        dir = argv[next + 1];
        break;
      case 's':
        size = atoi(argv[next + 1]);
        break;
      case 'm':
        machine = argv[next + 1];
        break;
      default:
        usage();
        break;
     }
      next++;
    } /* option? */
    else
      usage();

  if (size < 1)
    usage();
  size *= (1024 * 1024);
  sprint(name, "%s/bonnie.%d", dir, getpid());
  fprint(2, "File '%s', size: %d\n", name, size);

  /* Fill up a file, writing it a char at a time with the stdio putc() call */
  fprint(2, "Writing with putc()...");
  newfile(name, &fd, &stream, 1, OWRITE);
  timestamp();
  for (words = 0; words < size; words++)
    if (BPUTC(stream, words & 0x7f) < 0)
      io_error("putc");
  
  /*
   * note that we always close the file before measuring time, in an
   *  effort to force as much of the I/O out as we can
   */
  if (Bterm(stream) < 0)
    io_error("fclose after putc");
  get_delta_t(Putc);
  fprint(2, "done\n");

  /* Now read & rewrite it using block I/O.  Dirty one word in each block */
  newfile(name, &fd, &stream, 0, ORDWR);
  if (seek(fd, (off_t) 0, 0) == (off_t) -1)
    io_error("seek(2) before rewrite");
  fprint(2, "Rewriting...");
  timestamp();
  bufindex = 0;
  if ((words = read(fd, (char *) buf, Chunk)) == -1)
    io_error("rewrite read");
  while (words == Chunk)
  { /* while we can read a block */
    if (bufindex == Chunk / IntSize)
      bufindex = 0;
    buf[bufindex++]++;
    if (seek(fd, (off_t) -words, 1) == -1)
      io_error("relative seek(2)");
    if (write(fd, (char *) buf, words) == -1)
      io_error("re write(2)");
    if ((words = read(fd, (char *) buf, Chunk)) == -1)
      io_error("rwrite read");
  } /* while we can read a block */
  if (close(fd) == -1)
    io_error("close after rewrite");
  get_delta_t(ReWrite);
  fprint(2, "done\n");

  /* Write the whole file from scratch, again, with block I/O */
  newfile(name, &fd, &stream, 1, ORDWR);
  fprint(2, "Writing intelligently...");
  for (words = 0; words < Chunk / IntSize; words++)
    buf[words] = 0;
  timestamp();
  for (words = bufindex = 0; words < (size / Chunk); words++)
  { /* for each word */
    if (bufindex == (Chunk / IntSize))
      bufindex = 0;
    buf[bufindex++]++;
    if (write(fd, (char *) buf, Chunk) == -1)
      io_error("write(2)");
  } /* for each word */
  if (close(fd) == -1)
    io_error("close after fast write");
  get_delta_t(FastWrite);
  fprint(2, "done\n");

  /* read them all back with getc() */
  newfile(name, &fd, &stream, 0, OREAD);
  for (words = 0; words < 256; words++)
    chars[words] = 0;
  fprint(2, "Reading with getc()...");
  timestamp();
  for (words = 0; words < size; words++)
  { /* for each byte */
    if ((next = BGETC(stream)) < 0)
      io_error("getc(3)");

    /* just to fool optimizers */
    chars[next]++;
  } /* for each byte */
  if (Bterm(stream) == -1)
    io_error("fclose after getc");
  get_delta_t(Getc);
  fprint(2, "done\n");

  /* use the frequency count */
  for (words = 0; words < 256; words++)
    sprint((char *) buf, "%d", chars[words]);

  /* Now suck it in, Chunk at a time, as fast as we can */
  newfile(name, &fd, &stream, 0, ORDWR);
  if (seek(fd, (off_t) 0, 0) == -1)
    io_error("seek before read");
  fprint(2, "Reading intelligently...");
  timestamp();
  do
  { /* per block */
    if ((words = read(fd, (char *) buf, Chunk)) == -1)
      io_error("read(2)");
    chars[buf[abs(buf[0]) % (Chunk / IntSize)] & 0x7f]++;
  } /* per block */
  while (words);
  if (close(fd) == -1)
    io_error("close after read");
  get_delta_t(FastRead);
  fprint(2, "done\n");

  /* use the frequency count */
  for (words = 0; words < 256; words++)
    sprint((char *) buf, "%d", chars[words]);

  /*
   * Now test random seeks; first, set up for communicating with children.
   * The object of the game is to do "Seeks" seek() calls as quickly
   *  as possible.  So we'll farm them out among SeekProcCount processes.
   *  We'll control them by writing 1-byte tickets down a pipe which
   *  the children all read.  We write "Seeks" bytes with val 1, whichever
   *  child happens to get them does it and the right number of seeks get
   *  done.
   * The idea is that since the write() of the tickets is probably
   *  atomic, the parent process likely won't get scheduled while the
   *  children are seeking away.  If you draw a picture of the likely
   *  timelines for three children, it seems likely that the seeks will
   *  overlap very nicely with the process scheduling with the effect
   *  that there will *always* be a seek() outstanding on the file.
   * Question: should the file be opened *before* the fork, so that
   *  all the children are seeking on the same underlying file object?
   */
  if (pipe(seek_control) < 0)
    io_error("pipe");
  for (next = 0; next < Seeks; next++)
    seek_tickets[next] = 1;
  for ( ; next < (Seeks + SeekProcCount); next++)
    seek_tickets[next] = 0;

  /* launch some parallel seek processes */
  for (next = 0; next < SeekProcCount; next++)
  { /* for each seek proc */
    if ((child = fork()) == -1)
      io_error("fork");
    else if (child == 0)
    { /* child process */

      /* set up and wait for the go-ahead */
      close(seek_control[1]);
      newfile(name, &fd, &stream, 0, ORDWR);
      srand(getpid());
      fprint(2, "Seeker %d...", next + 1);

      /* wait for the go-ahead */
      if (read(seek_control[0], seek_tickets, 1) != 1)
	io_error("read ticket");
      timestamp();
      seeker_report[StartTime] = time_so_far();

      /* loop until we read a 0 ticket back from our parent */
      while(seek_tickets[0])
      { /* until Mom says stop */
        doseek((long) (rand() % size), fd,
	  ((seek_count++ % UpdateSeek) == 0));
	if (read(seek_control[0], seek_tickets, 1) != 1)
	  io_error("read ticket");
      } /* until Mom says stop */
      if (close(fd) == -1)
        io_error("close after seek");

      /* report to parent */
      get_delta_t(Lseek);
      seeker_report[EndTime] = time_so_far();
      seeker_report[CPU] = delta[(int) Lseek][CPU];
      if (write(seek_control[0], seeker_report, sizeof(seeker_report))
          != sizeof(seeker_report))
        io_error("pipe write");
      exits("");
    } /* child process */
  } /* for each seek proc */

  /*
   * Back in the parent; in an effort to ensure the children get an even
   *  start, wait a few seconds for them to get scheduled, open their
   *  files & so on.
   */
  close(seek_control[0]);
  sleep(5);
  fprint(2, "start 'em...");
  if (write(seek_control[1], seek_tickets, sizeof(seek_tickets)) 
      != sizeof(seek_tickets))
    io_error("write tickets");
  
  /* read back from children */
  for (next = 0; next < SeekProcCount; next++)
  { /* for each child */
    if (read(seek_control[1], (char *) seeker_report, sizeof(seeker_report))
        != sizeof(seeker_report))
      io_error("pipe read");

    /*
     * each child writes back its CPU, start & end times.  The elapsed time 
     *  to do all the seeks is the time the first child started until the 
     *  time the last child stopped
     */
    delta[(int) Lseek][CPU] += seeker_report[CPU];
    if (next == 0)
    { /* first time */
      first_start = seeker_report[StartTime];
      last_stop = seeker_report[EndTime];
    } /* first time */
    else
    { /* not first time */
      first_start = (first_start < seeker_report[StartTime]) ?
	first_start : seeker_report[StartTime]; 
      last_stop = (last_stop > seeker_report[EndTime]) ?
	last_stop : seeker_report[EndTime]; 
    } /* not first time */
    if (wait(0) < 0)
      io_error("wait");
    fprint(2, "done...");
  } /* for each child */
  fprint(2, "\n");
  delta[(int) Lseek][Elapsed] = last_stop - first_start;

  report(size);
  remove(name);
}

static void
report(int size)
{
  print("              ");
  print(
    "-------Sequential Output-------- ---Sequential Input-- --Random--\n");
  print("              ");
  print(
    "-Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---\n");
  print("Machine    MB ");
  print("K/sec %%CPU K/sec %%CPU K/sec %%CPU K/sec %%CPU K/sec ");
  print("%%CPU  /sec %%CPU\n");

  print("%-8.8s %4d ", machine, size / (1024 * 1024));
  print("%5d %4.1f %5d %4.1f %5d %4.1f ",
    (int) (((double) size) / (delta[(int) Putc][Elapsed] * 1024.0)),
    delta[(int) Putc][CPU] / delta[(int) Putc][Elapsed] * 100.0,
    (int) (((double) size) / (delta[(int) FastWrite][Elapsed] * 1024.0)),
    delta[(int) FastWrite][CPU] / delta[(int) FastWrite][Elapsed] * 100.0,
    (int) (((double) size) / (delta[(int) ReWrite][Elapsed] * 1024.0)),
    delta[(int) ReWrite][CPU] / delta[(int) ReWrite][Elapsed] * 100.0);
  print("%5d %4.1f %5d %4.1f ",
    (int) (((double) size) / (delta[(int) Getc][Elapsed] * 1024.0)),
    delta[(int) Getc][CPU] / delta[(int) Getc][Elapsed] * 100.0,
    (int) (((double) size) / (delta[(int) FastRead][Elapsed] * 1024.0)),
    delta[(int) FastRead][CPU] / delta[(int) FastRead][Elapsed] * 100.0);
  print("%5.1f %4.1f\n",
    ((double) Seeks) / delta[(int) Lseek][Elapsed],
    delta[(int) Lseek][CPU] / delta[(int) Lseek][Elapsed] * 100.0);
}

static void
newfile(char *name, int *fd, Biobufhdr **stream, int new, int mode)
{
  if (new)
  { /* create from scratch */
    if (remove(name) == -1 && *fd != -1)
      io_error("remove");
  } /* create from scratch */
  if (mode == ORDWR) {
    *stream = 0;
    if (new) {
      *fd = create(name, mode, 0666);
    } else {
      *fd = open(name, mode);
    }
  } else {
    *stream = Bopen(name, mode);
    *fd = BFILDES(*stream);
  }

  if (*fd == -1)
    io_error(name);
}

static void
usage()
{
  fprint(2,
    "usage: bonnie [-d scratch-dir] [-s size-in-Mb] [-m machine-label]\n");
  exits("usage");
}

static void
timestamp()
{
  last_timestamp = time_so_far();
  last_cpustamp = cpu_so_far();
}

static void 
get_delta_t(tests_t test)
{
  int which = (int) test;

  delta[which][Elapsed] = time_so_far() - last_timestamp;
  delta[which][CPU] = cpu_so_far() - last_cpustamp;
}

static double 
cpu_so_far()
{
  long tms[4];

  if (times(tms) < 0)
   io_error("times");
  return ((double) tms[0]) / ((double) 1000) +
   ((double) tms[1]) / ((double) 1000);
}

static double
time_so_far()
{
  long val;
  long tms[4];

  if ((val = times(tms)) < 0)
    io_error("times");

  return ((double) val) / ((double) 1000);
}

static void
io_error(char *message)
{
  char buf[Chunk];

  sprint(buf, "bonnie: drastic I/O error (%s)", message);
  perror(buf);
  exits("io error");
}

/*
 * Do a typical-of-something random I/O.  Any serious application that
 *  has a random I/O bottleneck is going to be smart enough to operate
 *  in a page mode, and not stupidly pull individual words out at
 *  odd offsets.  To keep the cache from getting too clever, some
 *  pages must be updated.  However an application that updated each of
 *  many random pages that it looked at is hard to imagine.  
 * However, it would be wrong to put the update percentage in as a
 *  parameter - the effect is too nonlinear.  Need a profile
 *  of what Oracle or Ingres or some such actually does.
 * Be warned - there is a *sharp* elbow in this curve - on a 1-Mb file,
 *  most substantial unix systems show >2000 random I/Os per second -
 *  obviously they've cached the whole thing and are just doing buffer
 *  copies.  
 */
static void 
doseek(long where, int fd, int update)
{
  int   buf[Chunk / IntSize];
  off_t probe;
  int   size;

  probe = (where / Chunk) * Chunk;
  if (seek(fd, probe, 0) != probe)
    io_error("seek in doseek");
  if ((size = read(fd, (char *) buf, Chunk)) == -1)
    io_error("read in doseek");

  /* every so often, update a block */
  if (update)
  { /* update this block */

    /* touch a word */
    buf[((int) rand() % (size/IntSize - 2)) + 1]--;
    if (seek(fd, (long) probe, 0) != probe)
      io_error("seek in doseek update");
    if (write(fd, (char *) buf, size) == -1)
      io_error("write in doseek");
  } /* update this block */
}

/* END OF bonnie.c */




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~1998-11-05  0:15 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-11-03 14:21 [9fans] Bonnie Benchmark Franklin
1998-11-04 22:03 G.David
1998-11-05  0:03 James
1998-11-05  0:07 G.David
1998-11-05  0:15 James

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).