Skip to contentSkip to conversation

Recent changes (master)

PATCH Jens Axboe 1 participant 1 message Oct 27, 2015

Subsystems (2)
lore
Share & tools
lore

Jens Axboe

author
#0 lore raw

The following changes since commit d2235e56057f54fc63ccbf789d4c54f9e99978af:

client: remove duplicated code (2015-10-20 09:07:31 -0600)

are available in the git repository at:

git://git.kernel.dk/fio.git master

for you to fetch changes up to 01cfefcc6255420a9e19d5774053ed2fb705b150:

client/backend: fix incomplete output_format checks (2015-10-27 18:34:33 +0900)

----------------------------------------------------------------
Jens Axboe (12):
Add support for multiple output formats
Enable the use of multiple output formats
Update fio man page
Re-instate --append-terse
Proper size return from output buffers
Don't setup output buffers we are not going to use jobs_eta alloc padding
log: abstract out and use generic buffer logger Unbreak output buffer logging over the network
stat: collapse buf output flush and free
stat: fix potential segfault for json output on network client client/backend: fix incomplete output_format checks

 Makefile            |   1 +
 backend.c           |   2 +-
 client.c            |  21 ++--
 diskutil.c          |  35 ++++---
 diskutil.h          |  11 +-
 eta.c               |   4 +-
 filesetup.c         |   2 +-
 fio.1               |   2 +
 fio.h               |  11 +-
 idletime.c          |  21 ++--
 idletime.h          |   3 +-
 init.c              |  50 +++++++---
 json.c              |  62 ++++++------
 json.h              |   5 +-
 lib/output_buffer.c |  48 +++++++++
 lib/output_buffer.h |  17 ++++
 log.c               |  50 ++++++----
 log.h               |  20 +++-
 parse.c             |   4 +-
 stat.c              | 282 +++++++++++++++++++++++++++-------------------------
 stat.h              |   5 +-
 21 files changed, 403 insertions(+), 253 deletions(-)
 create mode 100644 lib/output_buffer.c
 create mode 100644 lib/output_buffer.h

---

Diff of recent changes:

Makefile +1 -0
index 1507464..0b506e8 100644
@@ -47,6 +47,7 @@ SOURCE :=	gettime.c ioengines.c init.c stat.c log.c time.c filesetup.c \
 		lib/hweight.c lib/getrusage.c idletime.c td_error.c \
 		profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
 		lib/tp.c lib/bloom.c lib/gauss.c lib/mountcheck.c workqueue.c \
+		lib/output_buffer.c \
 		$(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c))
 
 ifdef CONFIG_LIBHDFS
backend.c +1 -1
index 8fd5535..b180196 100644
@@ -1977,7 +1977,7 @@ static void run_threads(void)
 			nr_process++;
 	}
 
-	if (output_format == FIO_OUTPUT_NORMAL) {
+	if (output_format & FIO_OUTPUT_NORMAL) {
 		log_info("Starting ");
 		if (nr_thread)
 			log_info("%d thread%s", nr_thread,
client.c +12 -9
index 005ddf4..db472c4 100644
@@ -117,7 +117,7 @@ static int read_data(int fd, void *data, size_t size)
 
 static void fio_client_json_init(void)
 {
-	if (output_format != FIO_OUTPUT_JSON)
+	if (!(output_format & FIO_OUTPUT_JSON))
 		return;
 	root = json_create_object();
 	json_object_add_value_string(root, "fio version", fio_version_string);
@@ -129,9 +129,9 @@ static void fio_client_json_init(void)
 
 static void fio_client_json_fini(void)
 {
-	if (output_format != FIO_OUTPUT_JSON)
+	if (!(output_format & FIO_OUTPUT_JSON))
 		return;
-	json_print_object(root);
+	json_print_object(root, NULL);
 	log_info("\n");
 	json_free_object(root);
 	root = NULL;
@@ -936,7 +936,7 @@ static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd)
 	struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
 	struct json_object *tsobj;
 
-	tsobj = show_thread_status(&p->ts, &p->rs);
+	tsobj = show_thread_status(&p->ts, &p->rs, NULL);
 	client->did_stat = 1;
 	if (tsobj) {
 		json_object_add_client_info(tsobj, client);
@@ -956,7 +956,7 @@ static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd)
 
 	if (++sum_stat_nr == sum_stat_clients) {
 		strcpy(client_ts.name, "All clients");
-		tsobj = show_thread_status(&client_ts, &client_gs);
+		tsobj = show_thread_status(&client_ts, &client_gs, NULL);
 		if (tsobj) {
 			json_object_add_client_info(tsobj, client);
 			json_array_add_value_object(clients_array, tsobj);
@@ -968,7 +968,7 @@ static void handle_gs(struct fio_client *client, struct fio_net_cmd *cmd)
 {
 	struct group_run_stats *gs = (struct group_run_stats *) cmd->payload;
 
-	show_group_stats(gs);
+	show_group_stats(gs, NULL);
 }
 
 static void handle_text(struct fio_client *client, struct fio_net_cmd *cmd)
@@ -1029,13 +1029,16 @@ static void handle_du(struct fio_client *client, struct fio_net_cmd *cmd)
 		log_info("\nDisk stats (read/write):\n");
 	}
 
-	if (output_format == FIO_OUTPUT_JSON) {
+	if (output_format & FIO_OUTPUT_JSON) {
 		struct json_object *duobj;
 		json_array_add_disk_util(&du->dus, &du->agg, du_array);
 		duobj = json_array_last_value_object(du_array);
 		json_object_add_client_info(duobj, client);
-	} else
-		print_disk_util(&du->dus, &du->agg, output_format == FIO_OUTPUT_TERSE);
+	}
+	if (output_format & FIO_OUTPUT_TERSE)
+		print_disk_util(&du->dus, &du->agg, 1, NULL);
+	if (output_format & FIO_OUTPUT_NORMAL)
+		print_disk_util(&du->dus, &du->agg, 0, NULL);
 }
 
 static void convert_jobs_eta(struct jobs_eta *je)
diskutil.c +19 -16
index 52d87f6..f83fc47 100644
@@ -495,13 +495,14 @@ void init_disk_util(struct thread_data *td)
 		f->du = __init_disk_util(td, f);
 }
 
-static void show_agg_stats(struct disk_util_agg *agg, int terse)
+static void show_agg_stats(struct disk_util_agg *agg, int terse,
+			   struct buf_output *out)
 {
 	if (!agg->slavecount)
 		return;
 
 	if (!terse) {
-		log_info(", aggrios=%llu/%llu, aggrmerge=%llu/%llu, "
+		log_buf(out, ", aggrios=%llu/%llu, aggrmerge=%llu/%llu, "
 			 "aggrticks=%llu/%llu, aggrin_queue=%llu, "
 			 "aggrutil=%3.2f%%",
 			(unsigned long long) agg->ios[0] / agg->slavecount,
@@ -513,7 +514,7 @@ static void show_agg_stats(struct disk_util_agg *agg, int terse)
 			(unsigned long long) agg->time_in_queue / agg->slavecount,
 			agg->max_util.u.f);
 	} else {
-		log_info(";slaves;%llu;%llu;%llu;%llu;%llu;%llu;%llu;%3.2f%%",
+		log_buf(out, ";slaves;%llu;%llu;%llu;%llu;%llu;%llu;%llu;%3.2f%%",
 			(unsigned long long) agg->ios[0] / agg->slavecount,
 			(unsigned long long) agg->ios[1] / agg->slavecount,
 			(unsigned long long) agg->merges[0] / agg->slavecount,
@@ -578,7 +579,7 @@ void disk_util_prune_entries(void)
 }
 
 void print_disk_util(struct disk_util_stat *dus, struct disk_util_agg *agg,
-		     int terse)
+		     int terse, struct buf_output *out)
 {
 	double util = 0;
 
@@ -589,9 +590,9 @@ void print_disk_util(struct disk_util_stat *dus, struct disk_util_agg *agg,
 
 	if (!terse) {
 		if (agg->slavecount)
-			log_info("  ");
+			log_buf(out, "  ");
 
-		log_info("  %s: ios=%llu/%llu, merge=%llu/%llu, "
+		log_buf(out, "  %s: ios=%llu/%llu, merge=%llu/%llu, "
 			 "ticks=%llu/%llu, in_queue=%llu, util=%3.2f%%",
 				dus->name,
 				(unsigned long long) dus->s.ios[0],
@@ -603,7 +604,7 @@ void print_disk_util(struct disk_util_stat *dus, struct disk_util_agg *agg,
 				(unsigned long long) dus->s.time_in_queue,
 				util);
 	} else {
-		log_info(";%s;%llu;%llu;%llu;%llu;%llu;%llu;%llu;%3.2f%%",
+		log_buf(out, ";%s;%llu;%llu;%llu;%llu;%llu;%llu;%llu;%3.2f%%",
 				dus->name,
 				(unsigned long long) dus->s.ios[0],
 				(unsigned long long) dus->s.ios[1],
@@ -619,10 +620,10 @@ void print_disk_util(struct disk_util_stat *dus, struct disk_util_agg *agg,
 	 * If the device has slaves, aggregate the stats for
 	 * those slave devices also.
 	 */
-	show_agg_stats(agg, terse);
+	show_agg_stats(agg, terse, out);
 
 	if (!terse)
-		log_info("\n");
+		log_buf(out, "\n");
 }
 
 void json_array_add_disk_util(struct disk_util_stat *dus,
@@ -689,7 +690,8 @@ static void json_object_add_disk_utils(struct json_object *obj,
 	}
 }
 
-void show_disk_util(int terse, struct json_object *parent)
+void show_disk_util(int terse, struct json_object *parent,
+		    struct buf_output *out)
 {
 	struct flist_head *entry;
 	struct disk_util *du;
@@ -704,21 +706,22 @@ void show_disk_util(int terse, struct json_object *parent)
 		return;
 	}
 
-	if (output_format == FIO_OUTPUT_JSON)
+	if (output_format & FIO_OUTPUT_JSON)
 		assert(parent);
 
-	if (!terse && output_format != FIO_OUTPUT_JSON)
-		log_info("\nDisk stats (read/write):\n");
+	if (!terse && !(output_format & FIO_OUTPUT_JSON))
+		log_buf(out, "\nDisk stats (read/write):\n");
 
-	if (output_format == FIO_OUTPUT_JSON)
+	if (output_format & FIO_OUTPUT_JSON)
 		json_object_add_disk_utils(parent, &disk_list);
-	else
+	if (output_format & ~(FIO_OUTPUT_JSON)) {
 		flist_for_each(entry, &disk_list) {
 			du = flist_entry(entry, struct disk_util, list);
 
 			aggregate_slaves_stats(du);
-			print_disk_util(&du->dus, &du->agg, terse);
+			print_disk_util(&du->dus, &du->agg, terse, out);
 		}
+	}
 
 	fio_mutex_up(disk_util_mutex);
 }
diskutil.h +7 -4
index c0ae0ed..25d0beb 100644
@@ -3,6 +3,8 @@
 #include "json.h"
 #define FIO_DU_NAME_SZ		64
 
+#include "lib/output_buffer.h"
+
 extern volatile int helper_exit;
 
 struct disk_util_stats {
@@ -105,8 +107,8 @@ extern struct flist_head disk_list;
  * disk util stuff
  */
 #ifdef FIO_HAVE_DISK_UTIL
-extern void print_disk_util(struct disk_util_stat *, struct disk_util_agg *, int terse);
-extern void show_disk_util(int terse, struct json_object *parent);
+extern void print_disk_util(struct disk_util_stat *, struct disk_util_agg *, int terse, struct buf_output *);
+extern void show_disk_util(int terse, struct json_object *parent, struct buf_output *);
 extern void json_array_add_disk_util(struct disk_util_stat *dus,
 		struct disk_util_agg *agg, struct json_array *parent);
 extern void init_disk_util(struct thread_data *);
@@ -115,10 +117,11 @@ extern void setup_disk_util(void);
 extern void disk_util_prune_entries(void);
 #else
 static inline void print_disk_util(struct disk_util_stat *du,
-				   struct disk_util_agg *agg, int terse)
+				   struct disk_util_agg *agg, int terse,
+				   struct buf_output *out)
 {
 }
-#define show_disk_util(terse, parent)
+#define show_disk_util(terse, parent, out)
 #define disk_util_prune_entries()
 #define init_disk_util(td)
 #define setup_disk_util()
eta.c +2 -2
index 3e8eb0b..7eb1c27 100644
@@ -352,7 +352,7 @@ int calc_thread_status(struct jobs_eta *je, int force)
 	static struct timeval rate_prev_time, disp_prev_time;
 
 	if (!force) {
-		if (output_format != FIO_OUTPUT_NORMAL &&
+		if (!(output_format & FIO_OUTPUT_NORMAL) &&
 		    f_out == stdout)
 			return 0;
 		if (temp_stall_ts || eta_print == FIO_ETA_NEVER)
@@ -590,7 +590,7 @@ struct jobs_eta *get_jobs_eta(int force, size_t *size)
 	if (!thread_number)
 		return NULL;
 
-	*size = sizeof(*je) + THREAD_RUNSTR_SZ + 1;
+	*size = sizeof(*je) + THREAD_RUNSTR_SZ + 8;
 	je = malloc(*size);
 	if (!je)
 		return NULL;
filesetup.c +1 -1
index e1dedcd..634d556 100644
@@ -936,7 +936,7 @@ int setup_files(struct thread_data *td)
 	 */
 	if (need_extend) {
 		temp_stall_ts = 1;
-		if (output_format == FIO_OUTPUT_NORMAL)
+		if (output_format & FIO_OUTPUT_NORMAL)
 			log_info("%s: Laying out IO file(s) (%u file(s) /"
 				 " %lluMB)\n", o->name, need_extend,
 					extend_size >> 20);
fio.1 +2 -0
index b049790..2ba36f9 100644
@@ -22,6 +22,7 @@ Write output to \fIfilename\fR.
 .TP
 .BI \-\-output-format \fR=\fPformat
 Set the reporting format to \fInormal\fR, \fIterse\fR, or \fIjson\fR.
+Multiple formats can be selected, separate by a comma.
 .TP
 .BI \-\-runtime \fR=\fPruntime
 Limit run time to \fIruntime\fR seconds.
@@ -34,6 +35,7 @@ Print statistics in a terse, semicolon-delimited format.
 .TP
 .B \-\-append-terse
 Print statistics in selected mode AND terse, semicolon-delimited format.
+Deprecated, use \-\-output-format instead to select multiple formats.
 .TP
 .B \-\-version
 Display version information and exit.
fio.h +8 -3
index adf879f..2dc445e 100644
@@ -674,9 +674,14 @@ extern const char *fio_get_os_string(int);
 #endif
 
 enum {
-	FIO_OUTPUT_TERSE	= 0,
-	FIO_OUTPUT_JSON,
-	FIO_OUTPUT_NORMAL,
+	__FIO_OUTPUT_TERSE	= 0,
+	__FIO_OUTPUT_JSON	= 1,
+	__FIO_OUTPUT_NORMAL	= 2,
+	FIO_OUTPUT_NR		= 3,
+
+	FIO_OUTPUT_TERSE	= 1U << __FIO_OUTPUT_TERSE,
+	FIO_OUTPUT_JSON		= 1U << __FIO_OUTPUT_JSON,
+	FIO_OUTPUT_NORMAL	= 1U << __FIO_OUTPUT_NORMAL,
 };
 
 enum {
idletime.c +11 -10
index db272fe..5cc8b65 100644
@@ -428,7 +428,7 @@ int fio_idle_prof_parse_opt(const char *args)
 		fio_idle_prof_init();
 		fio_idle_prof_start();
 		fio_idle_prof_stop();
-		show_idle_prof_stats(FIO_OUTPUT_NORMAL, NULL);
+		show_idle_prof_stats(FIO_OUTPUT_NORMAL, NULL, NULL);
 		return 1;
 	} else if (strcmp("system", args) == 0) {
 		ipc.opt = IDLE_PROF_OPT_SYSTEM;
@@ -446,7 +446,8 @@ int fio_idle_prof_parse_opt(const char *args)
 #endif
 }
 
-void show_idle_prof_stats(int output, struct json_object *parent)
+void show_idle_prof_stats(int output, struct json_object *parent,
+			  struct buf_output *out)
 {
 	int i, nr_cpus = ipc.nr_cpus;
 	struct json_object *tmp;
@@ -454,23 +455,23 @@ void show_idle_prof_stats(int output, struct json_object *parent)
 
 	if (output == FIO_OUTPUT_NORMAL) {
 		if (ipc.opt > IDLE_PROF_OPT_CALI)
-			log_info("\nCPU idleness:\n");
+			log_buf(out, "\nCPU idleness:\n");
 		else if (ipc.opt == IDLE_PROF_OPT_CALI)
-			log_info("CPU idleness:\n");
+			log_buf(out, "CPU idleness:\n");
 
 		if (ipc.opt >= IDLE_PROF_OPT_SYSTEM)
-			log_info("  system: %3.2f%%\n", fio_idle_prof_cpu_stat(-1));
+			log_buf(out, "  system: %3.2f%%\n", fio_idle_prof_cpu_stat(-1));
 
 		if (ipc.opt == IDLE_PROF_OPT_PERCPU) {
-			log_info("  percpu: %3.2f%%", fio_idle_prof_cpu_stat(0));
+			log_buf(out, "  percpu: %3.2f%%", fio_idle_prof_cpu_stat(0));
 			for (i = 1; i < nr_cpus; i++)
-				log_info(", %3.2f%%", fio_idle_prof_cpu_stat(i));
-			log_info("\n");
+				log_buf(out, ", %3.2f%%", fio_idle_prof_cpu_stat(i));
+			log_buf(out, "\n");
 		}
 
 		if (ipc.opt >= IDLE_PROF_OPT_CALI) {
-			log_info("  unit work: mean=%3.2fus,", ipc.cali_mean);
-			log_info(" stddev=%3.2f\n", ipc.cali_stddev);
+			log_buf(out, "  unit work: mean=%3.2fus,", ipc.cali_mean);
+			log_buf(out, " stddev=%3.2f\n", ipc.cali_stddev);
 		}
 
 		/* dynamic mem allocations can now be freed */
idletime.h +2 -1
index bd6dcef..84c1fbb 100644
@@ -2,6 +2,7 @@
 #define FIO_IDLETIME_H
 
 #include "fio.h"
+#include "lib/output_buffer.h"
 
 #define CALIBRATE_RUNS  10
 #define CALIBRATE_SCALE 1000
@@ -54,6 +55,6 @@ extern void fio_idle_prof_init(void);
 extern void fio_idle_prof_start(void);
 extern void fio_idle_prof_stop(void);
 
-extern void show_idle_prof_stats(int, struct json_object *);
+extern void show_idle_prof_stats(int, struct json_object *, struct buf_output *);
 
 #endif
init.c +38 -12

82 lines not on this page · raw message

json.c +31 -31

108 lines not on this page · raw message

json.h +4 -1
index 962c11c..d7017e0 100644
@@ -1,5 +1,8 @@
 #ifndef __JSON__H
 #define __JSON__H
+
+#include "lib/output_buffer.h"
+
 struct json_object;
 struct json_array;
 struct json_pair;
@@ -76,5 +79,5 @@ int json_array_add_value_type(struct json_array *array, int type, ...);
 #define json_array_last_value_object(obj) \
 	(obj->values[obj->value_cnt - 1]->object)
 
-void json_print_object(struct json_object *obj);
+void json_print_object(struct json_object *obj, struct buf_output *out);
 #endif
lib/output_buffer.c new file +48 -0

48 lines not on this page · raw message

lib/output_buffer.h new file +17 -0
new file mode 100644
index 0000000..396002f
@@ -0,0 +1,17 @@
+#ifndef FIO_OUTPUT_BUFFER_H
+#define FIO_OUTPUT_BUFFER_H
+
+#include <unistd.h>
+
+struct buf_output {
+	char *buf;
+	size_t buflen;
+	size_t max_buflen;
+};
+
+void buf_output_init(struct buf_output *out);
+void buf_output_free(struct buf_output *out);
+size_t buf_output_add(struct buf_output *out, const char *buf, size_t len);
+size_t buf_output_flush(struct buf_output *out);
+
+#endif
log.c +30 -20

82 lines not on this page · raw message

log.h +16 -4
index e509313..f1cf003 100644
@@ -4,15 +4,27 @@
 #include <stdio.h>
 #include <stdarg.h>
 
+#include "lib/output_buffer.h"
+
 extern FILE *f_out;
 extern FILE *f_err;
 
-extern int log_err(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
-extern int log_info(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
-extern int log_valist(const char *str, va_list);
-extern int log_local_buf(const char *buf, size_t);
+extern size_t log_err(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+extern size_t log_info(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
+extern size_t __log_buf(struct buf_output *, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+extern size_t log_valist(const char *str, va_list);
+extern size_t log_local_buf(const char *buf, size_t);
+extern size_t log_info_buf(const char *buf, size_t len);
 extern int log_info_flush(void);
 
+#define log_buf(buf, format, args...)		\
+do {						\
+	if ((buf) != NULL)			\
+		__log_buf(buf, format, ##args);	\
+	else					\
+		log_info(format, ##args);	\
+} while (0)
+
 enum {
 	FIO_LOG_DEBUG	= 1,
 	FIO_LOG_INFO	= 2,
parse.c +2 -2
index 3e94c7d..e330dea 100644
@@ -52,7 +52,7 @@ static void posval_sort(struct fio_option *o, struct value_pair *vpmap)
 }
 
 static void show_option_range(struct fio_option *o,
-				int (*logger)(const char *format, ...))
+			      size_t (*logger)(const char *format, ...))
 {
 	if (o->type == FIO_OPT_FLOAT_LIST) {
 		if (o->minfp == DBL_MIN && o->maxfp == DBL_MAX)
@@ -109,7 +109,7 @@ static void show_option_help(struct fio_option *o, int is_err)
 		"no argument (opt)",
 		"deprecated",
 	};
-	int (*logger)(const char *format, ...);
+	size_t (*logger)(const char *format, ...);
 
 	if (is_err)
 		logger = log_err;
stat.c +148 -134

701 lines not on this page · raw message

stat.h +3 -2
index e87dae0..e289c2e 100644
@@ -2,6 +2,7 @@
 #define FIO_STAT_H
 
 #include "iolog.h"
+#include "lib/output_buffer.h"
 
 struct group_run_stats {
 	uint64_t max_run[DDIR_RWDIR_CNT], min_run[DDIR_RWDIR_CNT];
@@ -246,8 +247,8 @@ extern struct jobs_eta *get_jobs_eta(int force, size_t *size);
 extern void stat_init(void);
 extern void stat_exit(void);
 
-extern struct json_object * show_thread_status(struct thread_stat *ts, struct group_run_stats *rs);
-extern void show_group_stats(struct group_run_stats *rs);
+extern struct json_object * show_thread_status(struct thread_stat *ts, struct group_run_stats *rs, struct buf_output *);
+extern void show_group_stats(struct group_run_stats *rs, struct buf_output *);
 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);