special purpose of also signaling the start of a new
job.
+wait_for=str Specifies the name of the already defined job to wait
+ for. Single waitee name only may be specified. If set, the job
+ won't be started until all workers of the waitee job are done.
+
+ Wait_for operates on the job name basis, so there are a few
+ limitations. First, the waitee must be defined prior to the
+ waiter job (meaning no forward references). Second, if a job
+ is being referenced as a waitee, it must have a unique name
+ (no duplicate waitees).
+
description=str Text description of the job. Doesn't do anything except
dump this text description when this job is run. It's
not parsed.
return true;
}
+static bool waitee_running(struct thread_data *me)
+{
+ const char *waitee = me->o.wait_for;
+ const char *self = me->o.name;
+ struct thread_data *td;
+ int i;
+
+ if (!waitee)
+ return false;
+
+ for_each_td(td, i) {
+ if (!strcmp(td->o.name, self) || strcmp(td->o.name, waitee))
+ continue;
+
+ if (td->runstate < TD_EXITED) {
+ dprint(FD_PROCESS, "%s fenced by %s(%s)\n",
+ self, td->o.name,
+ runstate_to_name(td->runstate));
+ return true;
+ }
+ }
+
+ dprint(FD_PROCESS, "%s: %s completed, can run\n", self, waitee);
+ return false;
+}
+
/*
* Main function for kicking off and reaping jobs, as needed.
*/
break;
}
+ if (waitee_running(td)) {
+ dprint(FD_PROCESS, "%s: waiting for %s\n",
+ td->o.name, td->o.wait_for);
+ break;
+ }
+
init_disk_util(td);
td->rusage_sem = fio_mutex_init(FIO_MUTEX_LOCKED);
{
free(o->description);
free(o->name);
+ free(o->wait_for);
free(o->directory);
free(o->filename);
free(o->filename_format);
string_to_cpu(&o->description, top->description);
string_to_cpu(&o->name, top->name);
+ string_to_cpu(&o->wait_for, top->wait_for);
string_to_cpu(&o->directory, top->directory);
string_to_cpu(&o->filename, top->filename);
string_to_cpu(&o->filename_format, top->filename_format);
string_to_net(top->description, o->description);
string_to_net(top->name, o->name);
+ string_to_net(top->wait_for, o->wait_for);
string_to_net(top->directory, o->directory);
string_to_net(top->filename, o->filename);
string_to_net(top->filename_format, o->filename_format);
--- /dev/null
+[global]
+threads=1
+group_reporting=1
+filename=/tmp/data
+filesize=128m
+
+[writers]
+rw=write
+bs=128k
+numjobs=4
+runtime=10
+
+[readers]
+new_group
+wait_for=writers
+rw=randread
+bs=4k
+numjobs=4
+runtime=10
+
+[writers2]
+new_group
+wait_for=readers
+rw=randwrite
+bs=4k
+numjobs=4
+runtime=10
+
+[readers2]
+new_group
+wait_for=writers2
+rw=randread
+bs=4k
+numjobs=4
+runtime=10
May be used to override the job name. On the command line, this parameter
has the special purpose of signalling the start of a new job.
.TP
+.BI wait_for \fR=\fPstr
+Specifies the name of the already defined job to wait for. Single waitee name
+only may be specified. If set, the job won't be started until all workers of
+the waitee job are done. Wait_for operates on the job name basis, so there are
+a few limitations. First, the waitee must be defined prior to the waiter job
+(meaning no forward references). Second, if a job is being referenced as a
+waitee, it must have a unique name (no duplicate waitees).
+.TP
.BI description \fR=\fPstr
Human-readable description of the job. It is printed when the job is run, but
otherwise has no special purpose.
extern void td_set_runstate(struct thread_data *, int);
extern int td_bump_runstate(struct thread_data *, int);
extern void td_restore_runstate(struct thread_data *, int);
+extern const char *runstate_to_name(int runstate);
/*
* Allow 60 seconds for a job to quit on its own, otherwise reap with
snprintf(name, size, "%s_%s.%s", logname, logtype, suf);
}
+static int check_waitees(char *waitee)
+{
+ struct thread_data *td;
+ int i, ret = 0;
+
+ for_each_td(td, i) {
+ if (td->subjob_number)
+ continue;
+
+ ret += !strcmp(td->o.name, waitee);
+ }
+
+ return ret;
+}
+
+static bool wait_for_ok(const char *jobname, struct thread_options *o)
+{
+ int nw;
+
+ if (!o->wait_for)
+ return true;
+
+ if (!strcmp(jobname, o->wait_for)) {
+ log_err("%s: a job cannot wait for itself (wait_for=%s).\n",
+ jobname, o->wait_for);
+ return false;
+ }
+
+ if (!(nw = check_waitees(o->wait_for))) {
+ log_err("%s: waitee job %s unknown.\n", jobname, o->wait_for);
+ return false;
+ }
+
+ if (nw > 1) {
+ log_err("%s: multiple waitees %s found,\n"
+ "please avoid duplicates when using wait_for option.\n",
+ jobname, o->wait_for);
+ return false;
+ }
+
+ return true;
+}
+
/*
* Adds a job to the list of things todo. Sanitizes the various options
* to make sure we don't have conflicts, and initializes various
if (fixup_options(td))
goto err;
+ /*
+ * Belongs to fixup_options, but o->name is not necessarily set as yet
+ */
+ if (!wait_for_ok(jobname, o))
+ goto err;
+
flow_init_job(td);
/*
"REAPED",
};
-static const char *runstate_to_name(int runstate)
+const char *runstate_to_name(int runstate)
{
compiletime_assert(TD_LAST == 12, "td runstate list");
if (runstate >= 0 && runstate < TD_LAST)
.category = FIO_OPT_C_GENERAL,
.group = FIO_OPT_G_DESC,
},
+ {
+ .name = "wait_for",
+ .lname = "Waitee name",
+ .type = FIO_OPT_STR_STORE,
+ .off1 = td_var_offset(wait_for),
+ .help = "Name of the job this one wants to wait for before starting",
+ .category = FIO_OPT_C_GENERAL,
+ .group = FIO_OPT_G_DESC,
+ },
{
.name = "filename",
.lname = "Filename(s)",
};
enum {
- FIO_SERVER_VER = 50,
+ FIO_SERVER_VER = 51,
FIO_SERVER_MAX_FRAGMENT_PDU = 1024,
FIO_SERVER_MAX_CMD_MB = 2048,
uint64_t set_options[NR_OPTS_SZ];
char *description;
char *name;
+ char *wait_for;
char *directory;
char *filename;
char *filename_format;
uint64_t set_options[NR_OPTS_SZ];
uint8_t description[FIO_TOP_STR_MAX];
uint8_t name[FIO_TOP_STR_MAX];
+ uint8_t wait_for[FIO_TOP_STR_MAX];
uint8_t directory[FIO_TOP_STR_MAX];
uint8_t filename[FIO_TOP_STR_MAX];
uint8_t filename_format[FIO_TOP_STR_MAX];