argv[i++] = tl->name;
}
- err = run_program2(argc, argv, 0, NULL);
+ err = run_program(argc, argv, 1, NULL);
+ if (err)
+ fprintf(stderr, "%s exited with %d, expected 0\n", argv[0], err);
free(argv);
return err;
}
.SH SYNOPSIS
.B iowatcher
-\fIOPTIONS...\fR
+\fI[options]\fR [--] \fI[program arguments ...]\fR
.SH DESCRIPTION
iowatcher graphs the results of a blktrace run. It can graph the result of an existing blktrace, start a new blktrace, or start a new blktrace and a benchmark run. It can then create an image or movie of the IO from a given trace. iowatcher can produce either SVG files or movies in mp4 format (with ffmpeg) or ogg format (with png2theora).
\fB-D, --blktrace-destination\fP <destination>
Destination for blktrace.
.TP
-\fB-p, --prog\fP <program>
-Program to run while blktrace is run.
+\fB-p, --prog\fP
+Run a program while blktrace is run. The program and its arguments must be
+specified after all other options. Note that this option previously required
+the program to be given as a single argument but it now flags that iowatcher
+should expect extra arguments to be run during the trace.
+.TP
+\fB--\fP
+End option parsing. If \fB--prog\fP is specified, everything after \fB--\fP is
+the program to be run. This can be useful if the program name could otherwise
+be mistaken for an option.
.TP
\fB-K, --keep-movie-svgs\fP
Keep the SVG files generated for movie mode.
static int num_blktrace_devices = 0;
static char *blktrace_outfile = "trace";
static char *blktrace_dest_dir = ".";
-static char *program_to_run = NULL;
+static char **prog_argv = NULL;
+static int prog_argc = 0;
static char *ffmpeg_codec = "libx264";
static void alloc_mpstat_gld(struct trace_file *tf)
HELP_LONG_OPT = 1,
};
-char *option_string = "F:T:t:o:l:r:O:N:d:D:p:m::h:w:c:x:y:a:C:PK";
+char *option_string = "+F:T:t:o:l:r:O:N:d:D:pm::h:w:c:x:y:a:C:PK";
static struct option long_options[] = {
{"columns", required_argument, 0, 'c'},
{"fio-trace", required_argument, 0, 'F'},
{"only-graph", required_argument, 0, 'O'},
{"device", required_argument, 0, 'd'},
{"blktrace-destination", required_argument, 0, 'D'},
- {"prog", required_argument, 0, 'p'},
+ {"prog", no_argument, 0, 'p'},
{"movie", optional_argument, 0, 'm'},
{"codec", optional_argument, 0, 'C'},
{"keep-movie-svgs", no_argument, 0, 'K'},
"\t-F (--fio-trace): fio bandwidth trace (more than one allowed)\n"
"\t-l (--label): trace label in the graph\n"
"\t-o (--output): output file name (SVG only)\n"
- "\t-p (--prog): program to run while blktrace is run\n"
+ "\t-p (--prog): run a program while blktrace is run\n"
"\t-K (--keep-movie-svgs keep svgs generated for movie mode\n"
"\t-m (--movie [=spindle|rect]): create IO animations\n"
"\t-C (--codec): ffmpeg codec. Use ffmpeg -codecs to list\n"
{
int c;
int disabled = 0;
+ int p_flagged = 0;
while (1) {
- // int this_option_optind = optind ? optind : 1;
int option_index = 0;
c = getopt_long(ac, av, option_string,
}
break;
case 'p':
- program_to_run = strdup(optarg);
+ p_flagged = 1;
break;
case 'K':
keep_movie_svgs = 1;
break;
}
}
+
+ if (optind < ac && p_flagged) {
+ prog_argv = &av[optind];
+ prog_argc = ac - optind;
+ } else if (p_flagged) {
+ fprintf(stderr, "--prog or -p given but no program specified\n");
+ exit(1);
+ } else if (optind < ac) {
+ fprintf(stderr, "Extra arguments '%s'... (and --prog not specified)\n", av[optind]);
+ exit(1);
+ }
+
return 0;
}
}
start_mpstat(path);
- if (program_to_run) {
- ret = run_program(program_to_run);
- if (ret) {
- fprintf(stderr, "failed to run %s\n",
- program_to_run);
- exit(1);
- }
- wait_for_tracers();
- } else {
- /* no program specified, just wait for
- * blktrace to exit
- */
- wait_for_tracers();
+
+ if (prog_argv && prog_argc) {
+ ret = run_program(prog_argc, prog_argv, 1, NULL);
+ if (ret != 127)
+ printf("%s exited with %d\n", prog_argv[0], ret);
}
+
+ wait_for_tracers();
free(path);
}
return 0;
}
-int run_program(char *str)
-{
- int ret;
-
- fprintf(stderr, "running program %s\n", str);
- ret = system(str);
- if (ret == -1) {
- fprintf(stderr, "failed to run program %s error %s\n", str, strerror(errno));
- stop_all_tracers();
- return -errno;
- }
- stop_all_tracers();
- return 0;
-}
-
-int wait_program(pid_t pid, const char *pname, int expexit)
+int wait_program(pid_t pid, const char *pname)
{
int status;
int ret = 0;
ret = WEXITSTATUS(status);
if (ret == 127) /* spawnp failed after forking */
fprintf(stderr, "Failed to run '%s'\n", pname);
- else if (ret != expexit)
- fprintf(stderr, "'%s' exit status %d, expected %d\n",
- pname, ret, expexit);
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status));
ret = -1;
return ret;
}
-int run_program2(int argc, char **argv, int expexit, pid_t *pid)
+int run_program(int argc, char **argv, int wait, pid_t *pid)
{
int i;
int err;
err = posix_spawnp(&_pid, argv[0], NULL, NULL, argv, environ);
if (err != 0) {
fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err));
- } else if (expexit >= 0) {
- err = wait_program(_pid, argv[0], expexit);
+ } else if (wait) {
+ err = wait_program(_pid, argv[0]);
} else if (!pid) {
fprintf(stderr, "Warning: %s (%ld): Not saving pid and not waiting for it.\n",
argv[0], (long)_pid);
int wait_for_tracers(void)
{
int status = 0;
+ stop_all_tracers();
if (blktrace_pid != 0) {
waitpid(blktrace_pid, &status, WUNTRACED);
blktrace_pid = 0;
*/
#ifndef __IOWATCH_TRACERS
#define __IOWATCH_TRACERS
-int run_program(char *str);
-int run_program2(int argc, char **argv, int expexit, pid_t *pid);
-int wait_program(pid_t pid, const char *pname, int expexit);
+int run_program(int argc, char **argv, int wait, pid_t *pid);
+int wait_program(pid_t pid, const char *pname);
int stop_blktrace(void);
int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest);
int start_mpstat(char *trace_name);