int sum_stat_clients;
static int sum_stat_nr;
+static struct json_object *root = NULL;
+static struct json_array *clients_array = NULL;
+static struct json_array *du_array = NULL;
static int do_output_all_clients;
#define FIO_CLIENT_HASH_BITS 7
INIT_FLIST_HEAD(&client_hash[i]);
}
+static void fio_client_json_init(void)
+{
+ if (output_format != FIO_OUTPUT_JSON)
+ return;
+ root = json_create_object();
+ json_object_add_value_string(root, "fio version", fio_version_string);
+ clients_array = json_create_array();
+ json_object_add_value_array(root, "client_stats", clients_array);
+ du_array = json_create_array();
+ json_object_add_value_array(root, "disk_util", du_array);
+}
+
+static void fio_client_json_fini(void)
+{
+ if (output_format != FIO_OUTPUT_JSON)
+ return;
+ json_print_object(root);
+ log_info("\n");
+ json_free_object(root);
+ root = NULL;
+ clients_array = NULL;
+ du_array = NULL;
+}
+
static struct fio_client *find_client_by_fd(int fd)
{
int bucket = hash_long(fd, FIO_CLIENT_HASH_BITS) & FIO_CLIENT_HASH_MASK;
dprint(FD_NET, "client: start all\n");
+ fio_client_json_init();
+
flist_for_each_safe(entry, tmp, &client_list) {
client = flist_entry(entry, struct fio_client, list);
pdu.thread_number = cpu_to_le32(client->thread_number);
pdu.groupid = cpu_to_le32(client->groupid);
convert_thread_options_to_net(&pdu.top, o);
-
+
return fio_net_send_cmd(client->fd, FIO_NET_CMD_UPDATE_JOB, &pdu, sizeof(pdu), tag, &client->cmd_list);
}
dst->unified_rw_rep = le32_to_cpu(src->unified_rw_rep);
}
+static void json_object_add_client_info(struct json_object *obj,
+struct fio_client *client)
+{
+ json_object_add_value_string(obj, "hostname", client->hostname);
+ json_object_add_value_int(obj, "port", client->port);
+}
+
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;
- show_thread_status(&p->ts, &p->rs);
+ tsobj = show_thread_status(&p->ts, &p->rs);
client->did_stat = 1;
+ if (tsobj) {
+ json_object_add_client_info(tsobj, client);
+ json_array_add_value_object(clients_array, tsobj);
+ }
if (!do_output_all_clients)
return;
if (++sum_stat_nr == sum_stat_clients) {
strcpy(client_ts.name, "All clients");
- show_thread_status(&client_ts, &client_gs);
+ tsobj = show_thread_status(&client_ts, &client_gs);
+ if (tsobj) {
+ json_object_add_client_info(tsobj, client);
+ json_array_add_value_object(clients_array, tsobj);
+ }
}
}
log_info("\nDisk stats (read/write):\n");
}
- print_disk_util(&du->dus, &du->agg, output_format == FIO_OUTPUT_TERSE);
+ 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);
}
static void convert_jobs_eta(struct jobs_eta *je)
}
}
+ fio_client_json_fini();
+
free(pfds);
return retval;
}
log_info("\n");
}
-static void print_disk_util_json(struct disk_util *du, struct json_array *array)
+void json_array_add_disk_util(struct disk_util_stat *dus,
+ struct disk_util_agg *agg, struct json_array *array)
{
- double util = 0;
- struct disk_util_stat *dus = &du->dus;
- struct disk_util_agg *agg = &du->agg;
struct json_object *obj;
-
- obj = json_create_object();
- json_array_add_value_object(array, obj);
+ double util = 0;
if (dus->msec)
util = (double) 100 * dus->io_ticks / (double) dus->msec;
if (util > 100.0)
util = 100.0;
+ obj = json_create_object();
+ json_array_add_value_object(array, obj);
json_object_add_value_string(obj, "name", dus->name);
json_object_add_value_int(obj, "read_ios", dus->ios[0]);
json_object_add_value_float(obj, "aggr_util", agg->max_util.u.f);
}
+void json_object_add_disk_utils(struct json_object *obj,
+ struct flist_head *head)
+{
+ struct json_array *array = json_create_array();
+ struct flist_head *entry;
+ struct disk_util *du;
+
+ json_object_add_value_array(obj, "disk_util", array);
+
+ flist_for_each(entry, head) {
+ du = flist_entry(entry, struct disk_util, list);
+
+ aggregate_slaves_stats(du);
+ json_array_add_disk_util(&du->dus, &du->agg, array);
+ }
+}
+
void show_disk_util(int terse, struct json_object *parent)
{
struct flist_head *entry;
struct disk_util *du;
- struct json_array *array = NULL;
fio_mutex_down(disk_util_mutex);
return;
}
- if (!terse)
+ if (!terse && !parent)
log_info("\nDisk stats (read/write):\n");
if (output_format == FIO_OUTPUT_JSON) {
- array = json_create_array();
- json_object_add_value_array(parent, "disk_util", array);
- }
-
- flist_for_each(entry, &disk_list) {
- du = flist_entry(entry, struct disk_util, list);
+ json_object_add_disk_utils(parent, &disk_list);
+ } else
+ flist_for_each(entry, &disk_list) {
+ du = flist_entry(entry, struct disk_util, list);
- aggregate_slaves_stats(du);
- if (output_format == FIO_OUTPUT_JSON)
- print_disk_util_json(du, array);
- else
+ aggregate_slaves_stats(du);
print_disk_util(&du->dus, &du->agg, terse);
- }
+ }
fio_mutex_up(disk_util_mutex);
}
#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 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 *);
extern int update_io_ticks(void);
extern void setup_disk_util(void);
#define disk_util_prune_entries()
#define init_disk_util(td)
#define setup_disk_util()
+#define json_array_add_disk_util(dus, agg, parent)
+
static inline int update_io_ticks(void)
{
return disk_util_exit;
{
disk_util_exit = 1;
}
-
#endif
#define json_array_add_value_array(obj, val) \
json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val))
+#define json_array_last_value_object(obj) \
+ (obj->values[obj->value_cnt - 1]->object)
+
void json_print_object(struct json_object *obj);
#endif
show_lat_m(io_u_lat_m);
}
-void show_thread_status(struct thread_stat *ts, struct group_run_stats *rs)
+
+void show_thread_status_normal(struct thread_stat *ts, struct group_run_stats *rs)
{
double usr_cpu, sys_cpu;
unsigned long runtime;
log_info(";%3.2f%%", io_u_lat_m[i]);
/* disk util stats, if any */
- show_disk_util(1, NULL);
+ if (is_backend)
+ show_disk_util(1, NULL);
/* Additional output if continue_on_error set - default off*/
if (ts->continue_on_error)
/* Additional output if continue_on_error set - default off*/
if (ts->continue_on_error) {
json_object_add_value_int(root, "total_err", ts->total_err_count);
- json_object_add_value_int(root, "total_err", ts->first_error);
+ json_object_add_value_int(root, "first_error", ts->first_error);
}
/* Additional output if description is set */
log_err("fio: bad terse version!? %d\n", terse_version);
}
+struct json_object *show_thread_status(struct thread_stat *ts,
+ struct group_run_stats *rs)
+{
+ if (output_format == FIO_OUTPUT_TERSE)
+ show_thread_status_terse(ts, rs);
+ else if (output_format == FIO_OUTPUT_JSON)
+ return(show_thread_status_json(ts, rs));
+ else
+ show_thread_status_normal(ts, rs);
+ return NULL;
+}
+
static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr)
{
double mean, S;
struct json_object *tmp = show_thread_status_json(ts, rs);
json_array_add_value_object(array, tmp);
} else
- show_thread_status(ts, rs);
+ show_thread_status_normal(ts, rs);
}
if (output_format == FIO_OUTPUT_JSON) {
/* disk util stats, if any */
extern void stat_init(void);
extern void stat_exit(void);
-extern void show_thread_status(struct thread_stat *ts, struct group_run_stats *rs);
+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 int calc_thread_status(struct jobs_eta *je, int force);
extern void display_thread_status(struct jobs_eta *je);