X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=client.c;h=7f035c7d7804e764e1557c1fee1af1641d971038;hp=66ef38ca1e93dd761975b5773adc215cae4efa57;hb=38fdef226f1a1fa053ab53005abbc184143bff65;hpb=7f868316a7244cad23735e44e6ef66e5779c9660 diff --git a/client.c b/client.c index 66ef38ca..7f035c7d 100644 --- a/client.c +++ b/client.c @@ -28,6 +28,7 @@ struct client_eta { struct fio_client { struct flist_head list; struct flist_head hash_list; + struct flist_head arg_list; struct sockaddr_in addr; struct sockaddr_un addr_un; char *hostname; @@ -44,6 +45,8 @@ struct fio_client { struct flist_head eta_list; struct client_eta *eta_in_flight; + struct flist_head cmd_list; + uint16_t argc; char **argv; }; @@ -61,6 +64,13 @@ enum { static FLIST_HEAD(client_list); static FLIST_HEAD(eta_list); +static FLIST_HEAD(arg_list); + +static struct thread_stat client_ts; +static struct group_run_stats client_gs; +static int sum_stat_clients; +static int sum_stat_nr; + #define FIO_CLIENT_HASH_BITS 7 #define FIO_CLIENT_HASH_SZ (1 << FIO_CLIENT_HASH_BITS) #define FIO_CLIENT_HASH_MASK (FIO_CLIENT_HASH_SZ - 1) @@ -127,6 +137,7 @@ static void remove_client(struct fio_client *client) free(client); nr_clients--; + sum_stat_clients--; } static void __fio_client_add_cmd_option(struct fio_client *client, @@ -143,23 +154,49 @@ static void __fio_client_add_cmd_option(struct fio_client *client, void fio_client_add_cmd_option(void *cookie, const char *opt) { struct fio_client *client = cookie; + struct flist_head *entry; if (!client || !opt) return; __fio_client_add_cmd_option(client, opt); + + /* + * Duplicate arguments to shared client group + */ + flist_for_each(entry, &arg_list) { + client = flist_entry(entry, struct fio_client, arg_list); + + __fio_client_add_cmd_option(client, opt); + } } int fio_client_add(const char *hostname, void **cookie) { + struct fio_client *existing = *cookie; struct fio_client *client; + if (existing) { + /* + * We always add our "exec" name as the option, hence 1 + * means empty. + */ + if (existing->argc == 1) + flist_add_tail(&existing->arg_list, &arg_list); + else { + while (!flist_empty(&arg_list)) + flist_del_init(arg_list.next); + } + } + 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); if (fio_server_parse_string(hostname, &client->hostname, &client->is_sock, &client->port, @@ -238,6 +275,8 @@ static int fio_client_connect(struct fio_client *client) else fd = fio_client_connect_ip(client); + dprint(FD_NET, "client: %s connected %d\n", client->hostname, fd); + if (fd < 0) return 1; @@ -257,7 +296,7 @@ void fio_clients_terminate(void) flist_for_each(entry, &client_list) { client = flist_entry(entry, struct fio_client, list); - fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_QUIT, 0); + fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_QUIT, 0, NULL); } } @@ -286,8 +325,7 @@ static void probe_client(struct fio_client *client) { dprint(FD_NET, "client: send probe\n"); - fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_PROBE, 0); - handle_client(client); + fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_PROBE, 0, &client->cmd_list); } static int send_client_cmd_line(struct fio_client *client) @@ -539,6 +577,20 @@ static void handle_ts(struct fio_net_cmd *cmd) convert_gs(&p->rs, &p->rs); show_thread_status(&p->ts, &p->rs); + + if (sum_stat_clients == 1) + return; + + sum_thread_stats(&client_ts, &p->ts, sum_stat_nr); + sum_group_stats(&client_gs, &p->rs); + + client_ts.members++; + client_ts.groupid = p->ts.groupid; + + if (++sum_stat_nr == sum_stat_clients) { + strcpy(client_ts.name, "All clients"); + show_thread_status(&client_ts, &client_gs); + } } static void handle_gs(struct fio_net_cmd *cmd) @@ -603,13 +655,40 @@ static void dec_jobs_eta(struct client_eta *eta) } } +static void remove_reply_cmd(struct fio_client *client, struct fio_net_cmd *cmd) +{ + struct fio_net_int_cmd *icmd = NULL; + struct flist_head *entry; + + flist_for_each(entry, &client->cmd_list) { + icmd = flist_entry(entry, struct fio_net_int_cmd, list); + + if (cmd->tag == (uintptr_t) icmd) + break; + + icmd = NULL; + } + + if (!icmd) { + log_err("fio: client: unable to find matching tag\n"); + return; + } + + flist_del(&icmd->list); + cmd->tag = icmd->saved_tag; + free(icmd); +} + static void handle_eta(struct fio_client *client, struct fio_net_cmd *cmd) { struct jobs_eta *je = (struct jobs_eta *) cmd->payload; - struct client_eta *eta = (struct client_eta *) cmd->tag; + struct client_eta *eta = (struct client_eta *) (uintptr_t) cmd->tag; dprint(FD_NET, "client: got eta tag %p, %d\n", eta, eta->pending); + assert(client->eta_in_flight == eta); + + client->eta_in_flight = NULL; flist_del_init(&client->eta_list); convert_jobs_eta(je); @@ -620,7 +699,7 @@ static void handle_eta(struct fio_client *client, struct fio_net_cmd *cmd) static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd) { struct cmd_probe_pdu *probe = (struct cmd_probe_pdu *) cmd->payload; - const char *os, *arch; + const char *os, *arch, *bit; os = fio_get_os_string(probe->os); if (!os) @@ -630,9 +709,18 @@ static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd) if (!arch) os = "unknown"; - log_info("hostname=%s, be=%u, os=%s, arch=%s, fio=%u.%u.%u\n", - probe->hostname, probe->bigendian, os, arch, probe->fio_major, - probe->fio_minor, probe->fio_patch); + if (probe->bpp == 2) + bit = "16-bit"; + else if (probe->bpp == 4) + bit = "32-bit"; + else if (probe->bpp == 8) + bit = "64-bit"; + else + bit = "unknown"; + + log_info("hostname=%s, be=%u, %s, os=%s, arch=%s, fio=%u.%u.%u\n", + probe->hostname, probe->bigendian, bit, os, arch, + probe->fio_major, probe->fio_minor, probe->fio_patch); if (!client->name) client->name = strdup((char *) probe->hostname); @@ -648,8 +736,8 @@ static int handle_client(struct fio_client *client) if (!cmd) return 0; - dprint(FD_NET, "client: got cmd op %d from %s\n", - cmd->opcode, client->hostname); + dprint(FD_NET, "client: got cmd op %s from %s\n", + fio_server_op(cmd->opcode), client->hostname); switch (cmd->opcode) { case FIO_NET_CMD_QUIT: @@ -680,10 +768,12 @@ static int handle_client(struct fio_client *client) free(cmd); break; case FIO_NET_CMD_ETA: + remove_reply_cmd(client, cmd); handle_eta(client, cmd); free(cmd); break; case FIO_NET_CMD_PROBE: + remove_reply_cmd(client, cmd); handle_probe(client, cmd); free(cmd); break; @@ -696,7 +786,7 @@ static int handle_client(struct fio_client *client) free(cmd); break; default: - log_err("fio: unknown client op: %d\n", cmd->opcode); + log_err("fio: unknown client op: %s\n", fio_server_op(cmd->opcode)); free(cmd); break; } @@ -725,9 +815,11 @@ static void request_client_etas(void) continue; } + assert(!client->eta_in_flight); flist_add_tail(&client->eta_list, &eta_list); + client->eta_in_flight = eta; fio_net_send_simple_cmd(client->fd, FIO_NET_CMD_SEND_ETA, - (uint64_t) eta); + (uintptr_t) eta, &client->cmd_list); } while (skipped--) @@ -736,6 +828,55 @@ static void request_client_etas(void) dprint(FD_NET, "client: requested eta tag %p\n", eta); } +static int client_check_cmd_timeout(struct fio_client *client, + struct timeval *now) +{ + struct fio_net_int_cmd *cmd; + struct flist_head *entry, *tmp; + int ret = 0; + + flist_for_each_safe(entry, tmp, &client->cmd_list) { + cmd = flist_entry(entry, struct fio_net_int_cmd, list); + + if (mtime_since(&cmd->tv, now) < FIO_NET_CLIENT_TIMEOUT) + continue; + + log_err("fio: client %s, timeout on cmd %s\n", client->hostname, + fio_server_op(cmd->cmd.opcode)); + flist_del(&cmd->list); + free(cmd); + ret = 1; + } + + return flist_empty(&client->cmd_list) && ret; +} + +static int fio_client_timed_out(void) +{ + struct fio_client *client; + struct flist_head *entry, *tmp; + struct timeval tv; + int ret = 0; + + gettimeofday(&tv, NULL); + + flist_for_each_safe(entry, tmp, &client_list) { + client = flist_entry(entry, struct fio_client, list); + + if (flist_empty(&client->cmd_list)) + continue; + + if (!client_check_cmd_timeout(client, &tv)) + continue; + + log_err("fio: client %s timed out\n", client->hostname); + remove_client(client); + ret = 1; + } + + return ret; +} + int fio_handle_clients(void) { struct fio_client *client; @@ -747,6 +888,10 @@ int fio_handle_clients(void) pfds = malloc(nr_clients * sizeof(struct pollfd)); + sum_stat_clients = nr_clients; + init_thread_stat(&client_ts); + init_group_run_stat(&client_gs); + while (!exit_backend && nr_clients) { i = 0; flist_for_each(entry, &client_list) { @@ -766,6 +911,9 @@ int fio_handle_clients(void) if (mtime_since(&eta_tv, &tv) >= 900) { request_client_etas(); memcpy(&eta_tv, &tv, sizeof(tv)); + + if (fio_client_timed_out()) + break; } ret = poll(pfds, nr_clients, 100);