[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RE: [Qemu-devel][PATCH] block level testing/execersing utility
From: |
Shahar Frank |
Subject: |
RE: [Qemu-devel][PATCH] block level testing/execersing utility |
Date: |
Thu, 28 Aug 2008 05:22:03 -0700 |
> From: address@hidden [mailto:qemu-
> address@hidden On Behalf Of Samuel
> Thibault
> Sent: Thursday, August 28, 2008 12:47 PM
> To: address@hidden
> Subject: Re: [Qemu-devel][PATCH] block level testing/execersing utility
>
> Shahar Frank, le Thu 28 Aug 2008 02:27:13 -0700, a écrit :
> > can do also multiple threading.
> >
> > + arg->offset = random() * arg->blocksize;
>
> Take care: random() uses a central mutex for safety. Use rand_r or
> rand48_r instead.
>
> Samuel
>
Thanks. Attached is a fixed version. I also replaced seek + read/write with
pread/pwrite.
Shahar
Index: btest/btest.c
===================================================================
--- btest/btest.c (revision 0)
+++ btest/btest.c (revision 0)
@@ -0,0 +1,759 @@
+/*
+ * Block test/exerciser utility
+ *
+ * Copyright (c) 2008 Shahar Frank
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/syscall.h> /* For SYS_xxx definitions */
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+#define BTEST_VERSION 1
+
+int secs = 60;
+int threads = 1;
+int def_blocksize = 4 * 1024;
+int openflags = O_CREAT | O_LARGEFILE | O_NOATIME | O_SYNC;
+int write_behind;
+
+char *prog;
+int debug;
+int dorandom;
+int doread;
+int rseed;
+
+typedef struct IOStats {
+ char *title;
+ uint64_t duration;
+ uint64_t sduration; /* sync duration */
+ uint64_t lat;
+ uint64_t ops;
+ uint64_t bytes;
+ uint64_t errors;
+} IOStats;
+
+struct shared {
+ pthread_cond_t start_cond;
+ pthread_mutex_t lock;
+ int started;
+ int finished;
+ IOStats total;
+} shared = {
+ PTHREAD_COND_INITIALIZER,
+ PTHREAD_MUTEX_INITIALIZER,
+ };
+
+volatile int finished;
+
+/** printf style debugging MACRO, conmmon header includes name of function */
+#define WARN(fmt, args...) warn(__FUNCTION__, fmt, ## args)
+
+/** printf style abort MACRO, conmmon header includes name of function */
+#define PANIC(fmt, args...) panic(__FUNCTION__, fmt, ## args)
+
+#define DEBUG(fmt, args...) if (debug) warn(__FUNCTION__, fmt, ## args)
+#define DEBUG2(fmt, args...) if (debug > 1) warn(__FUNCTION__, fmt, ## args)
+#define DEBUG3(fmt, args...) if (debug > 2) warn(__FUNCTION__, fmt, ## args)
+
+#ifndef BLKGETSIZE
+#define BLKGETSIZE _IO(0x12,96)
+#endif
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+#endif
+
+uint64_t
+timestamp(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+/**
+ * Show a message and abort the probram.
+ * @param fn the name of the calling function
+ * @param msg printf style message string
+ */
+void panic(const char *fn, char *msg, ...)
+{
+ char buf[512];
+ va_list va;
+ int n;
+
+ va_start(va, msg);
+ n = vsprintf(buf, msg, va);
+ va_end(va);
+ buf[n] = 0;
+
+ fprintf(stderr, "PANIC: [%d:%" PRId64 "] %s: %s%s%s\n", getpid(),
timestamp(), fn, buf, errno ? ": " : "", errno ? strerror(errno) : "");
+
+ exit(-1);
+}
+
+/**
+ * Print a message to the stderr.
+ * @param fn the name of the calling function
+ * @param msg printf style message string
+ */
+void warn(const char *fn, char *msg, ...)
+{
+ char buf[512];
+ va_list va;
+ int n;
+
+ va_start(va, msg);
+ n = vsprintf(buf, msg, va);
+ va_end(va);
+ buf[n] = 0;
+
+ fprintf(stderr, "[%s:%d:%" PRId64 "]: %s: %s\n", "btest", getpid(),
timestamp(), fn, buf);
+}
+
+uint64_t parse_storage_size(char *arg)
+{
+ int l = strlen(arg);
+ uint64_t factor = 1;
+
+ arg = strdupa(arg);
+ switch (arg[l - 1]) {
+ case 'G':
+ case 'g':
+ factor = 1 << 30;
+ break;
+ case 'M':
+ case 'm':
+ factor = 1 << 20;
+ break;
+ case 'K':
+ case 'k':
+ factor = 1 << 10;
+ break;
+ case 'B':
+ case 'b':
+ factor = 512;
+ break;
+ default:
+ l++;
+ }
+ arg[l] = 0;
+ return strtoull(arg, 0, 0) * factor;
+}
+
+static int64_t
+blockdev_getsize(int fd)
+{
+ int64_t b;
+ long sz;
+ int err;
+
+ err = ioctl (fd, BLKGETSIZE, &sz);
+ if (err)
+ return err;
+
+ err = ioctl(fd, BLKGETSIZE64, &b);
+ if (err || b == 0 || b == sz)
+ b = sz << 9;
+ return b;
+}
+
+static int64_t
+getsize(int fd)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0) {
+ WARN("fstat failed: %m");
+ return -1;
+ }
+
+ if (S_ISBLK(st.st_mode))
+ return blockdev_getsize(fd);
+
+ if (S_ISREG(st.st_mode))
+ return st.st_size;
+
+ WARN("unsupported file type");
+ return -1;
+}
+
+typedef struct worker_arg {
+ int fd;
+ int blocksize;
+ char *file;
+ int64_t size;
+ loff_t offset;
+ loff_t startoffset;
+ loff_t endoffset;
+ int randomratio;
+ int readratio;
+ void *buf;
+ pid_t tid;
+ int (*io)(struct worker_arg *);
+ struct drand48_data rbuf;
+ IOStats stats;
+ struct worker_arg *next;
+} worker_arg;
+
+worker_arg *workers;
+
+int
+do_seq_read(worker_arg *arg)
+{
+ if (arg->offset + arg->blocksize > arg->endoffset)
+ arg->offset = arg->startoffset;
+ DEBUG3("file %s fd %d seek to offset %" PRIu64, arg->file, arg->fd,
arg->offset);
+ if (pread(arg->fd, arg->buf, arg->blocksize, arg->offset) !=
arg->blocksize)
+ return -1;
+ arg->offset += arg->blocksize;
+ return 0;
+}
+
+int
+do_seq_write(worker_arg *arg)
+{
+ if (arg->offset + arg->blocksize > arg->endoffset)
+ arg->offset = arg->startoffset;
+ DEBUG3("file %s fd %d seek to offset %" PRIu64, arg->file, arg->fd,
arg->offset);
+ if (pwrite(arg->fd, arg->buf, arg->blocksize, arg->offset) !=
arg->blocksize)
+ return -1;
+ arg->offset += arg->blocksize;
+ return 0;
+}
+
+uint64_t
+saferandom(struct drand48_data *buffer)
+{
+ double d;
+
+ drand48_r(buffer, &d);
+
+ return (uint64_t)d;
+}
+
+int
+do_rand_read(worker_arg *arg)
+{
+ arg->offset = saferandom(&arg->rbuf) * arg->blocksize;
+ if (arg->offset + arg->blocksize > arg->endoffset)
+ arg->offset = arg->startoffset + arg->offset % (arg->endoffset
- arg->startoffset - arg->blocksize);
+ DEBUG3("file %s fd %d seek to offset %" PRIu64, arg->file, arg->fd,
arg->offset);
+ if (pread(arg->fd, arg->buf, arg->blocksize, arg->offset) !=
arg->blocksize)
+ return -1;
+ arg->offset += arg->blocksize;
+ return 0;
+}
+
+int
+do_rand_write(worker_arg *arg)
+{
+ arg->offset = saferandom(&arg->rbuf) * arg->blocksize;
+ if (arg->offset + arg->blocksize > arg->endoffset)
+ arg->offset = arg->startoffset + arg->offset % (arg->endoffset
- arg->startoffset - arg->blocksize);
+ DEBUG3("file %s fd %d seek to offset %" PRIu64, arg->file, arg->fd,
arg->offset);
+ if (pwrite(arg->fd, arg->buf, arg->blocksize, arg->offset) !=
arg->blocksize)
+ return -1;
+ arg->offset += arg->blocksize;
+ return 0;
+}
+
+int
+do_io(worker_arg *arg)
+{
+ int (*io)(struct worker_arg *);
+ int doread = 0, dorandom = 0;
+
+ if (arg->readratio == 100)
+ doread = 1;
+ else if (arg->readratio == 0)
+ doread = 0;
+ else
+ doread = (saferandom(&arg->rbuf) % 100) < arg->readratio;
+
+ if (arg->randomratio == 100)
+ dorandom = 1 << 1;
+ else if (arg->randomratio == 0)
+ dorandom = 0 << 1;
+ else
+ dorandom = ((saferandom(&arg->rbuf) % 100) < arg->randomratio)
? 1 << 1 : 0 << 1;
+
+ switch (doread | dorandom) {
+ case 0:
+ DEBUG3("%s %d: seq write", arg->file, arg->tid);
+ io = do_seq_write;
+ break;
+ case 1:
+ DEBUG3("%s %d: seq read", arg->file, arg->tid);
+ io = do_seq_read;
+ break;
+ case 2:
+ DEBUG3("%s %d: random write", arg->file, arg->tid);
+ io = do_rand_write;
+ break;
+ case 3:
+ DEBUG3("%s %d: random read", arg->file, arg->tid);
+ io = do_rand_read;
+ break;
+ }
+
+ return io(arg);
+}
+
+void
+summary(char *title, IOStats *stats)
+{
+ printf("%s: %.3f seconds, %" PRIu64 " ops, avg latency %" PRIu64 "
usec, bandwidth %" PRIu64
+ " KB/s, errors %" PRIu64"\n",
+ title,
+ stats->duration * 1.0/ (double)1000000.0,
+ stats->ops,
+ stats->lat,
+ (uint64_t)(stats->bytes * 1.0 / (stats->duration / 1000000.0)
/ (1 << 10)),
+ stats->errors);
+}
+
+char *
+randomratio_str(int ratio, char *buf)
+{
+ if (ratio == 0)
+ return "S";
+ if (ratio == 100)
+ return "R";
+ else
+ sprintf(buf, "%d", ratio);
+ return buf;
+}
+
+char *
+readratio_str(int ratio, char *buf)
+{
+ if (ratio == 0)
+ return "W";
+ if (ratio == 100)
+ return "R";
+ else
+ sprintf(buf, "%d", ratio);
+ return buf;
+}
+
+int
+gettid(void)
+{
+ return syscall(__NR_gettid);
+}
+
+void
+worker_summary(worker_arg *arg)
+{
+ IOStats *stats = &arg->stats;
+
+ printf("%s %s %s %d %"PRIu64 " %" PRIu64 ": %.3f seconds, %" PRIu64
+ " ops, avg latency %" PRIu64 " usec, bandwidth %" PRIu64
+ " KB/s, errors %" PRIu64"\n",
+ arg->file,
+ randomratio_str(arg->randomratio, alloca(8)),
+ readratio_str(arg->readratio, alloca(8)),
+ arg->blocksize,
+ arg->startoffset, arg->endoffset,
+ stats->duration * 1.0 / (double)1000000.0,
+ stats->ops,
+ stats->lat,
+ (uint64_t)(stats->bytes * 1.0 / (stats->duration / 1000000.0)
/ (1 << 10)),
+ stats->errors);
+}
+
+void
+dostats(int sig)
+{
+ worker_arg *worker;
+
+ pthread_mutex_lock(&shared.lock);
+ for (worker = workers; worker; worker = worker->next)
+ worker_summary(worker);
+ pthread_mutex_unlock(&shared.lock);
+}
+
+/*char *
+parse_worker_arg(worker_arg *arg, char *line)
+{
+ char *s = line;
+
+ while (*s && !isalpha(*s))
+ s++;
+ if (!*s || (toupper(*s) != 'R' && toupeer(*s) != 'S' && !isdigit(*s))
+ return "random ratio";
+ return 0;
+}
+*/
+
+void *
+worker(worker_arg *arg)
+{
+ struct timespec t1, t2;
+ IOStats *stats = &arg->stats;
+
+ arg->tid = gettid();
+ srand48_r(rseed, &arg->rbuf);
+
+ DEBUG("%d: starting worker thread on '%s'", arg->tid, arg->file);
+
+ pthread_mutex_lock(&shared.lock);
+ shared.started++;
+ pthread_cond_wait(&shared.start_cond, &shared.lock);
+ pthread_mutex_unlock(&shared.lock);
+
+ DEBUG("%d: !! worker thread on '%s'", arg->tid, arg->file);
+ while (!finished) {
+ clock_gettime(CLOCK_REALTIME, &t1);
+ if (do_io(arg) < 0) {
+ //if (debug)
+ WARN("%d: IO error on '%s': %m", arg->tid,
arg->file);
+ stats->errors++;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &t2);
+ stats->duration += (t2.tv_sec - t1.tv_sec) * 1000000llu
+ (t2.tv_nsec - t1.tv_nsec) / 1000.0;
+ stats->ops++;
+ stats->bytes += arg->blocksize;
+ }
+ }
+ stats->lat = stats->duration / stats->ops;
+ worker_summary(arg);
+
+ pthread_mutex_lock(&shared.lock);
+ shared.finished++;
+ shared.total.errors += stats->errors;
+ shared.total.ops += stats->ops;
+ shared.total.duration += stats->duration;
+ shared.total.bytes += stats->bytes;
+ shared.total.lat += stats->lat;
+ pthread_mutex_unlock(&shared.lock);
+
+ return 0;
+}
+
+/**
+ * Create and initialize new worker thread.
+ * Returns the newly created thread ID.
+ */
+pthread_t
+new_worker(char *file, int blocksize, int randomratio, int readratio, uint64_t
start, uint64_t len)
+{
+ worker_arg *arg;
+ pthread_t thid;
+ int fd;
+
+ openflags |= (readratio == 100) ? O_RDONLY : O_RDWR;
+
+ DEBUG("open flags: 0x%x", openflags);
+ if ((fd = open(file, openflags, 0600)) < 0)
+ PANIC("open '%s' failed", file);
+
+ if (!(arg = calloc(1, sizeof *arg)))
+ PANIC("out of mem - alloc arg");
+
+ pthread_mutex_lock(&shared.lock);
+ arg->next = workers ;
+ workers = arg;
+ pthread_mutex_unlock(&shared.lock);
+
+ arg->randomratio = randomratio;
+ arg->readratio = readratio;
+ arg->fd = fd;
+ arg->file = strdup(file);
+ arg->blocksize = blocksize;
+ arg->startoffset = start;
+
+ if ((arg->size = getsize(fd)) < 0)
+ PANIC("can't get size of '%s'", file);
+
+ if (len == 0 && arg->size > arg->startoffset + blocksize)
+ len = arg->size - arg->startoffset;
+
+ arg->endoffset = arg->startoffset + len;
+ if (arg->size == 0)
+ arg->size = arg->endoffset;
+
+ DEBUG("'%s' size is %" PRId64 " using blocksize %d", file, arg->size,
arg->blocksize);
+ if (arg->endoffset - arg->startoffset < blocksize)
+ PANIC("file '%s' is too small, min size is one block (%d)",
file, blocksize);
+ if (arg->endoffset > arg->size)
+ PANIC("file '%s' offset %" PRId64 " is out of file/device size
range (%"PRId64")",
+ file, arg->endoffset, arg->size);
+
+ if (!(arg->buf = valloc(blocksize)))
+ PANIC("can't alloc buf sized %d bytes", blocksize);
+ memset(arg->buf, 0, blocksize);
+
+ if (pthread_create(&thid, NULL, (void *(*)(void *))worker, arg))
+ PANIC("thread creation failed [file %s]", file);
+
+ DEBUG("thread %d created", thid);
+ return thid;
+}
+
+int
+start(int n)
+{
+ time_t t;
+
+ pthread_mutex_lock(&shared.lock);
+ while (n > shared.started) {
+ DEBUG("wait: n %d started %d", n, shared.started);
+ pthread_mutex_unlock(&shared.lock);
+ sleep(1);
+ pthread_mutex_lock(&shared.lock);
+ }
+ pthread_mutex_unlock(&shared.lock);
+
+ time(&t);
+ printf("%d threads are ready, starting test at %s", n, ctime(&t));
+ pthread_cond_broadcast(&shared.start_cond);
+ return 0;
+}
+
+void
+flush(worker)
+{
+ worker_arg *w;
+ struct timespec t1, t2;
+ IOStats *stats;
+
+ for (w = workers; w; w = w->next) {
+ stats = &w->stats;
+ clock_gettime(CLOCK_REALTIME, &t1);
+ fsync(w->fd);
+ close(w->fd);
+ clock_gettime(CLOCK_REALTIME, &t2);
+ stats->sduration = (t2.tv_sec - t1.tv_sec) * 1000000llu +
(t2.tv_nsec - t1.tv_nsec) / 1000.0;
+ shared.total.sduration += stats->sduration;
+ }
+}
+
+int
+finish(pthread_t *thread_list, int n)
+{
+ int i;
+
+ finished = 1;
+ for (i = 0; i < n; i++) {
+ pthread_mutex_lock(&shared.lock);
+ DEBUG("wait: n %d finished %d", n, shared.finished);
+ if (shared.finished >= n)
+ break; // shread lock is still locked, but we are
alone, so it is ok
+ pthread_mutex_unlock(&shared.lock);
+
+ pthread_join(thread_list[i], NULL);
+ }
+ if (write_behind)
+ flush();
+ shared.total.duration /= n;
+ shared.total.lat /= n;
+ return 0;
+}
+
+void usage(void)
+{
+ printf("Usage: %s [-hdV -W -D -b <blocksize> -t <sec> -T
<threds_per_dev> -o <startoffset> -l <length> -S <seed>] <S|R|random-ratio>
<R|W|read-ratio> <dev/file> ...\n",
+ prog);
+ printf("\n\tDefaults:\n");
+ printf("\t\tBlocksize %d\n", def_blocksize);
+ printf("\t\tDuration in seconds %d\n", secs);
+ printf("\t\tNumber of threads per file %d\n", threads);
+ printf("\t\tThe default start offset is 0\n");
+ printf("\t\tThe default length for IO is the size of the
file/device\n");
+ printf("\t\tThe default random seed is the current time\n");
+ printf("\t\tThe default open flags are:\n");
+ printf("\t\t\t O_CREAT | O_LARGEFILE | O_NOATIME | O_SYNC\n");
+ printf("\t\tWrite behind mode (-W): O_CREAT | O_LARGEFILE | O_NOATIME
\n");
+ printf("\t\tDirect IO mode (-D): O_CREAT | O_LARGEFILE | O_NOATIME |
O_DIRECT \n");
+
+ exit(1);
+}
+
+pthread_t *thread_list;
+
+void doexit(int sig)
+{
+ time_t t;
+ finish(thread_list, shared.started);
+ summary("Total", &shared.total);
+ if (write_behind) {
+ shared.total.duration += shared.total.sduration;
+ shared.total.lat = shared.total.duration / shared.total.ops;
+ summary("Synced", &shared.total);
+ }
+ time(&t);
+ printf("Test is done at %s", ctime(&t));
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ struct timespec duration = {0}, remaining = {0};
+ int i, t, opt, nfiles, nthreads;
+ int blocksize = def_blocksize;
+ uint64_t len = 0, startoff = 0;
+
+ prog = strchr(argv[0], '/');
+ if (!prog)
+ prog = argv[0];
+ else
+ prog++;
+
+ rseed = time(0);
+
+ while ((opt = getopt(argc, argv, "+hVdt:T:b:s:o:l:S:DW")) != -1) {
+ switch (opt) {
+ default:
+ case 'h':
+ usage();
+ break;
+ case 'V':
+ printf("%s version %d\n", prog, BTEST_VERSION);
+ exit(0);
+ case 'd':
+ debug++;
+ break;
+ case 'b':
+ blocksize = parse_storage_size(optarg);
+ if (!blocksize)
+ PANIC("invalid blocksize parameter: -b %s",
+ optarg);
+ printf("IO Block size is %d\n", blocksize);
+ break;
+ case 'o':
+ startoff = parse_storage_size(optarg);
+ printf("File start offset is %" PRId64 "\n", startoff);
+ break;
+ case 'l':
+ len = parse_storage_size(optarg);
+ if (!len)
+ PANIC("invalid len size parameter: -l %s",
+ optarg);
+ printf("Limit IO space to %s (%" PRId64 " bytes) per
file\n", optarg, len);
+ break;
+ case 'S':
+ rseed = atoi(optarg);
+ printf("Use random seed %d\n", rseed);
+ break;
+ case 't':
+ secs = atoi(optarg);
+ if (!secs)
+ PANIC("invalid seconds parameter: -t %s",
+ optarg);
+ break;
+ case 'T':
+ threads = atoi(optarg);
+ if (!threads)
+ PANIC("invalid threads parameter: -T %s",
+ optarg);
+ break;
+ case 'W':
+ printf("Allow write behind\n");
+ openflags &= ~(O_SYNC|O_DIRECT);
+ write_behind = 1;
+ break;
+ case 'D':
+ printf("Use direct IO\n");
+ openflags &= ~O_SYNC;
+ openflags |= O_DIRECT;
+ break;
+ }
+ }
+ if (argc - optind < 3)
+ usage();
+
+ switch (argv[optind][0]) {
+ case 'R':
+ case 'r':
+ dorandom = 100;
+ break;
+ case 'S':
+ case 's':
+ dorandom = 0;
+ break;
+ default:
+ dorandom = atoi(argv[optind]);
+ if (dorandom < 0 || dorandom > 100)
+ PANIC("bad random/sequencial parameter: should be
R|S|0-100");
+ }
+ optind++;
+
+ switch (argv[optind][0]) {
+ case 'R':
+ case 'r':
+ doread = 100;
+ break;
+ case 'W':
+ case 'w':
+ doread = 0;
+ break;
+ default:
+ doread = atoi(argv[optind]);
+ if (doread < 0 || doread > 100)
+ PANIC("bad read/write parameter: should be R|W|0-100");
+ }
+ optind++;
+
+ DEBUG("using random seed %d", rseed);
+
+ nfiles = argc - optind;
+ nthreads = nfiles * threads;
+ if (!(thread_list = calloc(nthreads, sizeof(*thread_list))))
+ PANIC("no mem for thread list (threads %d)", threads * nfiles);
+
+ for (i = 0; i < nfiles; i++)
+ for (t = 0; t < threads; t++)
+ thread_list[i * threads + t] =
+ new_worker(argv[optind + i], blocksize,
dorandom, doread, startoff, len);
+
+ signal(SIGTERM, doexit);
+ signal(SIGINT, doexit);
+ signal(SIGUSR1, dostats);
+ start(nthreads);
+
+ duration.tv_sec = secs;
+
+ while (nanosleep(&duration, &remaining) < 0)
+ duration = remaining;
+
+ doexit(0);
+
+ return 0;
+}
Index: btest/scripts/btest-test-sum.awk
===================================================================
--- btest/scripts/btest-test-sum.awk (revision 0)
+++ btest/scripts/btest-test-sum.awk (revision 0)
@@ -0,0 +1,25 @@
+#!/bin/awk -f
+
+$1 == "@@" { type = $2; types[ntypes++] = type; next }
+
+$1 == "##" { test = $0; if (testcount[test] > 0) next; tests[ntests++] = test;
next }
+
+$1 == "Total:" { totals[type, test] = $0; testcount[test]++; next }
+$1 == "Synced:" { synced[type, test] = $0; next }
+
+END {
+ for (t = 0; t < ntests; t++ ) {
+ test = tests[t]
+ if (testcount[test] == 0)
+ continue
+ print "Test: ", test
+ for (ty = 0; ty < ntypes; ty++) {
+ type = types[ty]
+ if ((type, test) in totals)
+ print type, totals[type, test]
+ if ((type, test) in synced)
+ print type, synced[type, test]
+ }
+ }
+}
+
Property changes on: btest/scripts/btest-test-sum.awk
___________________________________________________________________
Name: svn:executable
+ *
Index: btest/scripts/btest-test
===================================================================
--- btest/scripts/btest-test (revision 0)
+++ btest/scripts/btest-test (revision 0)
@@ -0,0 +1,149 @@
+#!/bin/bash
+
+function panic() {
+ echo "Panic: $*" > /dev/stderr
+ exit 1
+}
+
+if [ -z "$1" -o -z "$2" ]; then
+ echo "Usage: `basename $0` <label> <testdir>"
+fi
+
+label=$1
+basedir=$2/btest$$-`date +%s`
+
+echo "@@ $label"
+
+if ! mkdir -p $basedir; then
+ panic "can't mkdir $basedir"
+fi
+
+rm -rf $basedir/*
+
+big=1G
+mid=512M
+small=100M
+
+echo "## Create 16 big ($big) files - 32k block"
+btest -b 32k -t 900 -l $big S W $basedir/fileX{1..16}
+
+echo "## Create 16 big ($big) files - 32k block - allow Write behind"
+btest -W -b 32k -t 900 -l $big S W $basedir/fileY{1..16}
+
+echo "## Rewrite 16 big ($big) files - 32k block - sync"
+btest -b 32k -t 900 -l $big S W $basedir/fileY{1..16}
+
+echo "## Rewrite 16 big ($big) files - 4k block - sync"
+btest -b 4k -t 900 -l $big S W $basedir/fileY{1..16}
+
+echo "## Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 900 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 25% Random, 75% Read 32k blocks - sync"
+btest -b 32k -t 180 -l $big 25 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 900 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 25% Random, 75% Read 4k blocks - sync"
+btest -b 4k -t 180 -l $big 25 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 25% Random, 75% Read 32k blocks -
direct"
+btest -D -b 32k -t 180 -l $big 25 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 25% Random, 75% Read 4k blocks -
direct"
+btest -D -b 4k -t 180 -l $big 25 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 25% Random, 75% Read 32k blocks -
write behind"
+btest -W -b 32k -t 180 -l $big 25 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 25% Random, 75% Read 4k blocks - write
behind"
+btest -W -b 4k -t 180 -l $big 25 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 10% Random, 75% Read 4k blocks - sync"
+btest -b 4k -t 180 -l $big 10 75 $basedir/fileY{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 16 big ($files) - 5% Random, 75% Read 4k blocks - sync"
+btest -b 4k -t 180 -l $big 10 75 $basedir/fileY{1..16}
+
+echo "## Create 16 middle ($mid) sized files - 4k blocks, sync"
+btest -W -b 4k -t 500 -l $mid S W $basedir/fileM{1..16}
+
+echo "## Create 16 small ($small) sized files - 4k blocks, sync"
+btest -W -b 4k -t 500 -l $small S W $basedir/fileS{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## random Read 16 middle ($mid) sized files - 4k blocks, sync"
+btest -b 4k -t 500 -l $mid R R $basedir/fileM{1..16}
+
+echo "## random Read 16 small ($mid) sized files - 4k blocks, sync"
+btest -b 4k -t 500 -l $mid R R $basedir/fileS{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## random Read 16 middle ($mid) sized files - 4k blocks, direct"
+btest -b 4k -t 500 -l $mid R R $basedir/fileM{1..16}
+
+echo "## random Read 16 small ($mid) sized files - 4k blocks, direct"
+btest -b 4k -t 500 -l $mid R R $basedir/fileS{1..16}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 15 mixed files, 5 big ($big), 5 middle sized ($mid) and
5 small ($small) - 25% Random, 75% Read 32k blocks - sync"
+btest -b 32k -t 180 -l $big 25 75 $basedir/fileY{1..5} $basedir/fileM{1..5}
$basedir/fileS{1..5}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 900 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 15 mixed files, 5 big ($big), 5 middle sized ($mid) and
5 small ($small) - 25% Random, 75% Read 4k blocks - sync"
+btest -b 4k -t 180 -l $big 25 75 $basedir/fileY{1..5} $basedir/fileM{1..5}
$basedir/fileS{1..5}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 15 mixed files, 5 big ($big), 5 middle sized ($mid) and
5 small ($small) - 25% Random, 75% Read 32k blocks - direct"
+btest -D -b 32k -t 180 -l $big 25 75 $basedir/fileY{1..5} $basedir/fileM{1..5}
$basedir/fileS{1..5}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 15 mixed files, 5 big ($big), 5 middle sized ($mid) and
5 small ($small) - 25% Random, 75% Read 4k blocks - direct"
+btest -D -b 4k -t 180 -l $big 25 75 $basedir/fileY{1..5} $basedir/fileM{1..5}
$basedir/fileS{1..5}
+
+echo "## Flush cashe using - Seq read of big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 15 mixed files, 5 big ($big), 5 middle sized ($mid) and
5 small ($small) - 25% Random, 75% Read 32k blocks - write behind"
+btest -W -b 32k -t 180 -l $big 25 75 $basedir/fileY{1..5} $basedir/fileM{1..5}
$basedir/fileS{1..5}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
+echo "## Stress IO on 15 mixed files, 5 big ($big), 5 middle sized ($mid) and
5 small ($small) - 25% Random, 75% Read 4k blocks - write behind"
+btest -W -b 4k -t 180 -l $big 25 75 $basedir/fileY{1..5} $basedir/fileM{1..5}
$basedir/fileS{1..5}
+
+echo "## Flush cashe using - Seq read of 16 big ($big) files - 32k blocks"
+btest -b 32k -t 300 -l $big S R $basedir/fileX{1..16}
+
Index: btest/Makefile
===================================================================
--- btest/Makefile (revision 0)
+++ btest/Makefile (revision 0)
@@ -0,0 +1,5 @@
+btest: btest.c
+ $(CC) $(CFLAGS) -D _LARGEFILE64_SOURCE -Wall -o $@ $(LDFLAGS) -l
pthread -l rt $<
+
+clean:
+ rm -f *.o btest
btest-2.patch
Description: btest-2.patch
- [Qemu-devel][PATCH] qemu-fuse, Shahar Frank, 2008/08/27
- Re: [Qemu-devel][PATCH] qemu-fuse, Anthony Liguori, 2008/08/27
- Re: [Qemu-devel][PATCH] qemu-fuse, Luca Bigliardi, 2008/08/27
- Re: [Qemu-devel][PATCH] qemu-fuse, Anthony Liguori, 2008/08/27
- Re: [Qemu-devel][PATCH] qemu-fuse, Daniel P. Berrange, 2008/08/27
- Re: [Qemu-devel][PATCH] qemu-fuse, Jamie Lokier, 2008/08/27
- RE: [Qemu-devel][PATCH] qemu-fuse, Shahar Frank, 2008/08/28
- [Qemu-devel][PATCH] block level testing/execersing utility, Shahar Frank, 2008/08/28
- Re: [Qemu-devel][PATCH] block level testing/execersing utility, Samuel Thibault, 2008/08/28
- RE: [Qemu-devel][PATCH] block level testing/execersing utility,
Shahar Frank <=
- Re: [Qemu-devel][PATCH] block level testing/execersing utility, Anthony Liguori, 2008/08/28
Re: [Qemu-devel][PATCH] qemu-fuse, Jamie Lokier, 2008/08/27
[Qemu-devel] Re: [PATCH] qemu-fuse, Szabolcs Szakacsits, 2008/08/29