Merge branch 's3_crypto' of github.com:hualongfeng/fio
[fio.git] / client.c
index 2d8a2bb151fbc52db553cf5cca5c59871181cac7..37da74bca5d7eecb2d7f1530466de7a0c3b18627 100644 (file)
--- a/client.c
+++ b/client.c
@@ -59,6 +59,7 @@ struct group_run_stats client_gs;
 int sum_stat_clients;
 
 static int sum_stat_nr;
+static struct buf_output allclients;
 static struct json_object *root = NULL;
 static struct json_object *job_opt_object = NULL;
 static struct json_array *clients_array = NULL;
@@ -198,14 +199,23 @@ static void fio_client_json_init(void)
 
 static void fio_client_json_fini(void)
 {
-       if (!(output_format & FIO_OUTPUT_JSON))
+       struct buf_output out;
+
+       if (!root)
                return;
 
-       log_info("\n");
-       json_print_object(root, NULL);
-       log_info("\n");
+       buf_output_init(&out);
+
+       __log_buf(&out, "\n");
+       json_print_object(root, &out);
+       __log_buf(&out, "\n");
+       log_info_buf(out.buf, out.buflen);
+
+       buf_output_free(&out);
+
        json_free_object(root);
        root = NULL;
+       job_opt_object = NULL;
        clients_array = NULL;
        du_array = NULL;
 }
@@ -233,6 +243,9 @@ void fio_put_client(struct fio_client *client)
        if (--client->refs)
                return;
 
+       log_info_buf(client->buf.buf, client->buf.buflen);
+       buf_output_free(&client->buf);
+
        free(client->hostname);
        if (client->argv)
                free(client->argv);
@@ -271,9 +284,10 @@ static int fio_client_dec_jobs_eta(struct client_eta *eta, client_eta_op eta_fn)
 static void fio_drain_client_text(struct fio_client *client)
 {
        do {
-               struct fio_net_cmd *cmd;
+               struct fio_net_cmd *cmd = NULL;
 
-               cmd = fio_net_recv_cmd(client->fd, false);
+               if (fio_server_poll_fd(client->fd, POLLIN, 0))
+                       cmd = fio_net_recv_cmd(client->fd, false);
                if (!cmd)
                        break;
 
@@ -351,9 +365,7 @@ void fio_client_add_cmd_option(void *cookie, const char *opt)
        }
 }
 
-struct fio_client *fio_client_add_explicit(struct client_ops *ops,
-                                          const char *hostname, int type,
-                                          int port)
+static struct fio_client *get_new_client(void)
 {
        struct fio_client *client;
 
@@ -366,7 +378,18 @@ struct fio_client *fio_client_add_explicit(struct client_ops *ops,
        INIT_FLIST_HEAD(&client->eta_list);
        INIT_FLIST_HEAD(&client->cmd_list);
 
-       client->hostname = strdup(hostname);
+       buf_output_init(&client->buf);
+
+       return client;
+}
+
+struct fio_client *fio_client_add_explicit(struct client_ops *ops,
+                                          const char *hostname, int type,
+                                          int port)
+{
+       struct fio_client *client;
+
+       client = get_new_client();
 
        if (type == Fio_client_socket)
                client->is_sock = true;
@@ -386,6 +409,7 @@ struct fio_client *fio_client_add_explicit(struct client_ops *ops,
        client->ops = ops;
        client->refs = 1;
        client->type = ops->client_type;
+       client->hostname = strdup(hostname);
 
        __fio_client_add_cmd_option(client, "fio");
 
@@ -441,21 +465,16 @@ int fio_client_add(struct client_ops *ops, const char *hostname, void **cookie)
                }
        }
 
-       client = malloc(sizeof(*client));
-       memset(client, 0, sizeof(*client));
-
-       INIT_FLIST_HEAD(&client->list);
-       INIT_FLIST_HEAD(&client->hash_list);
-       INIT_FLIST_HEAD(&client->arg_list);
-       INIT_FLIST_HEAD(&client->eta_list);
-       INIT_FLIST_HEAD(&client->cmd_list);
+       client = get_new_client();
 
        if (fio_server_parse_string(hostname, &client->hostname,
                                        &client->is_sock, &client->port,
                                        &client->addr.sin_addr,
                                        &client->addr6.sin6_addr,
-                                       &client->ipv6))
+                                       &client->ipv6)) {
+               fio_put_client(client);
                return -1;
+       }
 
        client->fd = -1;
        client->ops = ops;
@@ -503,7 +522,7 @@ static void probe_client(struct fio_client *client)
 
        sname = server_name(client, buf, sizeof(buf));
        memset(pdu.server, 0, sizeof(pdu.server));
-       strncpy((char *) pdu.server, sname, sizeof(pdu.server) - 1);
+       snprintf((char *) pdu.server, sizeof(pdu.server), "%s", sname);
 
        fio_net_send_cmd(client->fd, FIO_NET_CMD_PROBE, &pdu, sizeof(pdu), &tag, &client->cmd_list);
 }
@@ -557,7 +576,8 @@ static int fio_client_connect_sock(struct fio_client *client)
 
        memset(addr, 0, sizeof(*addr));
        addr->sun_family = AF_UNIX;
-       strncpy(addr->sun_path, client->hostname, sizeof(addr->sun_path) - 1);
+       snprintf(addr->sun_path, sizeof(addr->sun_path), "%s",
+                client->hostname);
 
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd < 0) {
@@ -926,7 +946,7 @@ static void convert_io_stat(struct io_stat *dst, struct io_stat *src)
 
 static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
 {
-       int i, j;
+       int i, j, k;
 
        dst->error              = le32_to_cpu(src->error);
        dst->thread_number      = le32_to_cpu(src->thread_number);
@@ -934,6 +954,8 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
        dst->pid                = le32_to_cpu(src->pid);
        dst->members            = le32_to_cpu(src->members);
        dst->unified_rw_rep     = le32_to_cpu(src->unified_rw_rep);
+       dst->ioprio             = le32_to_cpu(src->ioprio);
+       dst->disable_prio_stat  = le32_to_cpu(src->disable_prio_stat);
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
                convert_io_stat(&dst->clat_stat[i], &src->clat_stat[i]);
@@ -942,6 +964,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
                convert_io_stat(&dst->bw_stat[i], &src->bw_stat[i]);
                convert_io_stat(&dst->iops_stat[i], &src->iops_stat[i]);
        }
+       convert_io_stat(&dst->sync_stat, &src->sync_stat);
 
        dst->usr_time           = le64_to_cpu(src->usr_time);
        dst->sys_time           = le64_to_cpu(src->sys_time);
@@ -950,6 +973,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
        dst->majf               = le64_to_cpu(src->majf);
        dst->clat_percentiles   = le32_to_cpu(src->clat_percentiles);
        dst->lat_percentiles    = le32_to_cpu(src->lat_percentiles);
+       dst->slat_percentiles   = le32_to_cpu(src->slat_percentiles);
        dst->percentile_precision = le64_to_cpu(src->percentile_precision);
 
        for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
@@ -972,18 +996,25 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
        for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
                dst->io_u_lat_m[i]      = le64_to_cpu(src->io_u_lat_m[i]);
 
-       for (i = 0; i < DDIR_RWDIR_CNT; i++)
-               for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
-                       dst->io_u_plat[i][j] = le64_to_cpu(src->io_u_plat[i][j]);
+       for (i = 0; i < FIO_LAT_CNT; i++)
+               for (j = 0; j < DDIR_RWDIR_CNT; j++)
+                       for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
+                               dst->io_u_plat[i][j][k] = le64_to_cpu(src->io_u_plat[i][j][k]);
 
-       for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+       for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
+               dst->io_u_sync_plat[j] = le64_to_cpu(src->io_u_sync_plat[j]);
+
+       for (i = 0; i < DDIR_RWDIR_SYNC_CNT; i++)
                dst->total_io_u[i]      = le64_to_cpu(src->total_io_u[i]);
+
+       for (i = 0; i < DDIR_RWDIR_CNT; i++) {
                dst->short_io_u[i]      = le64_to_cpu(src->short_io_u[i]);
                dst->drop_io_u[i]       = le64_to_cpu(src->drop_io_u[i]);
        }
 
        dst->total_submit       = le64_to_cpu(src->total_submit);
        dst->total_complete     = le64_to_cpu(src->total_complete);
+       dst->nr_zone_resets     = le64_to_cpu(src->nr_zone_resets);
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
                dst->io_bytes[i]        = le64_to_cpu(src->io_bytes[i]);
@@ -1016,12 +1047,28 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
        dst->ss_deviation.u.f   = fio_uint64_to_double(le64_to_cpu(src->ss_deviation.u.i));
        dst->ss_criterion.u.f   = fio_uint64_to_double(le64_to_cpu(src->ss_criterion.u.i));
 
+       for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+               dst->nr_clat_prio[i] = le32_to_cpu(src->nr_clat_prio[i]);
+               for (j = 0; j < dst->nr_clat_prio[i]; j++) {
+                       for (k = 0; k < FIO_IO_U_PLAT_NR; k++)
+                               dst->clat_prio[i][j].io_u_plat[k] =
+                                       le64_to_cpu(src->clat_prio[i][j].io_u_plat[k]);
+                       convert_io_stat(&dst->clat_prio[i][j].clat_stat,
+                                       &src->clat_prio[i][j].clat_stat);
+                       dst->clat_prio[i][j].ioprio =
+                               le32_to_cpu(dst->clat_prio[i][j].ioprio);
+               }
+       }
+
        if (dst->ss_state & FIO_SS_DATA) {
                for (i = 0; i < dst->ss_dur; i++ ) {
                        dst->ss_iops_data[i] = le64_to_cpu(src->ss_iops_data[i]);
                        dst->ss_bw_data[i] = le64_to_cpu(src->ss_bw_data[i]);
                }
        }
+
+       dst->cachehit           = le64_to_cpu(src->cachehit);
+       dst->cachemiss          = le64_to_cpu(src->cachemiss);
 }
 
 static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src)
@@ -1059,13 +1106,10 @@ static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd)
        struct flist_head *opt_list = NULL;
        struct json_object *tsobj;
 
-       if (output_format & FIO_OUTPUT_TERSE)
-               return;
-
        if (client->opt_lists && p->ts.thread_number <= client->jobs)
                opt_list = &client->opt_lists[p->ts.thread_number - 1];
 
-       tsobj = show_thread_status(&p->ts, &p->rs, opt_list, NULL);
+       tsobj = show_thread_status(&p->ts, &p->rs, opt_list, &client->buf);
        client->did_stat = true;
        if (tsobj) {
                json_object_add_client_info(tsobj, client);
@@ -1075,7 +1119,7 @@ static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd)
        if (sum_stat_clients <= 1)
                return;
 
-       sum_thread_stats(&client_ts, &p->ts, sum_stat_nr == 1);
+       sum_thread_stats(&client_ts, &p->ts);
        sum_group_stats(&client_gs, &p->rs);
 
        client_ts.members++;
@@ -1086,7 +1130,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, NULL, NULL);
+               tsobj = show_thread_status(&client_ts, &client_gs, NULL, &allclients);
                if (tsobj) {
                        json_object_add_client_info(tsobj, client);
                        json_array_add_value_object(clients_array, tsobj);
@@ -1098,42 +1142,33 @@ static void handle_gs(struct fio_client *client, struct fio_net_cmd *cmd)
 {
        struct group_run_stats *gs = (struct group_run_stats *) cmd->payload;
 
-       if (output_format & FIO_OUTPUT_TERSE)
-               return;
-
        if (output_format & FIO_OUTPUT_NORMAL)
-               show_group_stats(gs, NULL);
+               show_group_stats(gs, &client->buf);
 }
 
 static void handle_job_opt(struct fio_client *client, struct fio_net_cmd *cmd)
 {
        struct cmd_job_option *pdu = (struct cmd_job_option *) cmd->payload;
-       struct print_option *p;
-
-       if (!job_opt_object)
-               return;
 
        pdu->global = le16_to_cpu(pdu->global);
        pdu->truncated = le16_to_cpu(pdu->truncated);
        pdu->groupid = le32_to_cpu(pdu->groupid);
 
-       p = malloc(sizeof(*p));
-       p->name = strdup((char *) pdu->name);
-       if (pdu->value[0] != '\0')
-               p->value = strdup((char *) pdu->value);
-       else
-               p->value = NULL;
-
        if (pdu->global) {
-               const char *pos = "";
+               if (!job_opt_object)
+                       return;
 
-               if (p->value)
-                       pos = p->value;
-
-               json_object_add_value_string(job_opt_object, p->name, pos);
+               json_object_add_value_string(job_opt_object,
+                                            (const char *)pdu->name,
+                                            (const char *)pdu->value);
        } else if (client->opt_lists) {
                struct flist_head *opt_list = &client->opt_lists[pdu->groupid];
+               struct print_option *p;
 
+               p = malloc(sizeof(*p));
+               p->name = strdup((const char *)pdu->name);
+               p->value = pdu->value[0] ? strdup((const char *)pdu->value) :
+                       NULL;
                flist_add_tail(&p->list, opt_list);
        }
 }
@@ -1151,9 +1186,10 @@ static void handle_text(struct fio_client *client, struct fio_net_cmd *cmd)
        name = client->name ? client->name : client->hostname;
 
        if (!client->skip_newline && !(output_format & FIO_OUTPUT_TERSE))
-               log_buf(&out, "<%s> ", name);
-       log_buf(&out, "%s", buf);
+               __log_buf(&out, "<%s> ", name);
+       __log_buf(&out, "%s", buf);
        log_info_buf(out.buf, out.buflen);
+       buf_output_free(&out);
        client->skip_newline = strchr(buf, '\n') == NULL;
 }
 
@@ -1194,23 +1230,24 @@ static void handle_du(struct fio_client *client, struct fio_net_cmd *cmd)
 {
        struct cmd_du_pdu *du = (struct cmd_du_pdu *) cmd->payload;
 
-       if (output_format & FIO_OUTPUT_TERSE)
-               return;
-
-       if (!client->disk_stats_shown) {
+       if (!client->disk_stats_shown)
                client->disk_stats_shown = true;
-               if (!(output_format & FIO_OUTPUT_JSON))
-                       log_info("\nDisk stats (read/write):\n");
-       }
 
        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);
        }
-       if (output_format & FIO_OUTPUT_NORMAL)
-               print_disk_util(&du->dus, &du->agg, 0, NULL);
+       if (output_format & FIO_OUTPUT_NORMAL) {
+               __log_buf(&client->buf, "\nDisk stats (read/write):\n");
+               print_disk_util(&du->dus, &du->agg, 0, &client->buf);
+       }
+       if (output_format & FIO_OUTPUT_TERSE && terse_version >= 3) {
+               print_disk_util(&du->dus, &du->agg, 1, &client->buf);
+               __log_buf(&client->buf, "\n");
+       }
 }
 
 static void convert_jobs_eta(struct jobs_eta *je)
@@ -1468,9 +1505,6 @@ static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd)
        const char *os, *arch;
        char bit[16];
 
-       if (output_format & FIO_OUTPUT_TERSE)
-               return;
-
        os = fio_get_os_string(probe->os);
        if (!os)
                os = "unknown";
@@ -1482,10 +1516,11 @@ static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd)
        sprintf(bit, "%d-bit", probe->bpp * 8);
        probe->flags = le64_to_cpu(probe->flags);
 
-       if (!(output_format & FIO_OUTPUT_JSON))
+       if (output_format & FIO_OUTPUT_NORMAL) {
                log_info("hostname=%s, be=%u, %s, os=%s, arch=%s, fio=%s, flags=%lx\n",
                        probe->hostname, probe->bigendian, bit, os, arch,
                        probe->fio_version, (unsigned long) probe->flags);
+       }
 
        if (!client->name)
                client->name = strdup((char *) probe->hostname);
@@ -1587,6 +1622,11 @@ static struct cmd_iolog_pdu *convert_iolog_gz(struct fio_net_cmd *cmd,
                err = inflate(&stream, Z_NO_FLUSH);
                /* may be Z_OK, or Z_STREAM_END */
                if (err < 0) {
+                       /*
+                        * Z_STREAM_ERROR and Z_BUF_ERROR can safely be
+                        * ignored */
+                       if (err == Z_STREAM_ERROR || err == Z_BUF_ERROR)
+                               break;
                        log_err("fio: inflate error %d\n", err);
                        free(ret);
                        ret = NULL;
@@ -1647,6 +1687,7 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd,
        ret->log_type           = le32_to_cpu(ret->log_type);
        ret->compressed         = le32_to_cpu(ret->compressed);
        ret->log_offset         = le32_to_cpu(ret->log_offset);
+       ret->log_prio           = le32_to_cpu(ret->log_prio);
        ret->log_hist_coarseness = le32_to_cpu(ret->log_hist_coarseness);
 
        if (*store_direct)
@@ -1661,9 +1702,11 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd,
                        s = (struct io_sample *)((char *)s + sizeof(struct io_u_plat_entry) * i);
 
                s->time         = le64_to_cpu(s->time);
-               s->data.val     = le64_to_cpu(s->data.val);
-               s->__ddir       = le32_to_cpu(s->__ddir);
+               if (ret->log_type != IO_LOG_TYPE_HIST)
+                       s->data.val     = le64_to_cpu(s->data.val);
+               s->__ddir       = __le32_to_cpu(s->__ddir);
                s->bs           = le64_to_cpu(s->bs);
+               s->priority     = le16_to_cpu(s->priority);
 
                if (ret->log_offset) {
                        struct io_sample_offset *so = (void *) s;
@@ -1726,7 +1769,6 @@ int fio_handle_client(struct fio_client *client)
 {
        struct client_ops *ops = client->ops;
        struct fio_net_cmd *cmd;
-       int size;
 
        dprint(FD_NET, "client: handle %s\n", client->hostname);
 
@@ -1760,14 +1802,26 @@ int fio_handle_client(struct fio_client *client)
                }
        case FIO_NET_CMD_TS: {
                struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
+               uint64_t offset;
+               int i;
+
+               for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+                       if (le32_to_cpu(p->ts.nr_clat_prio[i])) {
+                               offset = le64_to_cpu(p->ts.clat_prio_offset[i]);
+                               p->ts.clat_prio[i] =
+                                       (struct clat_prio_stat *)((char *)p + offset);
+                       }
+               }
 
                dprint(FD_NET, "client: ts->ss_state = %u\n", (unsigned int) le32_to_cpu(p->ts.ss_state));
                if (le32_to_cpu(p->ts.ss_state) & FIO_SS_DATA) {
                        dprint(FD_NET, "client: received steadystate ring buffers\n");
 
-                       size = le64_to_cpu(p->ts.ss_dur);
-                       p->ts.ss_iops_data = (uint64_t *) ((struct cmd_ts_pdu *)cmd->payload + 1);
-                       p->ts.ss_bw_data = p->ts.ss_iops_data + size;
+                       offset = le64_to_cpu(p->ts.ss_iops_data_offset);
+                       p->ts.ss_iops_data = (uint64_t *)((char *)p + offset);
+
+                       offset = le64_to_cpu(p->ts.ss_bw_data_offset);
+                       p->ts.ss_bw_data = (uint64_t *)((char *)p + offset);
                }
 
                convert_ts(&p->ts, &p->ts);
@@ -2113,8 +2167,12 @@ int fio_handle_clients(struct client_ops *ops)
                }
        }
 
+       log_info_buf(allclients.buf, allclients.buflen);
+       buf_output_free(&allclients);
+
        fio_client_json_fini();
 
+       free_clat_prio_stats(&client_ts);
        free(pfds);
        return retval || error_clients;
 }