X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=client.c;h=7fe571efd9c2b1b503e6a72c76b2df5fc4a29703;hp=515cbf2e178aae746d04a61ccfa0aab4b2d976c6;hb=fd200c6a7d51188815ca2bc80e517768877ebef6;hpb=0a79d3649b127b13c5f0ba33f4431a1d2e502868 diff --git a/client.c b/client.c index 515cbf2e..7fe571ef 100644 --- a/client.c +++ b/client.c @@ -1,13 +1,11 @@ #include #include #include -#include #include #include -#include +#include #include #include -#include #include #include #include @@ -23,17 +21,18 @@ #include "server.h" #include "flist.h" #include "hash.h" -#include "verify.h" +#include "verify-state.h" static void handle_du(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_gs(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd); static void handle_text(struct fio_client *client, struct fio_net_cmd *cmd); -static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd); +static void handle_stop(struct fio_client *client); static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd); static void convert_text(struct fio_net_cmd *cmd); +static void client_display_thread_status(struct jobs_eta *je); struct client_ops fio_client_ops = { .text = handle_text, @@ -42,13 +41,13 @@ struct client_ops fio_client_ops = { .group_stats = handle_gs, .stop = handle_stop, .start = handle_start, - .eta = display_thread_status, + .eta = client_display_thread_status, .probe = handle_probe, .eta_msec = FIO_CLIENT_DEF_ETA_MSEC, .client_type = FIO_CLIENT_TYPE_CLI, }; -static struct timeval eta_tv; +static struct timespec eta_ts; static FLIST_HEAD(client_list); static FLIST_HEAD(eta_list); @@ -60,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; @@ -120,6 +120,58 @@ static int read_data(int fd, void *data, size_t size) return 0; } +static int read_ini_data(int fd, void *data, size_t size) +{ + char *p = data; + int ret = 0; + FILE *fp; + int dupfd; + + dupfd = dup(fd); + if (dupfd < 0) + return errno; + + fp = fdopen(dupfd, "r"); + if (!fp) { + ret = errno; + close(dupfd); + goto out; + } + + while (1) { + ssize_t len; + char buf[OPT_LEN_MAX+1], *sub; + + if (!fgets(buf, sizeof(buf), fp)) { + if (ferror(fp)) { + if (errno == EAGAIN || errno == EINTR) + continue; + ret = errno; + } + break; + } + + sub = fio_option_dup_subs(buf); + len = strlen(sub); + if (len + 1 > size) { + log_err("fio: no space left to read data\n"); + free(sub); + ret = ENOSPC; + break; + } + + memcpy(p, sub, len); + free(sub); + p += len; + *p = '\0'; + size -= len; + } + + fclose(fp); +out: + return ret; +} + static void fio_client_json_init(void) { char time_buf[32]; @@ -147,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; } @@ -182,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); @@ -300,9 +364,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; @@ -315,10 +377,23 @@ struct fio_client *fio_client_add_explicit(struct client_ops *ops, INIT_FLIST_HEAD(&client->eta_list); INIT_FLIST_HEAD(&client->cmd_list); + 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(); + client->hostname = strdup(hostname); if (type == Fio_client_socket) - client->is_sock = 1; + client->is_sock = true; else { int ipv6; @@ -347,7 +422,7 @@ err: return NULL; } -int fio_client_add_ini_file(void *cookie, const char *ini_file, int remote) +int fio_client_add_ini_file(void *cookie, const char *ini_file, bool remote) { struct fio_client *client = cookie; struct client_file *cf; @@ -390,14 +465,7 @@ 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, @@ -557,7 +625,7 @@ int fio_client_terminate(struct fio_client *client) return fio_net_send_quit(client->fd); } -void fio_clients_terminate(void) +static void fio_clients_terminate(void) { struct flist_head *entry; struct fio_client *client; @@ -728,7 +796,7 @@ static int __fio_client_send_remote_ini(struct fio_client *client, strcpy((char *) pdu->file, filename); pdu->client_type = cpu_to_le16((uint16_t) client->type); - client->sent_job = 1; + client->sent_job = true; ret = fio_net_send_cmd(client->fd, FIO_NET_CMD_LOAD_FILE, pdu, p_size,NULL, NULL); free(pdu); return ret; @@ -765,13 +833,17 @@ static int __fio_client_send_local_ini(struct fio_client *client, return ret; } + /* + * Add extra space for variable expansion, but doesn't guarantee. + */ + sb.st_size += OPT_LEN_MAX; p_size = sb.st_size + sizeof(*pdu); pdu = malloc(p_size); buf = pdu->buf; len = sb.st_size; p = buf; - if (read_data(fd, p, len)) { + if (read_ini_data(fd, p, len)) { log_err("fio: failed reading job file %s\n", filename); close(fd); free(pdu); @@ -781,7 +853,7 @@ static int __fio_client_send_local_ini(struct fio_client *client, pdu->buf_len = __cpu_to_le32(sb.st_size); pdu->client_type = cpu_to_le32(client->type); - client->sent_job = 1; + client->sent_job = true; ret = fio_net_send_cmd(client->fd, FIO_NET_CMD_JOB, pdu, p_size, NULL, NULL); free(pdu); close(fd); @@ -789,7 +861,7 @@ static int __fio_client_send_local_ini(struct fio_client *client, } int fio_client_send_ini(struct fio_client *client, const char *filename, - int remote) + bool remote) { int ret; @@ -799,7 +871,7 @@ int fio_client_send_ini(struct fio_client *client, const char *filename, ret = __fio_client_send_remote_ini(client, filename); if (!ret) - client->sent_job = 1; + client->sent_job = true; return ret; } @@ -816,6 +888,8 @@ int fio_clients_send_ini(const char *filename) struct flist_head *entry, *tmp; flist_for_each_safe(entry, tmp, &client_list) { + bool failed = false; + client = flist_entry(entry, struct fio_client, list); if (client->nr_files) { @@ -827,12 +901,13 @@ int fio_clients_send_ini(const char *filename) cf = &client->files[i]; if (fio_client_send_cf(client, cf)) { + failed = true; remove_client(client); break; } } } - if (client->sent_job) + if (client->sent_job || failed) continue; if (!filename || fio_client_send_ini(client, filename, 0)) remove_client(client); @@ -882,6 +957,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) convert_io_stat(&dst->slat_stat[i], &src->slat_stat[i]); convert_io_stat(&dst->lat_stat[i], &src->lat_stat[i]); convert_io_stat(&dst->bw_stat[i], &src->bw_stat[i]); + convert_io_stat(&dst->iops_stat[i], &src->iops_stat[i]); } dst->usr_time = le64_to_cpu(src->usr_time); @@ -889,7 +965,8 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) dst->ctx = le64_to_cpu(src->ctx); dst->minf = le64_to_cpu(src->minf); dst->majf = le64_to_cpu(src->majf); - dst->clat_percentiles = le64_to_cpu(src->clat_percentiles); + dst->clat_percentiles = le32_to_cpu(src->clat_percentiles); + dst->lat_percentiles = le32_to_cpu(src->lat_percentiles); dst->percentile_precision = le64_to_cpu(src->percentile_precision); for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) { @@ -900,19 +977,21 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) } for (i = 0; i < FIO_IO_U_MAP_NR; i++) { - dst->io_u_map[i] = le32_to_cpu(src->io_u_map[i]); - dst->io_u_submit[i] = le32_to_cpu(src->io_u_submit[i]); - dst->io_u_complete[i] = le32_to_cpu(src->io_u_complete[i]); + dst->io_u_map[i] = le64_to_cpu(src->io_u_map[i]); + dst->io_u_submit[i] = le64_to_cpu(src->io_u_submit[i]); + dst->io_u_complete[i] = le64_to_cpu(src->io_u_complete[i]); } - for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) { - dst->io_u_lat_u[i] = le32_to_cpu(src->io_u_lat_u[i]); - dst->io_u_lat_m[i] = le32_to_cpu(src->io_u_lat_m[i]); - } + for (i = 0; i < FIO_IO_U_LAT_N_NR; i++) + dst->io_u_lat_n[i] = le64_to_cpu(src->io_u_lat_n[i]); + for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) + dst->io_u_lat_u[i] = le64_to_cpu(src->io_u_lat_u[i]); + 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] = le32_to_cpu(src->io_u_plat[i][j]); + dst->io_u_plat[i][j] = le64_to_cpu(src->io_u_plat[i][j]); for (i = 0; i < DDIR_RWDIR_CNT; i++) { dst->total_io_u[i] = le64_to_cpu(src->total_io_u[i]); @@ -922,6 +1001,7 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) 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]); @@ -935,6 +1015,8 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) dst->kb_base = le32_to_cpu(src->kb_base); dst->unit_base = le32_to_cpu(src->unit_base); + dst->sig_figs = le32_to_cpu(src->sig_figs); + dst->latency_depth = le32_to_cpu(src->latency_depth); dst->latency_target = le64_to_cpu(src->latency_target); dst->latency_window = le64_to_cpu(src->latency_window); @@ -943,6 +1025,24 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src) dst->nr_block_infos = le64_to_cpu(src->nr_block_infos); for (i = 0; i < dst->nr_block_infos; i++) dst->block_infos[i] = le32_to_cpu(src->block_infos[i]); + + dst->ss_dur = le64_to_cpu(src->ss_dur); + dst->ss_state = le32_to_cpu(src->ss_state); + dst->ss_head = le32_to_cpu(src->ss_head); + dst->ss_limit.u.f = fio_uint64_to_double(le64_to_cpu(src->ss_limit.u.i)); + dst->ss_slope.u.f = fio_uint64_to_double(le64_to_cpu(src->ss_slope.u.i)); + 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)); + + 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) @@ -954,12 +1054,13 @@ static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src) dst->min_run[i] = le64_to_cpu(src->min_run[i]); dst->max_bw[i] = le64_to_cpu(src->max_bw[i]); dst->min_bw[i] = le64_to_cpu(src->min_bw[i]); - dst->io_kb[i] = le64_to_cpu(src->io_kb[i]); + dst->iobytes[i] = le64_to_cpu(src->iobytes[i]); dst->agg[i] = le64_to_cpu(src->agg[i]); } dst->kb_base = le32_to_cpu(src->kb_base); dst->unit_base = le32_to_cpu(src->unit_base); + dst->sig_figs = le32_to_cpu(src->sig_figs); dst->groupid = le32_to_cpu(src->groupid); dst->unified_rw_rep = le32_to_cpu(src->unified_rw_rep); } @@ -982,8 +1083,8 @@ static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd) 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); - client->did_stat = 1; + 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); json_array_add_value_object(clients_array, tsobj); @@ -999,10 +1100,11 @@ static void handle_ts(struct fio_client *client, struct fio_net_cmd *cmd) client_ts.thread_number = p->ts.thread_number; client_ts.groupid = p->ts.groupid; client_ts.unified_rw_rep = p->ts.unified_rw_rep; + client_ts.sig_figs = p->ts.sig_figs; 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); @@ -1015,7 +1117,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; 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) @@ -1057,13 +1159,17 @@ static void handle_text(struct fio_client *client, struct fio_net_cmd *cmd) const char *buf = (const char *) pdu->buf; const char *name; int fio_unused ret; + struct buf_output out; + + buf_output_init(&out); name = client->name ? client->name : client->hostname; - if (!client->skip_newline) - fprintf(f_out, "<%s> ", name); - ret = fwrite(buf, pdu->buf_len, 1, f_out); - fflush(f_out); + if (!client->skip_newline && !(output_format & FIO_OUTPUT_TERSE)) + __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; } @@ -1104,21 +1210,22 @@ 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 (!client->disk_stats_shown) { - client->disk_stats_shown = 1; - log_info("\nDisk stats (read/write):\n"); - } + if (!client->disk_stats_shown) + client->disk_stats_shown = true; 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_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); + 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); } static void convert_jobs_eta(struct jobs_eta *je) @@ -1132,11 +1239,11 @@ static void convert_jobs_eta(struct jobs_eta *je) je->files_open = le32_to_cpu(je->files_open); for (i = 0; i < DDIR_RWDIR_CNT; i++) { - je->m_rate[i] = le32_to_cpu(je->m_rate[i]); - je->t_rate[i] = le32_to_cpu(je->t_rate[i]); + je->m_rate[i] = le64_to_cpu(je->m_rate[i]); + je->t_rate[i] = le64_to_cpu(je->t_rate[i]); je->m_iops[i] = le32_to_cpu(je->m_iops[i]); je->t_iops[i] = le32_to_cpu(je->t_iops[i]); - je->rate[i] = le32_to_cpu(je->rate[i]); + je->rate[i] = le64_to_cpu(je->rate[i]); je->iops[i] = le32_to_cpu(je->iops[i]); } @@ -1145,6 +1252,7 @@ static void convert_jobs_eta(struct jobs_eta *je) je->nr_threads = le32_to_cpu(je->nr_threads); je->is_pow2 = le32_to_cpu(je->is_pow2); je->unit_base = le32_to_cpu(je->unit_base); + je->sig_figs = le32_to_cpu(je->sig_figs); } void fio_client_sum_jobs_eta(struct jobs_eta *dst, struct jobs_eta *je) @@ -1180,7 +1288,7 @@ void fio_client_sum_jobs_eta(struct jobs_eta *dst, struct jobs_eta *je) strcpy((char *) dst->run_str, (char *) je->run_str); } -static void remove_reply_cmd(struct fio_client *client, struct fio_net_cmd *cmd) +static bool remove_reply_cmd(struct fio_client *client, struct fio_net_cmd *cmd) { struct fio_net_cmd_reply *reply = NULL; struct flist_head *entry; @@ -1196,12 +1304,13 @@ static void remove_reply_cmd(struct fio_client *client, struct fio_net_cmd *cmd) if (!reply) { log_err("fio: client: unable to find matching tag (%llx)\n", (unsigned long long) cmd->tag); - return; + return false; } flist_del(&reply->list); cmd->tag = reply->saved_tag; free(reply); + return true; } int fio_client_wait_for_reply(struct fio_client *client, uint64_t tag) @@ -1248,54 +1357,124 @@ static void handle_eta(struct fio_client *client, struct fio_net_cmd *cmd) fio_client_dec_jobs_eta(eta, client->ops->eta); } +static void client_flush_hist_samples(FILE *f, int hist_coarseness, void *samples, + uint64_t sample_size) +{ + struct io_sample *s; + int log_offset; + uint64_t i, j, nr_samples; + struct io_u_plat_entry *entry; + uint64_t *io_u_plat; + + int stride = 1 << hist_coarseness; + + if (!sample_size) + return; + + s = __get_sample(samples, 0, 0); + log_offset = (s->__ddir & LOG_OFFSET_SAMPLE_BIT) != 0; + + nr_samples = sample_size / __log_entry_sz(log_offset); + + for (i = 0; i < nr_samples; i++) { + + s = (struct io_sample *)((char *)__get_sample(samples, log_offset, i) + + i * sizeof(struct io_u_plat_entry)); + + entry = s->data.plat_entry; + io_u_plat = entry->io_u_plat; + + fprintf(f, "%lu, %u, %llu, ", (unsigned long) s->time, + io_sample_ddir(s), (unsigned long long) s->bs); + for (j = 0; j < FIO_IO_U_PLAT_NR - stride; j += stride) { + fprintf(f, "%llu, ", (unsigned long long)hist_sum(j, stride, io_u_plat, NULL)); + } + fprintf(f, "%llu\n", (unsigned long long) + hist_sum(FIO_IO_U_PLAT_NR - stride, stride, io_u_plat, NULL)); + + } +} + static int fio_client_handle_iolog(struct fio_client *client, struct fio_net_cmd *cmd) { - struct cmd_iolog_pdu *pdu; + struct cmd_iolog_pdu *pdu = NULL; bool store_direct; + char *log_pathname = NULL; + int ret = 0; pdu = convert_iolog(cmd, &store_direct); if (!pdu) { log_err("fio: failed converting IO log\n"); - return 1; + ret = 1; + goto out; + } + + /* allocate buffer big enough for next sprintf() call */ + log_pathname = malloc(10 + strlen((char *)pdu->name) + + strlen(client->hostname)); + if (!log_pathname) { + log_err("fio: memory allocation of unique pathname failed\n"); + ret = -1; + goto out; } + /* generate a unique pathname for the log file using hostname */ + sprintf(log_pathname, "%s.%s", pdu->name, client->hostname); if (store_direct) { - ssize_t ret; + ssize_t wrote; size_t sz; int fd; - fd = open((const char *) pdu->name, + fd = open((const char *) log_pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { - log_err("fio: open log: %s\n", strerror(errno)); - return 1; + log_err("fio: open log %s: %s\n", + log_pathname, strerror(errno)); + ret = 1; + goto out; } sz = cmd->pdu_len - sizeof(*pdu); - ret = write(fd, pdu->samples, sz); + wrote = write(fd, pdu->samples, sz); close(fd); - if (ret != sz) { + if (wrote != sz) { log_err("fio: short write on compressed log\n"); - return 1; + ret = 1; + goto out; } - return 0; + ret = 0; } else { FILE *f; - - f = fopen((const char *) pdu->name, "w"); + f = fopen((const char *) log_pathname, "w"); if (!f) { - log_err("fio: fopen log: %s\n", strerror(errno)); - return 1; + log_err("fio: fopen log %s : %s\n", + log_pathname, strerror(errno)); + ret = 1; + goto out; } - flush_samples(f, pdu->samples, - pdu->nr_samples * sizeof(struct io_sample)); + if (pdu->log_type == IO_LOG_TYPE_HIST) { + client_flush_hist_samples(f, pdu->log_hist_coarseness, pdu->samples, + pdu->nr_samples * sizeof(struct io_sample)); + } else { + flush_samples(f, pdu->samples, + pdu->nr_samples * sizeof(struct io_sample)); + } fclose(f); - return 0; + ret = 0; } + +out: + if (pdu && pdu != (void *) cmd->payload) + free(pdu); + + if (log_pathname) + free(log_pathname); + + return ret; } static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd) @@ -1315,9 +1494,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); - 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 (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); @@ -1345,7 +1526,7 @@ static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd) sum_stat_clients += client->nr_stat; } -static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd) +static void handle_stop(struct fio_client *client) { if (client->error) log_info("client <%s>: exited with error %d\n", client->hostname, client->error); @@ -1374,9 +1555,9 @@ static struct cmd_iolog_pdu *convert_iolog_gz(struct fio_net_cmd *cmd, #ifdef CONFIG_ZLIB struct cmd_iolog_pdu *ret; z_stream stream; - uint32_t nr_samples; + uint64_t nr_samples; size_t total; - void *p; + char *p; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; @@ -1392,16 +1573,20 @@ static struct cmd_iolog_pdu *convert_iolog_gz(struct fio_net_cmd *cmd, */ nr_samples = le64_to_cpu(pdu->nr_samples); - total = nr_samples * __log_entry_sz(le32_to_cpu(pdu->log_offset)); + if (pdu->log_type == IO_LOG_TYPE_HIST) + total = nr_samples * (__log_entry_sz(le32_to_cpu(pdu->log_offset)) + + sizeof(struct io_u_plat_entry)); + else + total = nr_samples * __log_entry_sz(le32_to_cpu(pdu->log_offset)); ret = malloc(total + sizeof(*pdu)); ret->nr_samples = nr_samples; memcpy(ret, pdu, sizeof(*pdu)); - p = (void *) ret + sizeof(*pdu); + p = (char *) ret + sizeof(*pdu); stream.avail_in = cmd->pdu_len - sizeof(*pdu); - stream.next_in = (void *) pdu + sizeof(*pdu); + stream.next_in = (void *)((char *) pdu + sizeof(*pdu)); while (stream.avail_in) { unsigned int this_chunk = 65536; unsigned int this_len; @@ -1411,10 +1596,15 @@ static struct cmd_iolog_pdu *convert_iolog_gz(struct fio_net_cmd *cmd, this_chunk = total; stream.avail_out = this_chunk; - stream.next_out = p; + stream.next_out = (void *)p; 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; @@ -1475,6 +1665,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_hist_coarseness = le32_to_cpu(ret->log_hist_coarseness); if (*store_direct) return ret; @@ -1484,16 +1675,25 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd, struct io_sample *s; s = __get_sample(samples, ret->log_offset, i); + if (ret->log_type == IO_LOG_TYPE_HIST) + s = (struct io_sample *)((char *)s + sizeof(struct io_u_plat_entry) * i); + s->time = le64_to_cpu(s->time); - s->val = le64_to_cpu(s->val); + s->data.val = le64_to_cpu(s->data.val); s->__ddir = le32_to_cpu(s->__ddir); - s->bs = le32_to_cpu(s->bs); + s->bs = le64_to_cpu(s->bs); if (ret->log_offset) { struct io_sample_offset *so = (void *) s; so->offset = le64_to_cpu(so->offset); } + + if (ret->log_type == IO_LOG_TYPE_HIST) { + s->data.plat_entry = (struct io_u_plat_entry *)(((char *)s) + sizeof(*s)); + s->data.plat_entry->list.next = NULL; + s->data.plat_entry->list.prev = NULL; + } } return ret; @@ -1544,6 +1744,7 @@ 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); @@ -1554,6 +1755,8 @@ int fio_handle_client(struct fio_client *client) dprint(FD_NET, "client: got cmd op %s from %s (pdu=%u)\n", fio_server_op(cmd->opcode), client->hostname, cmd->pdu_len); + client->last_cmd = cmd->opcode; + switch (cmd->opcode) { case FIO_NET_CMD_QUIT: if (ops->quit) @@ -1576,6 +1779,15 @@ int fio_handle_client(struct fio_client *client) case FIO_NET_CMD_TS: { struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload; + 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; + } + convert_ts(&p->ts, &p->ts); convert_gs(&p->rs, &p->rs); @@ -1593,7 +1805,8 @@ int fio_handle_client(struct fio_client *client) case FIO_NET_CMD_ETA: { struct jobs_eta *je = (struct jobs_eta *) cmd->payload; - remove_reply_cmd(client, cmd); + if (!remove_reply_cmd(client, cmd)) + break; convert_jobs_eta(je); handle_eta(client, cmd); break; @@ -1621,7 +1834,7 @@ int fio_handle_client(struct fio_client *client) client->state = Client_stopped; client->error = le32_to_cpu(pdu->error); client->signal = le32_to_cpu(pdu->signal); - ops->stop(client, cmd); + ops->stop(client); break; } case FIO_NET_CMD_ADD_JOB: { @@ -1710,6 +1923,9 @@ static void request_client_etas(struct client_ops *ops) struct client_eta *eta; int skipped = 0; + if (eta_print == FIO_ETA_NEVER) + return; + dprint(FD_NET, "client: request eta (%d)\n", nr_clients); eta = calloc(1, sizeof(*eta) + __THREAD_RUNSTR_SZ(REAL_MAX_JOBS)); @@ -1746,10 +1962,12 @@ static void request_client_etas(struct client_ops *ops) static int handle_cmd_timeout(struct fio_client *client, struct fio_net_cmd_reply *reply) { + uint16_t reply_opcode = reply->opcode; + flist_del(&reply->list); free(reply); - if (reply->opcode != FIO_NET_CMD_SEND_ETA) + if (reply_opcode != FIO_NET_CMD_SEND_ETA) return 1; log_info("client <%s>: timeout on SEND_ETA\n", client->hostname); @@ -1770,23 +1988,26 @@ static int handle_cmd_timeout(struct fio_client *client, } static int client_check_cmd_timeout(struct fio_client *client, - struct timeval *now) + struct timespec *now) { struct fio_net_cmd_reply *reply; struct flist_head *entry, *tmp; int ret = 0; flist_for_each_safe(entry, tmp, &client->cmd_list) { + unsigned int op; + reply = flist_entry(entry, struct fio_net_cmd_reply, list); - if (mtime_since(&reply->tv, now) < FIO_NET_CLIENT_TIMEOUT) + if (mtime_since(&reply->ts, now) < FIO_NET_CLIENT_TIMEOUT) continue; + op = reply->opcode; if (!handle_cmd_timeout(client, reply)) continue; log_err("fio: client %s, timeout on cmd %s\n", client->hostname, - fio_server_op(reply->opcode)); + fio_server_op(op)); ret = 1; } @@ -1797,10 +2018,10 @@ static int fio_check_clients_timed_out(void) { struct fio_client *client; struct flist_head *entry, *tmp; - struct timeval tv; + struct timespec ts; int ret = 0; - fio_gettime(&tv, NULL); + fio_gettime(&ts, NULL); flist_for_each_safe(entry, tmp, &client_list) { client = flist_entry(entry, struct fio_client, list); @@ -1808,7 +2029,7 @@ static int fio_check_clients_timed_out(void) if (flist_empty(&client->cmd_list)) continue; - if (!client_check_cmd_timeout(client, &tv)) + if (!client_check_cmd_timeout(client, &ts)) continue; if (client->ops->timed_out) @@ -1816,7 +2037,10 @@ static int fio_check_clients_timed_out(void) else log_err("fio: client %s timed out\n", client->hostname); - client->error = ETIMEDOUT; + if (client->last_cmd != FIO_NET_CMD_VTRIGGER) + client->error = ETIMEDOUT; + else + log_info("fio: ignoring timeout due to vtrigger\n"); remove_client(client); ret = 1; } @@ -1829,7 +2053,7 @@ int fio_handle_clients(struct client_ops *ops) struct pollfd *pfds; int i, ret = 0, retval = 0; - fio_gettime(&eta_tv, NULL); + fio_gettime(&eta_ts, NULL); pfds = malloc(nr_clients * sizeof(struct pollfd)); @@ -1861,13 +2085,13 @@ int fio_handle_clients(struct client_ops *ops) assert(i == nr_clients); do { - struct timeval tv; + struct timespec ts; int timeout; - fio_gettime(&tv, NULL); - if (mtime_since(&eta_tv, &tv) >= 900) { + fio_gettime(&ts, NULL); + if (eta_time_within_slack(mtime_since(&eta_ts, &ts))) { request_client_etas(ops); - memcpy(&eta_tv, &tv, sizeof(tv)); + memcpy(&eta_ts, &ts, sizeof(ts)); if (fio_check_clients_timed_out()) break; @@ -1907,8 +2131,17 @@ int fio_handle_clients(struct client_ops *ops) } } + log_info_buf(allclients.buf, allclients.buflen); + buf_output_free(&allclients); + fio_client_json_fini(); free(pfds); return retval || error_clients; } + +static void client_display_thread_status(struct jobs_eta *je) +{ + if (!(output_format & FIO_OUTPUT_JSON)) + display_thread_status(je); +}