Define SIGUSR1 to inform fio to dump run stats while continuing to run

For long running jobs, it may be interesting to see the stats without
having to terminate the job. Set up SIGUSR1 so that it does that,
gives you the stats at that point in time.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/backend.c b/backend.c
index 75cb18b..62df0ec 100644
--- a/backend.c
+++ b/backend.c
@@ -87,6 +87,11 @@
 	}
 }
 
+static void sig_show_status(int sig)
+{
+	show_running_run_stats();
+}
+
 static void set_sig_handlers(void)
 {
 	struct sigaction act;
@@ -101,6 +106,11 @@
 	act.sa_flags = SA_RESTART;
 	sigaction(SIGTERM, &act, NULL);
 
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = sig_show_status;
+	act.sa_flags = SA_RESTART;
+	sigaction(SIGUSR1, &act, NULL);
+
 	if (is_backend) {
 		memset(&act, 0, sizeof(act));
 		act.sa_handler = sig_int;
diff --git a/client.c b/client.c
index 5b5d60a..5dcc5f5 100644
--- a/client.c
+++ b/client.c
@@ -401,6 +401,11 @@
 	fio_clients_terminate();
 }
 
+static void sig_show_status(int sig)
+{
+	show_running_run_stats();
+}
+
 static void client_signal_handler(void)
 {
 	struct sigaction act;
@@ -414,6 +419,11 @@
 	act.sa_handler = sig_int;
 	act.sa_flags = SA_RESTART;
 	sigaction(SIGTERM, &act, NULL);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = sig_show_status;
+	act.sa_flags = SA_RESTART;
+	sigaction(SIGUSR1, &act, NULL);
 }
 
 static int send_client_cmd_line(struct fio_client *client)
diff --git a/stat.c b/stat.c
index 7e2ab36..3712783 100644
--- a/stat.c
+++ b/stat.c
@@ -1073,6 +1073,55 @@
 	free(threadstats);
 }
 
+static void *__show_running_run_stats(void *arg)
+{
+	struct thread_data *td;
+	unsigned long long *rt;
+	struct timeval tv;
+	int i;
+
+	rt = malloc(thread_number * sizeof(unsigned long long));
+	fio_gettime(&tv, NULL);
+
+	for_each_td(td, i) {
+		rt[i] = mtime_since(&td->start, &tv);
+		if (td_read(td) && td->io_bytes[DDIR_READ])
+			td->ts.runtime[DDIR_READ] += rt[i];
+		if (td_write(td) && td->io_bytes[DDIR_WRITE])
+			td->ts.runtime[DDIR_WRITE] += rt[i];
+
+		update_rusage_stat(td);
+		td->ts.io_bytes[0] = td->io_bytes[0];
+		td->ts.io_bytes[1] = td->io_bytes[1];
+		td->ts.total_run_time = mtime_since(&td->epoch, &tv);
+	}
+
+	show_run_stats();
+
+	for_each_td(td, i) {
+		if (td_read(td) && td->io_bytes[DDIR_READ])
+			td->ts.runtime[DDIR_READ] -= rt[i];
+		if (td_write(td) && td->io_bytes[DDIR_WRITE])
+			td->ts.runtime[DDIR_WRITE] -= rt[i];
+	}
+
+	free(rt);
+	return NULL;
+}
+
+/*
+ * Called from signal handler. It _should_ be safe to just run this inline
+ * in the sig handler, but we should be disturbing the system less by just
+ * creating a thread to do it.
+ */
+void show_running_run_stats(void)
+{
+	pthread_t thread;
+
+	pthread_create(&thread, NULL, __show_running_run_stats, NULL);
+	pthread_detach(thread);
+}
+
 static inline void add_stat_sample(struct io_stat *is, unsigned long data)
 {
 	double val = data;
diff --git a/stat.h b/stat.h
index ce640d9..cbbbf44 100644
--- a/stat.h
+++ b/stat.h
@@ -196,6 +196,7 @@
 extern int calc_thread_status(struct jobs_eta *je, int force);
 extern void display_thread_status(struct jobs_eta *je);
 extern void show_run_stats(void);
+extern void show_running_run_stats(void);
 extern void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src, int nr);
 extern void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src);
 extern void init_thread_stat(struct thread_stat *ts);