qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel][PATCH] block level testing/execersing utility


From: Shahar Frank
Subject: [Qemu-devel][PATCH] block level testing/execersing utility
Date: Thu, 28 Aug 2008 02:27:13 -0700

Hi All,

The attached is a small utility to test and exercise block level device.
I wrote it to test and benchmark Qemu image backends and to test Qemu
image related features. I think it may be useful for others too.

For the ones who ask why we need yet another tool, I can say that I
found that most existing tools are benchmarks oriented which make them
much less useful as a developing aid. I needed something that it is at
the level of dd but can do also random IO and multiple threading.

I added also sample scripts.

I hope it will be useful also for other people developing image related
features.

Shahar

Index: btest/btest.c
===================================================================
--- btest/btest.c       (revision 0)
+++ btest/btest.c       (revision 0)
@@ -0,0 +1,755 @@
+/*
+ * Block test/exerciser utility
+ *
+ * Copyright (c) 2008 Shahar Frank, Qumranet
+ *
+ * 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>
+
+#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;
+
+typedef struct IOStats {
+       char *title;
+       uint64_t duration;
+       uint64_t sduration;             /* sync duration */
+       uint64_t lat;
+       uint64_t slat;                  /* sync latency */
+       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 *);
+       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 (lseek64(arg->fd, arg->offset, SEEK_SET) < 0)
+               return -1;
+       if (read(arg->fd, arg->buf, arg->blocksize) != 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 (lseek64(arg->fd, arg->offset, SEEK_SET) < 0)
+               return -1;
+       if (write(arg->fd, arg->buf, arg->blocksize) != arg->blocksize)
+               return -1;
+       arg->offset += arg->blocksize;
+       return 0;
+}
+
+int
+do_rand_read(worker_arg *arg)
+{
+       arg->offset = random() * 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 (lseek64(arg->fd, arg->offset, SEEK_SET) < 0)
+               return -1;
+       if (read(arg->fd, arg->buf, arg->blocksize) != arg->blocksize)
+               return -1;
+       arg->offset += arg->blocksize;
+       return 0;
+}
+
+int
+do_rand_write(worker_arg *arg)
+{
+       arg->offset = random() * 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 (lseek64(arg->fd, arg->offset, SEEK_SET) < 0)
+               return -1;
+       //DEBUG3("write at offset %" PRIu64 " count %d", arg->offset,
arg->blocksize);
+       if (write(arg->fd, arg->buf, arg->blocksize) != 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 = (random() % 100) < arg->readratio;     
+               
+       if (arg->randomratio == 100)
+               dorandom = 1 << 1;
+       else if (arg->randomratio == 0)
+               dorandom = 0 << 1;
+       else
+               dorandom = ((random() % 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();
+       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;
+       shared.total.slat /= 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;
+       int seed = time(0);
+
+       prog = strchr(argv[0], '/');
+       if (!prog)
+               prog = argv[0];
+       else
+               prog++;
+
+       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':
+                       seed = atoi(optarg);
+                       printf("Use random seed %d\n", seed);
+                       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", seed);
+       srandom(seed);
+       
+       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

Attachment: btest.patch
Description: btest.patch


reply via email to

[Prev in Thread] Current Thread [Next in Thread]