qemu-devel
[Top][All Lists]
Advanced

[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

Attachment: btest-2.patch
Description: btest-2.patch


reply via email to

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