move to github, opensource.conformal.com is going away. from dhill.

also, use source files on github rather than as files in the ports tree.
This commit is contained in:
sthen 2016-03-11 19:43:45 +00:00
parent 34234fc77f
commit 1231aed82d
5 changed files with 12 additions and 991 deletions

View File

@ -1,27 +1,26 @@
# $OpenBSD: Makefile,v 1.24 2013/03/11 11:41:30 espie Exp $
# $OpenBSD: Makefile,v 1.25 2016/03/11 19:43:45 sthen Exp $
COMMENT= i/o generator
PKGNAME= iogen-3.1
REVISION= 1
CATEGORIES= sysutils
DISTFILES=
HOMEPAGE= http://opensource.conformal.com/wiki/Iogen
V= 3.1
REVISION= 2
GH_TAGNAME= IOGEN_${V:S/./_/g}
GH_ACCOUNT= conformal
GH_PROJECT= iogen
DISTNAME= ${GH_PROJECT}-${V}
CATEGORIES= sysutils
HOMEPAGE= https://github.com/conformal/iogen
# ISC
PERMIT_PACKAGE_CDROM= Yes
WANTLIB= c
NO_CHECKSUM= Yes
NO_TEST= Yes
CFLAGS+= -DVERSION=\"${PKGNAME:S/iogen-//}\"
FAKE_FLAGS+= BINDIR="${PREFIX}/bin" MANDIR="${PREFIX}/man/man"
MAKE_ENV= CC="${CC}"
WRKDIST= ${WRKDIR}
post-extract:
@lndir ${.CURDIR}/src ${WRKDIR}
.include <bsd.port.mk>

2
sysutils/iogen/distinfo Normal file
View File

@ -0,0 +1,2 @@
SHA256 (iogen-3.1.tar.gz) = xIRbsdkm24LNBz1vvddDQABinmfgI3UhWMOwWy6/tdE=
SIZE (iogen-3.1.tar.gz) = 7352

View File

@ -1,7 +0,0 @@
PROG= iogen
SRCS= iogen.c
CFLAGS+=-Wall
MAN= iogen.8
BINDIR= ${PREFIX}/bin
.include <bsd.prog.mk>

View File

@ -1,153 +0,0 @@
.\" $OpenBSD: iogen.8,v 1.8 2007/05/18 14:48:16 marco Exp $
.\"
.\" Copyright (c) 2005 Marco Peereboom <marco@peereboom.us>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd December 6, 2005
.Dt IOGEN 8
.Os
.Sh NAME
.Nm iogen
.Nd I/O generator
.Sh SYNOPSIS
.Nm iogen
.Bk -words
.Op Fl kr
.Op Fl b Ar max-io-size
.Op Fl d Ar target-directory
.Op Fl f Ar result-directory
.Op Fl n Ar nr-forks
.Op Fl p Ar read-percentage
.Op Fl s Ar max-file-size
.Op Fl t Ar update-time
.Ek
.Sh DESCRIPTION
.Nm
is a lightweight tool that generates heavily fragmented I/O.
It accomplishes this by forking a number of children that run I/O to a
filesystem.
.Pp
This tool is intended to test storage stacks under stress and worst case
scenarios.
However due to heavy fragmentation of the I/O files,
it tends to bypass caching algorithms in storage stacks.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl b Ar max-io-size
This is the fixed I/O size unless the -r flag is set.
The default is 64KB.
.It Fl d Ar target-directory
This is the directory where the I/O file will be written to.
The default is the current working directory.
.It Fl f Ar result-directory
This is the directory where the result file will be written to.
The result file is updated every
.Ar update-time
seconds with statistics.
The default is the current working directory.
.It Fl k
Kill all running
.Nm
processes.
.It Fl n Ar nr-forks
This will determine how many identical processes will be forked to run I/O.
The default is 1.
.It Fl p Ar read-percentage
This determins the read vs write distribution.
The range is from 10% to 90%.
The default is 50.
.It Fl P Ar pattern
Pattern is a whole number that designates the IO pattern. The default is a
text pattern that is human readable. Use ? to print out the available
patterns.
.It Fl r
Randomize I/O size between 1 and
.Ar max-io-size .
Enabling this flag will disable data verification.
The default is disabled.
.It Fl s Ar max-file-size
The file where the I/O is run to and from will grow sequentially until it is
bigger or equal to this value.
At that point all write I/O will also become random.
The default is 1GB.
.It Fl t Ar update-time
This determines the minimal amount of time between updates.
Under heavy I/O this value can be skewed due to
the asynchronous nature of
.Xr alarm 3 .
The default is 60 seconds.
.It Fl T Ar I/O timeout
This determines the maximum time an I/O run is allowed to take to complete.
If the timeout is reached all iogen processes will be terminated.
The default is disabled.
.El
.Pp
Although the algorithm for I/O generation is incredibly simple,
it has proven to be very effective at
bringing out issues in storage stacks.
It first grows the initial file a minimal amount to be able to start running
I/O in it.
After the initial growth,
it reads randomly within the current file size.
Every run is a distribution between reads and writes which is governed by
the read percentage value.
The file is grown sequentially until it reaches maximum file size.
Whenever this happens a message is logged to syslogd(8) and all writes become
random.
.Pp
To monitor progress one can
.Xr tail 1
the result file which is updated every
.Ar update-time
interval or send the process a
.Dv HUP
signal.
Whenever an I/O process receives a
.Dv HUP
signal, it prints statistical values to
.Xr stderr 4
at its earliest convenience.
.Pp
Whenever iogen runs into data corruption or a failed read or write it will
terminate all child processes.
.Sh EXAMPLES
Run iogen with all defaults in the current working directory:
.Pp
.Dl $ iogen
.Pp
Run
.Nm
with all defaults and a 1 second result file update:
.Pp
.Dl $ iogen -t 1
.Pp
Run
.Nm
with a 2GB max file, 128KB I/O size, and result file in
.Pa /tmp :
.Pp
.Bd -literal -offset indent
$ iogen -s 2g -b 128k -t 1 -f /tmp
.Ed
.Sh HISTORY
The first version of
.Nm
was written in 2005.
.Sh AUTHORS
.An Marco Peereboom Aq marco@peereboom.us
.Sh CAVEATS
This tool is capable of running extremely heavy I/O.
It is known to have broken hardware before so please use caution and don't
complain if something bad happens.

View File

@ -1,820 +0,0 @@
/* $OpenBSD: iogen.c,v 1.9 2007/05/18 14:48:16 marco Exp $ */
/*
* Copyright (c) 2005 Marco Peereboom <marco@peereboom.us>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#define LOGFATAL 0x01
#define LOGERR 0x02
#define LOGKILLALL 0x04
#define MINFILESIZE (262400llu)
#define MAXFILESIZE (10737418240llu)
#define MAXIOSIZE (10485760llu)
#define MINIOSIZE (1llu)
/* protos */
void err_log(int, const char *, ...);
/* signal handler flags */
volatile sig_atomic_t run = 1;
volatile sig_atomic_t print_stats = 0;
volatile sig_atomic_t update_res = 0;
/* globals */
off_t file_size;
off_t io_size;
int interval;
int timeout = -1;
int read_perc;
int randomize;
char target_dir[MAXPATHLEN];
char result_dir[MAXPATHLEN];
enum iog_pat_id {
IOGEN_PAT_BLINK4,
IOGEN_PAT_BLINK8,
IOGEN_PAT_BLINK16,
IOGEN_PAT_BLINK32,
IOGEN_PAT_BLINK64,
IOGEN_PAT_0,
IOGEN_PAT_5,
IOGEN_PAT_A,
IOGEN_PAT_F,
IOGEN_PAT_A5,
IOGEN_PAT_A5_BLINK,
IOGEN_PAT_AA55,
IOGEN_PAT_AA55_BLINK,
IOGEN_PAT_AAAA5555,
IOGEN_PAT_AAAA5555_BLINK,
IOGEN_PAT_AAAAAAA55555555,
IOGEN_PAT_A5_BLINK64,
IOGEN_PAT_BLINK1_64,
IOGEN_PAT_BLINK2_64,
IOGEN_PAT_BLINK4_64,
IOGEN_PAT_BLINK8_64,
IOGEN_PAT_WALK64,
IOGEN_PAT_WALK128,
IOGEN_PAT_COUNT,
IOGEN_PAT_TEXT, /* must be last entry */
};
enum iog_pat_id pattern = IOGEN_PAT_TEXT;
#define MAX_PAT_SIZE 512
struct iog_pattern {
size_t size;
enum iog_pat_id pattern;
u_int8_t buf[MAX_PAT_SIZE];
};
char *io_pattern[] = {
"The quick brown fox jumps over the lazy dog. ",
"tHE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. ",
"boo hoo hoo iogen is hurting my little disks ",
NULL
};
/* externs */
extern char *__progname;
void
killall(void)
{
char s[MAXPATHLEN];
switch (fork()) {
case -1:
err_log(LOGERR | LOGFATAL, "could not kill all processes");
/* NOTREACHED */
break;
case 0:
/* XXX clean this up */
sleep(2); /* wait until dad dies */
snprintf(s, sizeof s, "/usr/bin/pkill %s", __progname);
system(s);
exit(0);
/* NOTREACHED */
default:
exit(0);
/* NOTREACHED */
break;
}
}
void
err_log(int flags, const char *fmt, ...)
{
va_list ap;
char buf[256];
int errno_save = errno;
va_start(ap, fmt);
vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
if (flags & LOGERR)
snprintf(buf, sizeof buf, "%s: %s", buf, strerror(errno_save));
syslog(flags & LOGFATAL ? LOG_CRIT : LOG_NOTICE, buf);
if (flags & LOGKILLALL)
killall();
if (flags & LOGFATAL)
exit(1);
}
int
get_pattern(int pat, struct iog_pattern *ip)
{
u_int64_t scratch[MAX_PAT_SIZE / sizeof(u_int64_t)];
u_int32_t s = 0;
u_int8_t *p;
int x;
if (!ip)
return (1);
memset(scratch, 0, MAX_PAT_SIZE / sizeof(u_int64_t));
switch (pat) {
case IOGEN_PAT_BLINK64:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0xffffffffffffffffllu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_BLINK32:
scratch[s++] = 0xffffffff00000000llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_BLINK16:
scratch[s++] = 0xffff0000ffff0000llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_BLINK8:
scratch[s++] = 0xff00ff00ff00ff00llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_BLINK4:
scratch[s++] = 0xf0f0f0f0f0f0f0f0llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_0:
scratch[s++] = 0x0000000000000000llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_5:
scratch[s++] = 0x5555555555555555llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_A:
scratch[s++] = 0xaaaaaaaaaaaaaaaallu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_F:
scratch[s++] = 0xffffffffffffffffllu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_A5:
scratch[s++] = 0xa5a5a5a5a5a5a5a5llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_A5_BLINK:
scratch[s++] = 0xa55aa55aa55aa55allu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_AA55:
scratch[s++] = 0xaa55aa55aa55aa55llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_AA55_BLINK:
scratch[s++] = 0xaa55aa5555aa55aallu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_AAAA5555:
scratch[s++] = 0xaaaa5555aaaa5555llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_AAAA5555_BLINK:
scratch[s++] = 0xaaaa55555555aaaallu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_AAAAAAA55555555:
scratch[s++] = 0xaaaaaaaa55555555llu;
ip->size = sizeof(scratch[0]);
break;
case IOGEN_PAT_BLINK1_64:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x1111111111111111llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_BLINK2_64:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x2222222222222222llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_BLINK4_64:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x4444444444444444llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_BLINK8_64:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x8888888888888888llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_A5_BLINK64:
scratch[s++] = 0xaaaaaaaaaaaaaaaallu;
scratch[s++] = 0x5555555555555555llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_WALK64:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x0101010101010101llu;
scratch[s++] = 0x0202020202020202llu;
scratch[s++] = 0x0404040404040404llu;
scratch[s++] = 0x0808080808080808llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_WALK128:
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x0000000000000000llu;
scratch[s++] = 0x0101010101010101llu;
scratch[s++] = 0x0101010101010101llu;
scratch[s++] = 0x0202020202020202llu;
scratch[s++] = 0x0202020202020202llu;
scratch[s++] = 0x0404040404040404llu;
scratch[s++] = 0x0404040404040404llu;
scratch[s++] = 0x0808080808080808llu;
scratch[s++] = 0x0808080808080808llu;
ip->size = sizeof(scratch[0]) * s;
break;
case IOGEN_PAT_COUNT:
p = (u_int8_t *)&scratch;
for (x = 0; x < 256; x++)
*p++ = x;
ip->size = x;
break;
case IOGEN_PAT_TEXT:
ip->pattern = pat;
return (0);
default:
return (1);
}
ip->pattern = pat;
memcpy(ip->buf, scratch, ip->size);
return (0);
}
void
show_patterns(void)
{
int i, x;
struct iog_pattern p;
printf("id\tpattern\n");
for (i = 0; i < IOGEN_PAT_TEXT; i++) {
memset(&p, 0, sizeof(p));
if (get_pattern(i, &p))
return;
printf("%d:\t", i);
for (x = 0; x < p.size; x++) {
if ((x != 0) && (x % (sizeof(u_int64_t) * 4)) == 0)
printf("\n\t");
printf("%02x", p.buf[x]);
}
printf("\n");
}
}
void
usage(void)
{
fprintf(stderr, "%s version %s\n", __progname, VERSION);
fprintf(stderr, "usage: %s [-rk] [-s size] [-b size] [-p percentage] "
"[-d path] [-f path] [-n processes] [-t interval]\n", __progname);
fprintf(stderr, "-h this help\n");
fprintf(stderr, "-s <file size> [k|m|g]; Default = 1g\n");
fprintf(stderr, "-b <io size> [k|m]; Default = 64k\n");
fprintf(stderr, "-p <read percentage>; Default = 50\n");
fprintf(stderr, "-r randomize io block size; Default = no\n");
fprintf(stderr, "-d <target directory>; Default = current directory\n");
fprintf(stderr, "-f <result directory>; Default = iogen.res\n");
fprintf(stderr, "-n <number of io processes>; Default = 1\n");
fprintf(stderr, "-t <seconds between update>; Default = 60 seconds\n");
fprintf(stderr, "-T <seconds to timeout io>; Default = disabled\n");
fprintf(stderr, "-P <payload pattern>; ? displays patterns, Default = readable text\n");
fprintf(stderr, "-k kill all running io processes\n\n");
fprintf(stderr, "If parameters are omited defaults will be used.\n");
exit(0);
}
unsigned long long
quantify(char quant)
{
unsigned long long val;
if (isdigit(quant))
return (1);
quant = tolower(quant);
switch (quant) {
case 'k':
val = 1024;
break;
case 'm':
val = 1024 * 1024;
break;
case 'g':
val = 1024 * 1024 * 1024;
break;
default:
errx(1, "invalid quantifier");
/* NOTREACHED */
break;
}
return (val);
}
void
sigterm(int sig)
{
run = 0;
}
void
sighup(int sig)
{
print_stats = 1;
}
void
sigalarm(int sig)
{
update_res = 1;
}
void
sigtimeout(int sig)
{
/*
* XXX we can't set a flag because IO is wedged; terminate program.
* traditional race conditions are (mostly) not applicable because
* the main loop is not running. This is not pretty but it should
* work.
*/
err_log(LOGFATAL | LOGKILLALL,
"i/o timeout (%ds) in process %i", timeout, getpid());
}
void
fill_buffer(char *buffer, size_t size, int pat)
{
long long i = 0, more = 1;
char *p = buffer;
size_t copy_len;
struct iog_pattern ip;
memset(&ip, 0, sizeof(ip));
if (get_pattern(pat, &ip))
err_log(LOGFATAL, "can't find pattern %d", pat);
/* this really should become a regular pattern */
if (ip.pattern == IOGEN_PAT_TEXT) {
while (more) {
if (io_pattern[i] == NULL)
i = 0;
copy_len = strlen(io_pattern[i]);
if ((p + copy_len) > (buffer + size))
copy_len = (buffer + size) - p;
memcpy(p, io_pattern[i], copy_len);
p += copy_len;
i++;
if (p == buffer + size)
more = 0;
else if (p > buffer + size)
err_log(LOGFATAL,
"buffer overflow in fill pattern");
}
return;
}
/* fill buffer for non text pattern */
for (i = 0; i < size; i++)
buffer[i] = ip.buf[i % ip.size];
}
off_t
get_file_size(char *filename)
{
struct stat sb;
if (stat(filename, &sb) == -1)
err_log(LOGFATAL | LOGERR,
"stat failed in proces %i", getpid());
return (sb.st_size);
}
void
save_buffers(void *src, void *dst, off_t len)
{
char s[MAXPATHLEN];
FILE *sf, *df;
snprintf(s, sizeof s, "/tmp/dst.%d", getpid());
df = fopen(s, "w+");
if (!df)
err_log(LOGERR | LOGFATAL, "could not open dst");
snprintf(s, sizeof s, "/tmp/src.%d", getpid());
sf = fopen(s, "w+");
if (!sf)
err_log(LOGERR| LOGFATAL, "could not open src");
if (!fwrite(src, io_size, 1, sf))
err_log(LOGERR| LOGFATAL, "could not write /tmp/src.%d",
getpid());
if (!fwrite(dst, io_size, 1, df))
err_log(LOGERR| LOGFATAL, "could not write /tmp/dst.%d",
getpid());
fclose(sf);
fclose(df);
}
int
run_io(void)
{
pid_t pid;
int rv;
unsigned int i, max_reads, max_writes;
char *src, *dst;
char path_buf[MAXPATHLEN];
FILE *iofile, *resfile;
off_t io_spot;
size_t rand_buf;
int reached_max = 0;
time_t tm;
/* statistics */
off_t total = 0, read_total = 0, write_total = 0;
off_t write_block = 0, read_block = 0;
switch (pid = fork()) {
case -1:
err_log(LOGERR | LOGFATAL, "could not fork");
/* NOTREACHED */
break;
case 0:
break;
default:
return (pid);
/* NOTREACHED */
break;
}
/* child */
if (signal(SIGTERM, sigterm) == SIG_ERR)
err_log(LOGERR | LOGFATAL,
"could not install TERM handler in process %i",
getpid());
if (signal(SIGHUP, sighup) == SIG_ERR)
err_log(LOGERR | LOGFATAL,
"could not install HUP handler in process %i",
getpid());
if (signal(SIGALRM, sigalarm) == SIG_ERR)
err_log(LOGERR | LOGFATAL,
"could not install ALARM handler in process %i",
getpid());
if (timeout != -1)
if (signal(SIGALRM, sigtimeout) == SIG_ERR)
err_log(LOGERR | LOGFATAL,
"could not install TIMEOUT handler in process %i",
getpid());
/* poor mans memory test */
src = malloc(io_size);
if (!src)
err_log(LOGERR | LOGFATAL, "malloc failed in process %i",
getpid());
fill_buffer(src, io_size, pattern);
dst = malloc(io_size);
if (!dst)
err_log(LOGERR | LOGFATAL, "malloc failed in process %i",
getpid());
fill_buffer(dst, io_size, pattern);
if (memcmp(src, dst, io_size) != 0)
err_log(LOGFATAL,
"source and destination buffer not the same");
if (realpath(target_dir, path_buf) == NULL)
err_log(LOGERR | LOGFATAL, "invalid destination path %s",
target_dir);
rv = snprintf(target_dir, sizeof target_dir, "%s/%s_%i.io",
path_buf, __progname, getpid());
if (rv == -1 || rv > sizeof target_dir)
err_log(LOGERR | LOGFATAL,
"destination path name invalid or too long");
iofile = fopen(target_dir, "w+");
if (!iofile)
err_log(LOGERR | LOGFATAL, "could not create io file");
if (realpath(result_dir, path_buf) == NULL)
err_log(LOGERR | LOGFATAL,
"invalid result path %s", result_dir);
rv = snprintf(result_dir, sizeof result_dir, "%s/%s_%i.res",
path_buf, __progname, getpid());
if (rv == -1 || rv > sizeof result_dir)
err_log(LOGERR | LOGFATAL,
"result path name invalid or too long");
resfile = fopen(result_dir, "w+");
if (!resfile)
err_log(LOGERR | LOGFATAL, "could not create res file");
for (i = 0; i < 10; i++) {
write_block = fwrite(src, io_size, 1, iofile);
if (write_block != 1)
err_log(LOGERR | LOGFATAL,
"could not write initial file data in %i",
getpid());
total += write_block * io_size;
write_total = total;
}
alarm(interval);
max_reads = read_perc / 5;
max_writes = (100 - read_perc) / 5;
while (run) {
if (print_stats) {
print_stats = 0;
time(&tm);
fprintf(stderr,
"%.15s: total: %llu read: %llu write: %llu\n",
ctime(&tm) + 4, total, read_total , write_total);
fflush(stderr);
}
if (update_res) {
update_res = 0;
time(&tm);
fprintf(resfile,
"%.15s: total: %llu read: %llu write: %llu\n",
ctime(&tm) + 4, total, read_total , write_total);
fflush(resfile);
alarm(interval);
}
if (timeout != -1)
alarm(timeout);
/* reads */
for (i = 0; i < max_reads; i++) {
io_spot = get_file_size(target_dir) / io_size - 1;
io_spot = (arc4random() % io_spot + 1) * io_size;
rand_buf = 0;
if (randomize)
rand_buf = arc4random() % io_size;
fseeko(iofile, io_spot, SEEK_SET);
read_block = fread(dst, io_size - rand_buf, 1, iofile);
if (read_block) {
total += io_size - rand_buf;
read_total += io_size - rand_buf;
}
else
err_log(LOGFATAL | LOGERR | LOGKILLALL,
"could not read from file in process %i",
getpid());
if (!randomize)
if (memcmp(src, dst, io_size) != 0) {
save_buffers(src, dst, io_size);
err_log(LOGFATAL | LOGKILLALL,
"data corruption in process %i;"
"buffers saved to /tmp",
getpid());
}
}
/* writes */
for (i = 0; i < max_writes; i++) {
if (!reached_max)
fseeko(iofile, 0, SEEK_END);
else {
io_spot = get_file_size(target_dir) /
io_size - 1;
io_spot = (arc4random() % io_spot + 1) *
io_size;
fseeko(iofile, io_spot, SEEK_SET);
}
rand_buf = 0;
if (randomize)
rand_buf = arc4random() % io_size;
write_block = fwrite(src, io_size - rand_buf,
1, iofile);
if (write_block) {
total += io_size - rand_buf;
write_total += io_size - rand_buf;
}
else
err_log(LOGFATAL | LOGERR | LOGKILLALL,
"could not write to file in process %i",
getpid());
}
if (write_total >= file_size) {
if (reached_max != 1)
err_log(0, "file reached maximum size in "
"process %i\n", getpid());
reached_max = 1;
}
}
err_log(0, "%i exiting with total: %llu read: %llu write: %llu",
getpid(), total, read_total , write_total);
free(src);
free(dst);
fclose(iofile);
fclose(resfile);
exit(0);
/* NOTREACHED */
return (0);
}
int
main(int argc, char *argv[])
{
int ch;
int i, nr_proc = 1;
struct stat sb;
/* set defaults */
io_size = 64 * 1024;
file_size = 1 * 1024 * 1024 * 1024;
read_perc = 50;
randomize = 0;
interval = 60;
strlcpy(target_dir, "./", sizeof target_dir);
strlcpy(result_dir, "./", sizeof result_dir);
while ((ch = getopt(argc, argv, "b:d:f:kn:p:rs:t:T:P:")) != -1) {
switch (ch) {
case 'b':
io_size = atoll(optarg) *
quantify(optarg[strlen(optarg) - 1]);
if (io_size < MINIOSIZE)
errx(1, "io block size too small");
if (io_size > MAXIOSIZE)
errx(1, "io block size too large");
break;
case 'd':
if (stat(optarg, &sb) == -1)
err(1, "stat failed");
else
if (sb.st_mode & S_IFDIR)
strlcpy(target_dir, optarg,
sizeof target_dir);
else
errx(1, "invalid target path");
break;
case 'f':
if (stat(optarg, &sb) == -1)
err(1, "stat failed");
else
if (sb.st_mode & S_IFDIR)
strlcpy(result_dir, optarg,
sizeof result_dir);
else
errx(1, "invalid result path");
break;
case 'k':
killall();
/* NOTREACHED */
break;
case 'n':
nr_proc = atol(optarg);
if (nr_proc < 1)
errx(1, "invalid number of processes");
break;
case 'p':
read_perc = atol(optarg);
if (read_perc < 10)
errx(1, "read percentage size too small");
if (read_perc > 90)
errx(1, "read percentage size too large");
break;
case 'r':
randomize = 1;
break;
case 's':
file_size = atoll(optarg) *
quantify(optarg[strlen(optarg) - 1]);
if (file_size < MINFILESIZE)
errx(1, "file size too small");
if (file_size > MAXFILESIZE)
errx(1, "file size too large");
break;
case 't':
interval = atoi(optarg);
if (interval < 1)
errx(1, "time slice too small");
if (interval > 3600)
errx(1, "time slice too large");
break;
case 'T':
timeout = atoi(optarg);
if (timeout < 1)
errx(1, "time slice too small");
if (timeout > 3600)
errx(1, "time slice too large");
break;
case 'P':
if (optarg[0] == '?') {
show_patterns();
exit(0);
}
pattern = atoi(optarg);
if (pattern > IOGEN_PAT_TEXT)
errx(1, "illegal pattern");
break;
case 'h':
default:
usage();
/* NOTREACHED */
break;
}
}
err_log(0, "%s test run commences with %u proc(s)",
VERSION, nr_proc);
err_log(0,
"file size: %llu io size: %llu read percentage: %i random: %s "
"target: %s result: %s update interval: %i",
file_size, io_size, read_perc, randomize ? "yes" : "no",
target_dir, result_dir, interval);
for (i = 0; i < nr_proc; i++)
fprintf(stderr, "child spawned %i\n", run_io());
return (0);
}