X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=client.c;h=4121ea5f4f17df7a9565570bcbb51816ae0229fb;hp=637cd3fb5332dac5a552e19459fe344a807bf625;hb=34fbdab48d2399e8d11a6f40353ba00d2edf9151;hpb=bc0fec0e12f19dd424f4bf83cfca89d434184c8d diff --git a/client.c b/client.c index 637cd3fb..4121ea5f 100644 --- a/client.c +++ b/client.c @@ -33,6 +33,8 @@ 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_start(struct fio_client *client, struct fio_net_cmd *cmd); +static void convert_text(struct fio_net_cmd *cmd); + struct client_ops fio_client_ops = { .text = handle_text, .disk_util = handle_du, @@ -70,6 +72,8 @@ static int error_clients; #define FIO_CLIENT_HASH_MASK (FIO_CLIENT_HASH_SZ - 1) static struct flist_head client_hash[FIO_CLIENT_HASH_SZ]; +static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *, bool *); + static void fio_client_add_hash(struct fio_client *client) { int bucket = hash_long(client->fd, FIO_CLIENT_HASH_BITS); @@ -213,12 +217,32 @@ static int fio_client_dec_jobs_eta(struct client_eta *eta, client_eta_op eta_fn) return 1; } +static void fio_drain_client_text(struct fio_client *client) +{ + do { + struct fio_net_cmd *cmd; + + cmd = fio_net_recv_cmd(client->fd, false); + if (!cmd) + break; + + if (cmd->opcode == FIO_NET_CMD_TEXT) { + convert_text(cmd); + client->ops->text(client, cmd); + } + + free(cmd); + } while (1); +} + static void remove_client(struct fio_client *client) { assert(client->refs); dprint(FD_NET, "client: removed <%s>\n", client->hostname); + fio_drain_client_text(client); + if (!flist_empty(&client->list)) flist_del_init(&client->list); @@ -323,7 +347,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; @@ -533,7 +557,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; @@ -765,7 +789,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; @@ -792,6 +816,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) { @@ -803,12 +829,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); @@ -1156,7 +1183,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; @@ -1172,12 +1199,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) @@ -1224,6 +1252,112 @@ 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; + unsigned int *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->plat_entry; + io_u_plat = entry->io_u_plat; + + fprintf(f, "%lu, %u, %u, ", (unsigned long) s->time, + io_sample_ddir(s), s->bs); + for (j = 0; j < FIO_IO_U_PLAT_NR - stride; j += stride) { + fprintf(f, "%lu, ", hist_sum(j, stride, io_u_plat, NULL)); + } + fprintf(f, "%lu\n", (unsigned 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; + bool store_direct; + char *log_pathname; + + pdu = convert_iolog(cmd, &store_direct); + if (!pdu) { + log_err("fio: failed converting IO log\n"); + return 1; + } + + /* 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"); + return -1; + } + /* 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; + size_t sz; + int fd; + + fd = open((const char *) log_pathname, + O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) { + log_err("fio: open log %s: %s\n", + log_pathname, strerror(errno)); + return 1; + } + + sz = cmd->pdu_len - sizeof(*pdu); + ret = write(fd, pdu->samples, sz); + close(fd); + + if (ret != sz) { + log_err("fio: short write on compressed log\n"); + return 1; + } + + return 0; + } else { + FILE *f; + f = fopen((const char *) log_pathname, "w"); + if (!f) { + log_err("fio: fopen log %s : %s\n", + log_pathname, strerror(errno)); + return 1; + } + + 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; + } +} + static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd) { struct cmd_probe_reply_pdu *probe = (struct cmd_probe_reply_pdu *) cmd->payload; @@ -1318,7 +1452,11 @@ 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; @@ -1364,18 +1502,23 @@ err: * This has been compressed on the server side, since it can be big. * Uncompress here. */ -static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd) +static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd, + bool *store_direct) { struct cmd_iolog_pdu *pdu = (struct cmd_iolog_pdu *) cmd->payload; struct cmd_iolog_pdu *ret; uint64_t i; + int compressed; void *samples; + *store_direct = false; + /* * Convert if compressed and we support it. If it's not * compressed, we need not do anything. */ - if (le32_to_cpu(pdu->compressed)) { + compressed = le32_to_cpu(pdu->compressed); + if (compressed == XMIT_COMPRESSED) { #ifndef CONFIG_ZLIB log_err("fio: server sent compressed data by mistake\n"); return NULL; @@ -1385,6 +1528,9 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd) log_err("fio: failed decompressing log\n"); return NULL; } + } else if (compressed == STORE_COMPRESSED) { + *store_direct = true; + ret = pdu; } else ret = pdu; @@ -1393,12 +1539,19 @@ 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; samples = &ret->samples[0]; for (i = 0; i < ret->nr_samples; i++) { struct io_sample *s; s = __get_sample(samples, ret->log_offset, i); + if (ret->log_type == IO_LOG_TYPE_HIST) + s = (struct io_sample *)((void *)s + sizeof(struct io_u_plat_entry) * i); + s->time = le64_to_cpu(s->time); s->val = le64_to_cpu(s->val); s->__ddir = le32_to_cpu(s->__ddir); @@ -1409,6 +1562,12 @@ static struct cmd_iolog_pdu *convert_iolog(struct fio_net_cmd *cmd) so->offset = le64_to_cpu(so->offset); } + + if (ret->log_type == IO_LOG_TYPE_HIST) { + s->plat_entry = (struct io_u_plat_entry *)(((void *)s) + sizeof(*s)); + s->plat_entry->list.next = NULL; + s->plat_entry->list.prev = NULL; + } } return ret; @@ -1421,8 +1580,8 @@ static void sendfile_reply(int fd, struct cmd_sendfile_reply *rep, fio_net_send_cmd(fd, FIO_NET_CMD_SENDFILE, rep, size, &tag, NULL); } -static int send_file(struct fio_client *client, struct cmd_sendfile *pdu, - uint64_t tag) +static int fio_send_file(struct fio_client *client, struct cmd_sendfile *pdu, + uint64_t tag) { struct cmd_sendfile_reply *rep; struct stat sb; @@ -1462,7 +1621,7 @@ int fio_handle_client(struct fio_client *client) dprint(FD_NET, "client: handle %s\n", client->hostname); - cmd = fio_net_recv_cmd(client->fd); + cmd = fio_net_recv_cmd(client->fd, true); if (!cmd) return 0; @@ -1508,7 +1667,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; @@ -1550,12 +1710,7 @@ int fio_handle_client(struct fio_client *client) break; } case FIO_NET_CMD_IOLOG: - if (ops->iolog) { - struct cmd_iolog_pdu *pdu; - - pdu = convert_iolog(cmd); - ops->iolog(client, pdu); - } + fio_client_handle_iolog(client, cmd); break; case FIO_NET_CMD_UPDATE_JOB: ops->update_job(client, cmd); @@ -1577,7 +1732,7 @@ int fio_handle_client(struct fio_client *client) } case FIO_NET_CMD_SENDFILE: { struct cmd_sendfile *pdu = (struct cmd_sendfile *) cmd->payload; - send_file(client, pdu, cmd->tag); + fio_send_file(client, pdu, cmd->tag); break; } case FIO_NET_CMD_JOB_OPT: { @@ -1666,12 +1821,13 @@ static void request_client_etas(struct client_ops *ops) static int handle_cmd_timeout(struct fio_client *client, struct fio_net_cmd_reply *reply) { + flist_del(&reply->list); + free(reply); + if (reply->opcode != FIO_NET_CMD_SEND_ETA) return 1; log_info("client <%s>: timeout on SEND_ETA\n", client->hostname); - flist_del(&reply->list); - free(reply); flist_del_init(&client->eta_list); if (client->eta_in_flight) { @@ -1706,8 +1862,6 @@ static int client_check_cmd_timeout(struct fio_client *client, log_err("fio: client %s, timeout on cmd %s\n", client->hostname, fio_server_op(reply->opcode)); - flist_del(&reply->list); - free(reply); ret = 1; }