The following changes since commit 72c27ff8f2eaf945ae34776dab4da3fee753707d: Fix problem with mixing is_backend and terse_output (2011-10-16 11:50:31 +0200) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (6): client/server: send back nr_jobs and error exit code client: pass back server side error to client exit value Fix possible use-after-free on client disconnect Fio 1.99.8 Add terse version 2 output format Update command line usage help README | 2 +- client.c | 33 ++++++++++++++++++--- fio.1 | 2 +- fio.c | 14 +++++---- fio.h | 4 +- fio_version.h | 2 +- init.c | 50 +++++++++++++++++---------------- os/windows/install.wxs | 2 +- os/windows/version.h | 2 +- server.c | 9 +++++- server.h | 8 +++++ stat.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++- 12 files changed, 156 insertions(+), 45 deletions(-) --- Diff of recent changes: diff --git a/README b/README index 26b5909..d41fc66 100644 --- a/README +++ b/README @@ -137,7 +137,7 @@ $ fio --bandwidth-log Generate per-job bandwidth logs --minimal Minimal (terse) output --version Print version info and exit - --terse-version=type Terse version output format + --terse-version=type Terse version output format (default 3, or 2). --help Print this page --cmdhelp=cmd Print command help, "all" for all of them --showcmd Turn a job file into command line options diff --git a/client.c b/client.c index fb678e1..fda16b8 100644 --- a/client.c +++ b/client.c @@ -42,6 +42,8 @@ struct fio_client { int skip_newline; int is_sock; int disk_stats_shown; + unsigned int jobs; + int error; struct flist_head eta_list; struct client_eta *eta_in_flight; @@ -770,6 +772,25 @@ static void handle_probe(struct fio_client *client, struct fio_net_cmd *cmd) client->name = strdup((char *) probe->hostname); } +static void handle_start(struct fio_client *client, struct fio_net_cmd *cmd) +{ + struct cmd_start_pdu *pdu = (struct cmd_start_pdu *) cmd->payload; + + client->state = Client_started; + client->jobs = le32_to_cpu(pdu->jobs); +} + +static void handle_stop(struct fio_client *client, struct fio_net_cmd *cmd) +{ + struct cmd_end_pdu *pdu = (struct cmd_end_pdu *) cmd->payload; + + client->state = Client_stopped; + client->error = le32_to_cpu(pdu->error); + + if (client->error) + log_info("client <%s>: exited with error %d\n", client->hostname, client->error); +} + static int handle_client(struct fio_client *client) { struct fio_net_cmd *cmd; @@ -830,11 +851,11 @@ static int handle_client(struct fio_client *client) free(cmd); break; case FIO_NET_CMD_START: - client->state = Client_started; + handle_start(client, cmd); free(cmd); break; case FIO_NET_CMD_STOP: - client->state = Client_stopped; + handle_stop(client, cmd); free(cmd); break; default: @@ -936,7 +957,7 @@ int fio_handle_clients(void) struct fio_client *client; struct flist_head *entry; struct pollfd *pfds; - int i, ret = 0; + int i, ret = 0, retval = 0; gettimeofday(&eta_tv, NULL); @@ -993,10 +1014,12 @@ int fio_handle_clients(void) log_info("client: host=%s disconnected\n", client->hostname); remove_client(client); - } + retval = 1; + } else if (client->error) + retval = 1; } } free(pfds); - return 0; + return retval; } diff --git a/fio.1 b/fio.1 index aa027dc..d63d1f2 100644 --- a/fio.1 +++ b/fio.1 @@ -36,7 +36,7 @@ Print statistics in a terse, semicolon-delimited format. Display version information and exit. .TP .BI \-\-terse\-version \fR=\fPversion -Set terse version output format. +Set terse version output format (Current version 3, or older version 2). .TP .B \-\-help Display usage information and exit. diff --git a/fio.c b/fio.c index 856ca75..3a53794 100644 --- a/fio.c +++ b/fio.c @@ -55,9 +55,9 @@ unsigned long page_size; (char *) (((unsigned long) (buf) + page_mask) & ~page_mask) int groupid = 0; -int thread_number = 0; -int nr_process = 0; -int nr_thread = 0; +unsigned int thread_number = 0; +unsigned int nr_process = 0; +unsigned int nr_thread = 0; int shm_id = 0; int temp_stall_ts; unsigned long done_secs = 0; @@ -1398,10 +1398,12 @@ static int fork_main(int shmid, int offset) /* * Run over the job map and reap the threads that have exited, if any. */ -static void reap_threads(int *nr_running, int *t_rate, int *m_rate) +static void reap_threads(unsigned int *nr_running, unsigned int *t_rate, + unsigned int *m_rate) { struct thread_data *td; - int i, cputhreads, realthreads, pending, status, ret; + unsigned int cputhreads, realthreads, pending; + int i, status, ret; /* * reap exited threads (TD_EXITED -> TD_REAPED) @@ -1541,7 +1543,7 @@ static void run_threads(void) { struct thread_data *td; unsigned long spent; - int i, todo, nr_running, m_rate, t_rate, nr_started; + unsigned int i, todo, nr_running, m_rate, t_rate, nr_started; if (fio_pin_memory()) return; diff --git a/fio.h b/fio.h index df0daf6..be684ca 100644 --- a/fio.h +++ b/fio.h @@ -482,8 +482,8 @@ enum { #define __fio_stringify(x) __fio_stringify_1(x) extern int exitall_on_terminate; -extern int thread_number; -extern int nr_process, nr_thread; +extern unsigned int thread_number; +extern unsigned int nr_process, nr_thread; extern int shm_id; extern int groupid; extern int terse_output; diff --git a/fio_version.h b/fio_version.h index 9f897cc..d98e5e9 100644 --- a/fio_version.h +++ b/fio_version.h @@ -3,6 +3,6 @@ #define FIO_MAJOR 1 #define FIO_MINOR 99 -#define FIO_PATCH 7 +#define FIO_PATCH 8 #endif diff --git a/init.c b/init.c index 72ec85d..ee6c139 100644 --- a/init.c +++ b/init.c @@ -54,7 +54,7 @@ char **job_sections = NULL; int nr_job_sections = 0; char *exec_profile = NULL; int warnings_fatal = 0; -int terse_version = 2; +int terse_version = 3; int is_backend = 0; int nr_clients = 0; int log_syslog = 0; @@ -1107,32 +1107,34 @@ static void usage(const char *name) { printf("fio %s\n", fio_version_string); printf("%s [options] [job options] <job file(s)>\n", name); - printf("\t--debug=options\tEnable debug logging\n"); - printf("\t--output\tWrite output to file\n"); - printf("\t--timeout\tRuntime in seconds\n"); - printf("\t--latency-log\tGenerate per-job latency logs\n"); - printf("\t--bandwidth-log\tGenerate per-job bandwidth logs\n"); - printf("\t--minimal\tMinimal (terse) output\n"); - printf("\t--version\tPrint version info and exit\n"); - printf("\t--terse-version=x Terse version output format\n"); - printf("\t--help\t\tPrint this page\n"); - printf("\t--cmdhelp=cmd\tPrint command help, \"all\" for all of" + printf(" --debug=options\tEnable debug logging. May be one/more of:\n" + "\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n" + "\t\t\tdiskutil,job,mutex,profile,time,net\n"); + printf(" --output\t\tWrite output to file\n"); + printf(" --timeout\t\tRuntime in seconds\n"); + printf(" --latency-log\t\tGenerate per-job latency logs\n"); + printf(" --bandwidth-log\tGenerate per-job bandwidth logs\n"); + printf(" --minimal\t\tMinimal (terse) output\n"); + printf(" --version\t\tPrint version info and exit\n"); + printf(" --terse-version=x\tTerse version output format to 'x'\n"); + printf(" --help\t\tPrint this page\n"); + printf(" --cmdhelp=cmd\t\tPrint command help, \"all\" for all of" " them\n"); - printf("\t--showcmd\tTurn a job file into command line options\n"); - printf("\t--eta=when\tWhen ETA estimate should be printed\n"); - printf("\t \tMay be \"always\", \"never\" or \"auto\"\n"); - printf("\t--readonly\tTurn on safety read-only checks, preventing" + printf(" --showcmd\t\tTurn a job file into command line options\n"); + printf(" --eta=when\t\tWhen ETA estimate should be printed\n"); + printf(" \t\tMay be \"always\", \"never\" or \"auto\"\n"); + printf(" --readonly\t\tTurn on safety read-only checks, preventing" " writes\n"); - printf("\t--section=name\tOnly run specified section in job file\n"); - printf("\t--alloc-size=kb\tSet smalloc pool to this size in kb" + printf(" --section=name\tOnly run specified section in job file\n"); + printf(" --alloc-size=kb\tSet smalloc pool to this size in kb" " (def 1024)\n"); - printf("\t--warnings-fatal Fio parser warnings are fatal\n"); - printf("\t--max-jobs\tMaximum number of threads/processes to support\n"); - printf("\t--server=args\tStart a backend fio server\n"); - printf("\t--daemonize=pidfile Background fio server, write pid to file\n"); - printf("\t--client=hostname Talk to remote backend fio server at hostname\n"); + printf(" --warnings-fatal\tFio parser warnings are fatal\n"); + printf(" --max-jobs=nr\t\tMaximum number of threads/processes to support\n"); + printf(" --server=args\t\tStart a backend fio server\n"); + printf(" --daemonize=pidfile\tBackground fio server, write pid to file\n"); + printf(" --client=hostname\tTalk to remote backend fio server at hostname\n"); printf("\nFio was written by Jens Axboe <jens.axboe@xxxxxxxxxx>"); - printf("\n Jens Axboe <jaxboe@xxxxxxxxxxxx>\n"); + printf("\n Jens Axboe <jaxboe@xxxxxxxxxxxx>\n"); } #ifdef FIO_INC_DEBUG @@ -1330,7 +1332,7 @@ int parse_cmd_line(int argc, char *argv[]) break; case 'V': terse_version = atoi(optarg); - if (terse_version != 3) { + if (!(terse_version == 2 || terse_version == 3)) { log_err("fio: bad terse version format\n"); exit_val = 1; do_exit++; diff --git a/os/windows/install.wxs b/os/windows/install.wxs index 914d744..2c87d47 100755 --- a/os/windows/install.wxs +++ b/os/windows/install.wxs @@ -3,7 +3,7 @@ <?define VersionMajor = 1?> <?define VersionMinor = 99?> -<?define VersionBuild = 7?> +<?define VersionBuild = 8?> <Product Id="*" Codepage="1252" Language="1033" diff --git a/os/windows/version.h b/os/windows/version.h index 5d7c1f1..db181a1 100644 --- a/os/windows/version.h +++ b/os/windows/version.h @@ -3,4 +3,4 @@ #define FIO_VERSION_MAJOR FIO_MAJOR #define FIO_VERSION_MINOR FIO_MINOR #define FIO_VERSION_BUILD FIO_PATCH -#define FIO_VERSION_STRING "1.99.7" +#define FIO_VERSION_STRING "1.99.8" diff --git a/server.c b/server.c index 7c4804a..4da8bf0 100644 --- a/server.c +++ b/server.c @@ -332,6 +332,8 @@ static int fio_server_send_quit_cmd(void) static int handle_job_cmd(struct fio_net_cmd *cmd) { char *buf = (char *) cmd->payload; + struct cmd_start_pdu spdu; + struct cmd_end_pdu epdu; int ret; if (parse_jobs_ini(buf, 1, 0)) { @@ -339,9 +341,14 @@ static int handle_job_cmd(struct fio_net_cmd *cmd) return -1; } - fio_net_send_simple_cmd(server_fd, FIO_NET_CMD_START, 0, NULL); + spdu.jobs = cpu_to_le32(thread_number); + fio_net_send_cmd(server_fd, FIO_NET_CMD_START, &spdu, sizeof(spdu), 0); ret = exec_run(); + + epdu.error = ret; + fio_net_send_cmd(server_fd, FIO_NET_CMD_STOP, &epdu, sizeof(epdu), 0); + fio_server_send_quit_cmd(); reset_fio_state(); return ret; diff --git a/server.h b/server.h index da520e3..99689d4 100644 --- a/server.h +++ b/server.h @@ -95,6 +95,14 @@ struct cmd_line_pdu { struct cmd_single_line_pdu options[0]; }; +struct cmd_start_pdu { + uint32_t jobs; +}; + +struct cmd_end_pdu { + uint32_t error; +}; + extern int fio_start_server(char *); extern int fio_server_text_output(const char *, size_t); extern int fio_server_log(const char *format, ...); diff --git a/stat.c b/stat.c index 19b3696..d54ed2c 100644 --- a/stat.c +++ b/stat.c @@ -660,10 +660,68 @@ static void show_ddir_status_terse(struct thread_stat *ts, log_info(";%lu;%lu;%f%%;%f;%f", 0UL, 0UL, 0.0, 0.0, 0.0); } +static void show_thread_status_terse_v2(struct thread_stat *ts, + struct group_run_stats *rs) +{ + double io_u_dist[FIO_IO_U_MAP_NR]; + double io_u_lat_u[FIO_IO_U_LAT_U_NR]; + double io_u_lat_m[FIO_IO_U_LAT_M_NR]; + double usr_cpu, sys_cpu; + int i; + + /* General Info */ + log_info("2;%s;%d;%d", ts->name, ts->groupid, ts->error); + /* Log Read Status */ + show_ddir_status_terse(ts, rs, 0); + /* Log Write Status */ + show_ddir_status_terse(ts, rs, 1); + + /* CPU Usage */ + if (ts->total_run_time) { + double runt = (double) ts->total_run_time; + + usr_cpu = (double) ts->usr_time * 100 / runt; + sys_cpu = (double) ts->sys_time * 100 / runt; + } else { + usr_cpu = 0; + sys_cpu = 0; + } + + log_info(";%f%%;%f%%;%lu;%lu;%lu", usr_cpu, sys_cpu, ts->ctx, ts->majf, + ts->minf); + + /* Calc % distribution of IO depths, usecond, msecond latency */ + stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist); + stat_calc_lat_u(ts, io_u_lat_u); + stat_calc_lat_m(ts, io_u_lat_m); + + /* Only show fixed 7 I/O depth levels*/ + log_info(";%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%", + io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3], + io_u_dist[4], io_u_dist[5], io_u_dist[6]); + + /* Microsecond latency */ + for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) + log_info(";%3.2f%%", io_u_lat_u[i]); + /* Millisecond latency */ + for (i = 0; i < FIO_IO_U_LAT_M_NR; i++) + log_info(";%3.2f%%", io_u_lat_m[i]); + /* Additional output if continue_on_error set - default off*/ + if (ts->continue_on_error) + log_info(";%lu;%d", ts->total_err_count, ts->first_error); + log_info("\n"); + + /* Additional output if description is set */ + if (ts->description) + log_info(";%s", ts->description); + + log_info("\n"); +} + #define FIO_TERSE_VERSION "3" -static void show_thread_status_terse(struct thread_stat *ts, - struct group_run_stats *rs) +static void show_thread_status_terse_v3(struct thread_stat *ts, + struct group_run_stats *rs) { double io_u_dist[FIO_IO_U_MAP_NR]; double io_u_lat_u[FIO_IO_U_LAT_U_NR]; @@ -723,6 +781,17 @@ static void show_thread_status_terse(struct thread_stat *ts, log_info(";%s", ts->description); } +static void show_thread_status_terse(struct thread_stat *ts, + struct group_run_stats *rs) +{ + if (terse_version == 2) + show_thread_status_terse_v2(ts, rs); + else if (terse_version == 3) + show_thread_status_terse_v3(ts, rs); + else + log_err("fio: bad terse version!? %d\n", terse_version); +} + static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr) { double mean, S; -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html