Expand choices for exitall
authorHannes Weisbach <hannes.weisbach@gmail.com>
Wed, 27 Nov 2019 09:57:49 +0000 (10:57 +0100)
committerHannes Weisbach <hannes.weisbach@gmail.com>
Thu, 19 Dec 2019 09:43:51 +0000 (10:43 +0100)
Add exit_what thread_option with the following choices:

- "group" (default) exit all jobs of the same group (equal to "exitall=1")
- "stonewall", quit all jobs until the next stonewall
- "all", quit *all* jobs

Signed-off-by: Hannes Weisbach <hannes.weisbach@gmail.com>
HOWTO
backend.c
cconv.c
fio.1
fio.h
libfio.c
options.c
server.c
thread_options.h

diff --git a/HOWTO b/HOWTO
index 88dbb03fc23859ad39ba351b3fa06de81c96512b..41a667af4406a17b215952faa7ef3511bc0bb801 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -2814,9 +2814,21 @@ Threads, processes and job synchronization
 
 .. option:: exitall
 
-       By default, fio will continue running all other jobs when one job finishes
-       but sometimes this is not the desired action.  Setting ``exitall`` will
-       instead make fio terminate all other jobs when one job finishes.
+       By default, fio will continue running all other jobs when one job finishes.
+       Sometimes this is not the desired action.  Setting ``exitall`` will instead
+       make fio terminate all jobs in the same group, as soon as one job of that
+       group finishes.
+
+.. option:: exit_what
+
+       By default, fio will continue running all other jobs when one job finishes.
+       Sometimes this is not the desired action. Setting ``exit_all`` will
+       instead make fio terminate all jobs in the same group. The option
+        ``exit_what`` allows to control which jobs get terminated when ``exitall`` is
+        enabled. The default is ``group`` and does not change the behaviour of
+        ``exitall``. The setting ``all`` terminates all jobs. The setting ``stonewall``
+        terminates all currently running jobs across all groups and continues execution
+        with the next stonewalled group.
 
 .. option:: exec_prerun=str
 
index 1c339408fa5fd0338cdd0e98444b5a7a2fa509a8..d0d691b39e5ed86ce8e29fa22610d235238dcf0b 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -81,7 +81,7 @@ static void sig_int(int sig)
                        exit_value = 128;
                }
 
-               fio_terminate_threads(TERMINATE_ALL);
+               fio_terminate_threads(TERMINATE_ALL, TERMINATE_ALL);
        }
 }
 
@@ -1091,7 +1091,7 @@ reap:
                if (!in_ramp_time(td) && should_check_rate(td)) {
                        if (check_min_rate(td, &comp_time)) {
                                if (exitall_on_terminate || td->o.exitall_error)
-                                       fio_terminate_threads(td->groupid);
+                                       fio_terminate_threads(td->groupid, td->o.exit_what);
                                td_verror(td, EIO, "check_min_rate");
                                break;
                        }
@@ -1898,7 +1898,7 @@ static void *thread_main(void *data)
                exec_string(o, o->exec_postrun, (const char *)"postrun");
 
        if (exitall_on_terminate || (o->exitall_error && td->error))
-               fio_terminate_threads(td->groupid);
+               fio_terminate_threads(td->groupid, td->o.exit_what);
 
 err:
        if (td->error)
@@ -2050,7 +2050,7 @@ reaped:
        }
 
        if (*nr_running == cputhreads && !pending && realthreads)
-               fio_terminate_threads(TERMINATE_ALL);
+               fio_terminate_threads(TERMINATE_ALL, TERMINATE_ALL);
 }
 
 static bool __check_trigger_file(void)
@@ -2100,7 +2100,7 @@ void check_trigger_file(void)
                        fio_clients_send_trigger(trigger_remote_cmd);
                else {
                        verify_save_state(IO_LIST_ALL);
-                       fio_terminate_threads(TERMINATE_ALL);
+                       fio_terminate_threads(TERMINATE_ALL, TERMINATE_ALL);
                        exec_trigger(trigger_cmd);
                }
        }
@@ -2373,7 +2373,7 @@ reap:
                        dprint(FD_MUTEX, "wait on startup_sem\n");
                        if (fio_sem_down_timeout(startup_sem, 10000)) {
                                log_err("fio: job startup hung? exiting.\n");
-                               fio_terminate_threads(TERMINATE_ALL);
+                               fio_terminate_threads(TERMINATE_ALL, TERMINATE_ALL);
                                fio_abort = true;
                                nr_started--;
                                free(fd);
diff --git a/cconv.c b/cconv.c
index bff5e34fa5a49271b4eef63d5120266a06a96184..04854b0ebe848d94de229511056c2e0d7281f33e 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -236,7 +236,8 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->loops = le32_to_cpu(top->loops);
        o->mem_type = le32_to_cpu(top->mem_type);
        o->mem_align = le32_to_cpu(top->mem_align);
-       o->stonewall = le32_to_cpu(top->stonewall);
+       o->exit_what = le16_to_cpu(top->exit_what);
+       o->stonewall = le16_to_cpu(top->stonewall);
        o->new_group = le32_to_cpu(top->new_group);
        o->numjobs = le32_to_cpu(top->numjobs);
        o->cpus_allowed_policy = le32_to_cpu(top->cpus_allowed_policy);
@@ -433,7 +434,8 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->loops = cpu_to_le32(o->loops);
        top->mem_type = cpu_to_le32(o->mem_type);
        top->mem_align = cpu_to_le32(o->mem_align);
-       top->stonewall = cpu_to_le32(o->stonewall);
+       top->exit_what = cpu_to_le16(o->exit_what);
+       top->stonewall = cpu_to_le16(o->stonewall);
        top->new_group = cpu_to_le32(o->new_group);
        top->numjobs = cpu_to_le32(o->numjobs);
        top->cpus_allowed_policy = cpu_to_le32(o->cpus_allowed_policy);
diff --git a/fio.1 b/fio.1
index 14569e9fb3dfc4d2fee552549da470768f4accfe..a60863f62418e5bd778eff81eb366d21d82ecdb6 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -2509,9 +2509,20 @@ wall also implies starting a new reporting group, see
 \fBgroup_reporting\fR.
 .TP
 .BI exitall
-By default, fio will continue running all other jobs when one job finishes
-but sometimes this is not the desired action. Setting \fBexitall\fR will
-instead make fio terminate all other jobs when one job finishes.
+By default, fio will continue running all other jobs when one job finishes.
+Sometimes this is not the desired action. Setting \fBexitall\fR will instead
+make fio terminate all jobs in the same group, as soon as one job of that
+group finishes.
+.TP
+.BI exit_what
+By default, fio will continue running all other jobs when one job finishes.
+Sometimes this is not the desired action. Setting \fBexit_all\fR will instead
+make fio terminate all jobs in the same group. The option \fBexit_what\fR
+allows to control which jobs get terminated when \fBexitall\fR is enabled. The
+default is \fBgroup\fR and does not change the behaviour of \fBexitall\fR. The
+setting \fBall\fR terminates all jobs. The setting \fBstonewall\fR terminates
+all currently running jobs across all groups and continues execution with the
+next stonewalled group.
 .TP
 .BI exec_prerun \fR=\fPstr
 Before running this job, issue the command specified through
diff --git a/fio.h b/fio.h
index 2094d30b863ef41e01807464731e510c5dead8e8..e943ad165ba01c2d4d8132009f33af5efe72da8f 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -660,8 +660,14 @@ extern const char *runstate_to_name(int runstate);
  */
 #define FIO_REAP_TIMEOUT       300
 
-#define TERMINATE_ALL          (-1U)
-extern void fio_terminate_threads(unsigned int);
+enum {
+       TERMINATE_NONE = 0,
+       TERMINATE_GROUP = 1,
+       TERMINATE_STONEWALL = 2,
+       TERMINATE_ALL = -1,
+};
+
+extern void fio_terminate_threads(unsigned int, unsigned int);
 extern void fio_mark_td_terminate(struct thread_data *);
 
 /*
index 674bc1dc0a9ed37216bf86ae25acef05e33dd4f4..7348b16491ff266cadb7ba46d75e503984ccbc95 100644 (file)
--- a/libfio.c
+++ b/libfio.c
@@ -233,7 +233,7 @@ void fio_mark_td_terminate(struct thread_data *td)
        td->terminate = true;
 }
 
-void fio_terminate_threads(unsigned int group_id)
+void fio_terminate_threads(unsigned int group_id, unsigned int terminate)
 {
        struct thread_data *td;
        pid_t pid = getpid();
@@ -242,7 +242,10 @@ void fio_terminate_threads(unsigned int group_id)
        dprint(FD_PROCESS, "terminate group_id=%d\n", group_id);
 
        for_each_td(td, i) {
-               if (group_id == TERMINATE_ALL || group_id == td->groupid) {
+               if ((terminate == TERMINATE_GROUP && group_id == TERMINATE_ALL) ||
+                   (terminate == TERMINATE_GROUP && group_id == td->groupid) ||
+                   (terminate == TERMINATE_STONEWALL && td->runstate >= TD_RUNNING) ||
+                   (terminate == TERMINATE_ALL)) {
                        dprint(FD_PROCESS, "setting terminate on %s/%d\n",
                                                td->o.name, (int) td->pid);
 
index e4262def7285a68e80e9c1a295e6a4bd6dd8456a..287f0435b73cff776328787407f3dc8097911d92 100644 (file)
--- a/options.c
+++ b/options.c
@@ -3941,6 +3941,30 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_PROCESS,
        },
+       {
+               .name   = "exit_what",
+               .lname  = "What jobs to quit on terminate",
+               .type   = FIO_OPT_STR,
+               .off1   = offsetof(struct thread_options, exit_what),
+               .help   = "Fine-grained control for exitall",
+               .def    = "group",
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_PROCESS,
+               .posval = {
+                         { .ival = "group",
+                           .oval = TERMINATE_GROUP,
+                           .help = "exit_all=1 default behaviour",
+                         },
+                         { .ival = "stonewall",
+                           .oval = TERMINATE_STONEWALL,
+                           .help = "quit all currently running jobs; continue with next stonewall",
+                         },
+                         { .ival = "all",
+                           .oval = TERMINATE_ALL,
+                           .help = "Quit everything",
+                         },
+               },
+       },
        {
                .name   = "exitall_on_error",
                .lname  = "Exit-all on terminate in error",
index 824f036ad606f448ca09f87ec90a06038040a0c2..b7347b43e3961fea588a85ac821811dfff7f61b3 100644 (file)
--- a/server.c
+++ b/server.c
@@ -975,7 +975,7 @@ static int handle_trigger_cmd(struct fio_net_cmd *cmd, struct flist_head *job_li
        } else
                fio_net_queue_cmd(FIO_NET_CMD_VTRIGGER, rep, sz, NULL, SK_F_FREE | SK_F_INLINE);
 
-       fio_terminate_threads(TERMINATE_ALL);
+       fio_terminate_threads(TERMINATE_ALL, TERMINATE_ALL);
        fio_server_check_jobs(job_list);
        exec_trigger(buf);
        return 0;
@@ -992,7 +992,7 @@ static int handle_command(struct sk_out *sk_out, struct flist_head *job_list,
 
        switch (cmd->opcode) {
        case FIO_NET_CMD_QUIT:
-               fio_terminate_threads(TERMINATE_ALL);
+               fio_terminate_threads(TERMINATE_ALL, TERMINATE_ALL);
                ret = 0;
                break;
        case FIO_NET_CMD_EXIT:
index ee6e4d6d6b142745dba7e244e22a44bdf836f515..4b131bdaa3a266cbafdb4d8e11e2747e28f7b31e 100644 (file)
@@ -201,7 +201,8 @@ struct thread_options {
 
        unsigned long long max_latency;
 
-       unsigned int stonewall;
+       unsigned short exit_what;
+       unsigned short stonewall;
        unsigned int new_group;
        unsigned int numjobs;
        os_cpu_mask_t cpumask;
@@ -489,7 +490,8 @@ struct thread_options_pack {
        uint32_t mem_type;
        uint32_t mem_align;
 
-       uint32_t stonewall;
+       uint16_t exit_what;
+       uint16_t stonewall;
        uint32_t new_group;
        uint32_t numjobs;
        /*