#define DEF_LOOPS (1)
#define DEF_VERIFY (0)
#define DEF_STONEWALL (0)
+#define DEF_NUMJOBS (1)
#define ALIGN(buf) (char *) (((unsigned long) (buf) + MASK) & ~(MASK))
struct thread_data {
char file_name[256];
+ char directory[256];
int thread_number;
int error;
int fd;
unsigned int mem_type;
unsigned int verify;
unsigned int stonewall;
+ unsigned int numjobs;
cpu_set_t cpumask;
struct drand48_data bsrange_state;
return 0;
}
-static struct thread_data *get_new_job(int global)
+static struct thread_data *get_new_job(int global, struct thread_data *parent)
{
struct thread_data *td;
td = &threads[thread_number++];
memset(td, 0, sizeof(*td));
+ sprintf(td->directory, ".");
+
td->fd = -1;
td->thread_number = thread_number;
- td->ddir = def_thread.ddir;
- td->ioprio = def_thread.ioprio;
- td->sequential = def_thread.sequential;
- td->bs = def_thread.bs;
- td->min_bs = def_thread.min_bs;
- td->max_bs = def_thread.max_bs;
- td->odirect = def_thread.odirect;
- td->thinktime = def_thread.thinktime;
- td->fsync_blocks = def_thread.fsync_blocks;
- td->start_delay = def_thread.start_delay;
- td->timeout = def_thread.timeout;
- td->use_aio = def_thread.use_aio;
- td->create_file = def_thread.create_file;
- td->overwrite = def_thread.overwrite;
- td->invalidate_cache = def_thread.invalidate_cache;
- td->file_size = def_thread.file_size;
- td->file_offset = def_thread.file_offset;
- td->rate = def_thread.rate;
- td->ratemin = def_thread.ratemin;
- td->ratecycle = def_thread.ratecycle;
- td->aio_depth = def_thread.aio_depth;
- td->sync_io = def_thread.sync_io;
- td->mem_type = def_thread.mem_type;
- td->bw_avg_time = def_thread.bw_avg_time;
- td->create_serialize = def_thread.create_serialize;
- td->create_fsync = def_thread.create_fsync;
- td->loops = def_thread.loops;
- td->verify = def_thread.verify;
- td->stonewall = def_thread.stonewall;
- memcpy(&td->cpumask, &def_thread.cpumask, sizeof(td->cpumask));
+ td->ddir = parent->ddir;
+ td->ioprio = parent->ioprio;
+ td->sequential = parent->sequential;
+ td->bs = parent->bs;
+ td->min_bs = parent->min_bs;
+ td->max_bs = parent->max_bs;
+ td->odirect = parent->odirect;
+ td->thinktime = parent->thinktime;
+ td->fsync_blocks = parent->fsync_blocks;
+ td->start_delay = parent->start_delay;
+ td->timeout = parent->timeout;
+ td->use_aio = parent->use_aio;
+ td->create_file = parent->create_file;
+ td->overwrite = parent->overwrite;
+ td->invalidate_cache = parent->invalidate_cache;
+ td->file_size = parent->file_size;
+ td->file_offset = parent->file_offset;
+ td->rate = parent->rate;
+ td->ratemin = parent->ratemin;
+ td->ratecycle = parent->ratecycle;
+ td->aio_depth = parent->aio_depth;
+ td->sync_io = parent->sync_io;
+ td->mem_type = parent->mem_type;
+ td->bw_avg_time = parent->bw_avg_time;
+ td->create_serialize = parent->create_serialize;
+ td->create_fsync = parent->create_fsync;
+ td->loops = parent->loops;
+ td->verify = parent->verify;
+ td->stonewall = parent->stonewall;
+ td->numjobs = parent->numjobs;
+ memcpy(&td->cpumask, &parent->cpumask, sizeof(td->cpumask));
return td;
}
thread_number--;
}
-static int add_job(struct thread_data *td, const char *filename, int prioclass,
+static int add_job(struct thread_data *td, const char *jobname, int prioclass,
int prio)
{
+ int numjobs;
+
if (td == &def_thread)
return 0;
- strcpy(td->file_name, filename);
+ sprintf(td->file_name, "%s/%s.%d", td->directory, jobname, td->thread_number);
sem_init(&td->mutex, 1, 0);
td->ioprio = (prioclass << IOPRIO_CLASS_SHIFT) | prio;
td->verify = 0;
if (setup_rate(td))
- return -1;
+ goto err;
if (write_lat_log)
setup_log(&td->lat_log);
if (write_bw_log)
setup_log(&td->bw_log);
- printf("Client%d: file=%s, rw=%d, prio=%d/%d, seq=%d, odir=%d, bs=%d-%d, rate=%d, aio=%d, aio_depth=%d\n", td->thread_number, filename, td->ddir, prioclass, prio, td->sequential, td->odirect, td->min_bs, td->max_bs, td->rate, td->use_aio, td->aio_depth);
+ printf("Client%d: rw=%d, prio=%d/%d, seq=%d, odir=%d, bs=%d-%d, rate=%d, aio=%d, aio_depth=%d\n", td->thread_number, td->ddir, prioclass, prio, td->sequential, td->odirect, td->min_bs, td->max_bs, td->rate, td->use_aio, td->aio_depth);
+
+ /*
+ * recurse add identical jobs, clear numjobs and stonewall options
+ * as they don't apply to sub-jobs
+ */
+ numjobs = td->numjobs;
+ while (--numjobs) {
+ struct thread_data *td_new = get_new_job(0, td);
+
+ if (!td_new)
+ break;
+
+ td_new->numjobs = 1;
+ td_new->stonewall = 0;
+
+ if (add_job(td_new, jobname, prioclass, prio))
+ break;
+ }
return 0;
+err:
+ put_job(td);
+ return -1;
}
static void fill_cpu_mask(cpu_set_t cpumask, int cpu)
return 1;
}
+static int check_strstore(char *p, char *name, char *dest)
+{
+ char *s = strstr(p, name);
+
+ if (!s)
+ return 1;
+
+ s = strstr(p, "=");
+ if (!s)
+ return 1;
+
+ s++;
+ while (isblank(*s))
+ s++;
+
+ strcpy(dest, s);
+ return 0;
+}
+
static int check_range(char *p, char *name, unsigned long *s, unsigned long *e)
{
char str[128];
name[strlen(name) - 1] = '\0';
- td = get_new_job(global);
+ td = get_new_job(global, &def_thread);
if (!td)
break;
fgetpos(f, &off);
continue;
}
+ if (!check_int(p, "numjobs", &td->numjobs)) {
+ fgetpos(f, &off);
+ continue;
+ }
if (!check_range(p, "bsrange", &ul1, &ul2)) {
if (ul1 & 511)
printf("bad min block size, must be a multiple of 512\n");
fgetpos(f, &off);
continue;
}
+ if (!check_strstore(p, "directory", td->directory)) {
+ printf("got dir %s\n", td->directory);
+ fgetpos(f, &off);
+ continue;
+ }
if (!check_str(p, "mem", "malloc")) {
td->mem_type = MEM_MALLOC;
fgetpos(f, &off);
fsetpos(f, &off);
if (add_job(td, name, prioclass, prio))
- put_job(td);
+ break;
}
free(string);
def_thread.loops = DEF_LOOPS;
def_thread.verify = DEF_VERIFY;
def_thread.stonewall = DEF_STONEWALL;
+ def_thread.numjobs = DEF_NUMJOBS;
i = parse_options(argc, argv);