[Top][All Lists]
[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
btest.patch
Description: btest.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 <=
- 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, 2008/08/28
- 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