* Removing old version of bonnie

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26918 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Salvatore Benedetto 2008-08-10 15:33:26 +00:00
parent c3a9fa2150
commit 71d31cc518
3 changed files with 0 additions and 691 deletions

View File

@ -1,593 +0,0 @@
/*
* This is a file system benchmark which attempts to study bottlenecks -
* it is named 'Bonnie' after Bonnie Raitt, who knows how to use one.
*
* Commentary on Bonnie's operations may be found at
* http://www.textuality.com/bonnie/intro.html
*
* COPYRIGHT NOTICE:
* Copyright (c) Tim Bray, 1990-1996.
*
* 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 <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#if defined(SysV)
#include <limits.h>
#include <sys/times.h>
#else
#include <sys/resource.h>
#endif
#define IntSize (sizeof(int))
/*
* 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 (16384)
/* labels for the tests, used as an array index */
typedef enum
{
Putc, ReWrite, FastWrite, Getc, FastRead, Lseek, TestCount
} tests_t;
static double cpu_so_far();
static void doseek(off_t where, int fd, int update);
static void get_delta_t(tests_t test);
static void io_error(char * message);
static void newfile(char * name, int * fd, FILE * * stream, int create);
#if defined(SysV)
/* System V wrappers for randomizers */
static long random();
static void srandom(int seed);
#endif
static void report(char * machine, off_t size);
static void write_html(char * machine, off_t size);
static double time_so_far();
static void timestamp();
static void usage();
/*
* Housekeeping variables to build up timestamps for the tests;
* global to make it easy to keep track of the progress of time.
* all of this could have been done with non-global variables,
* but the code is easier to read this way and I don't anticipate
* much software engineering down the road
*/
static int basetime; /* when we started */
static double delta[(int) TestCount][2]; /* array of DeltaT values */
static double last_cpustamp = 0.0; /* for computing delta-t */
static double last_timestamp = 0.0; /* for computing delta-t */
main(
int argc,
char * argv[])
{
int buf[Chunk / IntSize];
int bufindex;
int chars[256];
int child;
char * dir;
int html = 0;
int fd;
double first_start;
double last_stop;
int lseek_count = 0;
char * machine;
char name[Chunk];
int next;
int seek_control[2];
int seek_feedback[2];
char seek_tickets[Seeks + SeekProcCount];
double seeker_report[3];
off_t size;
FILE * stream;
off_t words;
fd = -1;
basetime = (int) time((time_t *) NULL);
size = 100;
dir = ".";
machine = "";
/* pick apart args */
for (next = 1; next < argc; next++)
if (strcmp(argv[next], "-d") == 0)
dir = argv[++next];
else if (strcmp(argv[next], "-s") == 0)
size = atol(argv[++next]);
else if (strcmp(argv[next], "-m") == 0)
machine = argv[++next];
else if (strcmp(argv[next], "-html") == 0)
html = 1;
else
usage();
if (size < 1)
usage();
/* sanity check - 32-bit machines can't handle more than 2047 Mb */
if (sizeof(off_t) <= 4 && size > 2047)
{
fprintf(stderr, "File too large for 32-bit machine, sorry\n");
exit(1);
}
sprintf(name, "%s/Bonnie.%d", dir, getpid());
/* size is in meg, rounded down to multiple of Chunk */
size *= (1024 * 1024);
size = Chunk * (size / Chunk);
fprintf(stderr, "File '%s', size: %ld\n", name, size);
/* Fill up a file, writing it a char at a time with the stdio putc() call */
fprintf(stderr, "Writing with putc()...");
newfile(name, &fd, &stream, 1);
timestamp();
for (words = 0; words < size; words++)
if (putc(words & 0x7f, stream) == EOF)
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 (fclose(stream) == -1)
io_error("fclose after putc");
get_delta_t(Putc);
fprintf(stderr, "done\n");
/* Now read & rewrite it using block I/O. Dirty one word in each block */
newfile(name, &fd, &stream, 0);
if (lseek(fd, (off_t) 0, 0) == (off_t) -1)
io_error("lseek(2) before rewrite");
fprintf(stderr, "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 (lseek(fd, (off_t) -words, 1) == -1)
io_error("relative lseek(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);
fprintf(stderr, "done\n");
/* Write the whole file from scratch, again, with block I/O */
newfile(name, &fd, &stream, 1);
fprintf(stderr, "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);
fprintf(stderr, "done\n");
/* read them all back with getc() */
newfile(name, &fd, &stream, 0);
for (words = 0; words < 256; words++)
chars[words] = 0;
fprintf(stderr, "Reading with getc()...");
timestamp();
for (words = 0; words < size; words++)
{ /* for each byte */
if ((next = getc(stream)) == EOF)
io_error("getc(3)");
/* just to fool optimizers */
chars[next]++;
} /* for each byte */
if (fclose(stream) == -1)
io_error("fclose after getc");
get_delta_t(Getc);
fprintf(stderr, "done\n");
/* use the frequency count */
for (words = 0; words < 256; words++)
sprintf((char *) buf, "%d", chars[words]);
/* Now suck it in, Chunk at a time, as fast as we can */
newfile(name, &fd, &stream, 0);
if (lseek(fd, (off_t) 0, 0) == -1)
io_error("lseek before read");
fprintf(stderr, "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);
fprintf(stderr, "done\n");
/* use the frequency count */
for (words = 0; words < 256; words++)
sprintf((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" lseek() 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 lseeking on the same underlying file object?
*/
if (pipe(seek_feedback) == -1 || pipe(seek_control) == -1)
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_feedback[0]);
close(seek_control[1]);
newfile(name, &fd, &stream, 0);
srandom(getpid());
fprintf(stderr, "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) (random() % (size / Chunk)), fd,
((lseek_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_feedback[1], seeker_report, sizeof(seeker_report))
!= sizeof(seeker_report))
io_error("pipe write");
exit(0);
} /* 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_feedback[1]);
close(seek_control[0]);
sleep(5);
fprintf(stderr, "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_feedback[0], (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(&child) == -1)
io_error("wait");
fprintf(stderr, "done...");
} /* for each child */
fprintf(stderr, "\n");
delta[(int) Lseek][Elapsed] = last_stop - first_start;
if (html)
write_html(machine, size);
else
report(machine, size);
unlink(name);
}
static void
write_html(
char * machine,
off_t size)
{
printf("<TR><TD>%s</TD><TD>%d</TD>", machine, size / (1024 * 1024));
printf("<TD>%d</TD><TD>%4.1f</TD><TD>%d</TD><TD>%4.1f</TD><TD>%d</TD><TD>%4.1f</TD>",
(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);
printf("<TD>%d</TD><TD>%4.1f</TD><TD>%d</TD><TD>%4.1f</TD>",
(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);
printf("<TD>%5.1f</TD><TD>%4.1f</TD></TR>\n",
((double) Seeks) / delta[(int) Lseek][Elapsed],
delta[(int) Lseek][CPU] / delta[(int) Lseek][Elapsed] * 100.0);
}
static void
report(
char * machine,
off_t size)
{
printf(" ");
printf(
"-------Sequential Output-------- ---Sequential Input-- --Random--\n");
printf(" ");
printf(
"-Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---\n");
printf("Machine MB ");
printf("K/sec %%CPU K/sec %%CPU K/sec %%CPU K/sec %%CPU K/sec ");
printf("%%CPU /sec %%CPU\n");
printf("%-8.8s %4d ", machine, size / (1024 * 1024));
printf("%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);
printf("%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);
printf("%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,
FILE * * stream,
int create)
{
if (create)
{ /* create from scratch */
if (unlink(name) == -1 && *fd != -1)
io_error("unlink");
*fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0777);
} /* create from scratch */
else
*fd = open(name, O_RDWR, 0777);
if (*fd == -1)
io_error(name);
*stream = fdopen(*fd, "r+");
if (*stream == NULL)
io_error("fdopen");
}
static void
usage()
{
fprintf(stderr,
"usage: Bonnie [-d scratch-dir] [-s size-in-Mb] [-html] [-m machine-label]\n");
exit(1);
}
static void
timestamp()
{
last_timestamp = time_so_far();
last_cpustamp = cpu_so_far();
}
static void
get_delta_t(test)
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()
{
#if defined(SysV)
struct tms tms;
if (times(&tms) == -1)
io_error("times");
return ((double) tms.tms_utime) / ((double) sysconf(_SC_CLK_TCK)) +
((double) tms.tms_stime) / ((double) sysconf(_SC_CLK_TCK));
#else
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
return
((double) rusage.ru_utime.tv_sec) +
(((double) rusage.ru_utime.tv_usec) / 1000000.0) +
((double) rusage.ru_stime.tv_sec) +
(((double) rusage.ru_stime.tv_usec) / 1000000.0);
#endif
}
static double
time_so_far()
{
#if defined(SysV)
int val;
struct tms tms;
if ((val = times(&tms)) == -1)
io_error("times");
return ((double) val) / ((double) sysconf(_SC_CLK_TCK));
#else
struct timeval tp;
if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
io_error("gettimeofday");
return ((double) (tp.tv_sec - basetime)) +
(((double) tp.tv_usec) / 1000000.0);
#endif
}
static void
io_error(char * message)
{
char buf[Chunk];
sprintf(buf, "Bonnie: drastic I/O error (%s)", message);
perror(buf);
exit(1);
}
/*
* 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.
* The 'where' argument is used as a chunk number
* 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.
*/
static void
doseek(
off_t where,
int fd,
int update)
{
int buf[Chunk / IntSize];
off_t probe;
off_t size;
probe = where * Chunk;
if (lseek(fd, probe, 0) != probe)
io_error("lseek 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) random() % (size/IntSize - 2)) + 1]--;
if (lseek(fd, (long) probe, 0) != probe)
io_error("lseek in doseek update");
if (write(fd, (char *) buf, size) == -1)
io_error("write in doseek");
} /* update this block */
}
#if defined(SysV)
static char randseed[32];
static void
srandom(int seed)
{
sprintf(randseed, "%06d", seed);
}
static long
random()
{
return nrand48(randseed);
}
#endif

View File

@ -1,6 +0,0 @@
SubDir HAIKU_TOP src tests system libroot posix bonnie ;
SimpleTest bonnie :
Bonnie.c
;

View File

@ -1,92 +0,0 @@
.\"-------
.\" Man page portability notes
.\"
.\" These are some notes on conventions to maintain for greatest
.\" portability of this man page to various other versions of
.\" nroff.
.\"
.\" When you want a \ to appear in the output, use \e in the man page.
.\" (NOTE this comes up in the rc grammar, where to print out '\n' the
.\" man page must contain '\en'.)
.\"
.\" Evidently not all versions of nroff allow the omission of the
.\" terminal " on a macro argument. Thus what could be written
.\"
.\" .Cr "exec >[2] err.out
.\"
.\" in true nroffs must be written
.\"
.\" .Cr "exec >[2] err.out"
.\"
.\" instead.
.\"
.\" Use symbolic font names (e.g. R, I, B) instead of the standard
.\" font positions 1, 2, 3. Note that for Xf to work the standard
.\" font names must be single characters.
.\"
.\" Note that sentences should end at the end of a line. nroff and
.\" troff will supply the correct intersentence spacing, but only if
.\" the sentences end at the end of a line. Explicit spaces, if given,
.\" are apparently honored and the normal intersentence spacing is
.\" supressed.
.\"
.\" DaviD W. Sanderson
.\"-------
.\" Dd distance to space vertically before a "display"
.\" These are what n/troff use for interparagraph distance
.\"-------
.if t .nr Dd .4v
.if n .nr Dd 1v
.\"-------
.\" Sp space down the interparagraph distance
.\"-------
.de Sp
.sp \\n(Ddu
..
.\"-------
.\" Ds begin a display, indented .5 inches from the surrounding text.
.\"
.\" Note that uses of Ds and De may NOT be nested.
.\"-------
.de Ds
.Sp
.in +0.5i
.nf
..
.\"-------
.\" De end a display (no trailing vertical spacing)
.\"-------
.de De
.fi
.in
..
.TH Bonnie 1 "2.0.6" Textuality
.SH NAME
Bonnie - File system benchmark
.SH "SYNOPSIS"
.B Bonnie
.RI "[-d\ scratch-dir]"
.RI "[-html]"
.RI "[-m\ machine-label]"
.RI "[-s\ size-in-Mb]"
.SH "OPTIONS"
.PP
-d scratch-dir : Write scratch file in named directory (default: ".")
-html : Generate HTML output
-m machine-label : use <machine-label> to label report
-s size-in-Mb : how many Mb to use for testing (default: 100)
.\"-------
.SH "DESCRIPTION"
.\"-------
.I Bonnie
measures the performance of UNIX filesystem operations.
For details, see http://www.textuality.com/bonnie/
.\"-------
.SH "AUTHOR"
.\"-------
.I Bonnie
was written by Tim Bray,
(tbray@textuality.com),
.I Bonnie
is copyrighted 1990-1996 by Tim Bray.
For details, see http://www.textuality.com/bonnie/copyright.html