diff options
Diffstat (limited to 'iowatcher/tracers.c')
-rw-r--r-- | iowatcher/tracers.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/iowatcher/tracers.c b/iowatcher/tracers.c new file mode 100644 index 0000000..4c3d10d --- /dev/null +++ b/iowatcher/tracers.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2012 Fusion-io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Parts of this file were imported from Jens Axboe's blktrace sources (also GPL) + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <inttypes.h> +#include <string.h> +#include <asm/types.h> +#include <errno.h> +#include <sys/mman.h> +#include <time.h> +#include <signal.h> +#include <sys/wait.h> +#include <spawn.h> + +#include "plot.h" +#include "blkparse.h" +#include "list.h" +#include "tracers.h" + +extern char **environ; + +static pid_t blktrace_pid = 0; +static pid_t mpstat_pid = 0; + +static void sig_handler_for_quit(int val) +{ + fprintf(stderr, "Received signal %d. Terminating tracers.\n", val); + wait_for_tracers(SIGTERM); +} + +int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest) +{ + int ret; + int i; + char *argv[15 + MAX_DEVICES_PER_TRACE * 2]; + int argc = 0; + + if (!trace_name) + trace_name = "trace"; + if (!dest) + dest = "."; + + argv[argc++] = "blktrace"; + argv[argc++] = "-b"; + argv[argc++] = "8192"; + argv[argc++] = "-a"; + argv[argc++] = "queue"; + argv[argc++] = "-a"; + argv[argc++] = "complete"; + argv[argc++] = "-a"; + argv[argc++] = "issue"; + argv[argc++] = "-a"; + argv[argc++] = "notify"; + + if (num_devices == 1) { + argv[argc++] = "-o"; + argv[argc++] = trace_name; + } else { + /* Multiple devices output to a directory named trace_name */ + dest = trace_name; + } + argv[argc++] = "-D"; + argv[argc++] = dest; + + for (i = 0; i < num_devices; i++) { + argv[argc++] = "-d"; + argv[argc++] = devices[i]; + } + argv[argc] = NULL; + signal(SIGTERM, sig_handler_for_quit); + signal(SIGINT, sig_handler_for_quit); + ret = run_program(argc, argv, 0, &blktrace_pid, NULL); + return ret; +} + +int wait_program(pid_t pid, const char *pname, int sig) +{ + int status; + int ret = 0; + + if (sig) { + ret = kill(pid, sig); + if (ret) { + fprintf(stderr, "Failed to send signal %d to %s (%lu): %s\n", + sig, pname, (long)pid, strerror(errno)); + return ret; + } + fprintf(stderr, "Kill (%d): %s (%ld)\n", sig, pname, (long)pid); + } + + waitpid(pid, &status, 0); + if (WIFEXITED(status)) { + ret = WEXITSTATUS(status); + if (ret == 127) /* spawnp failed after forking */ + fprintf(stderr, "Failed to run '%s'\n", pname); + else + fprintf(stderr, "Exit (%d): %s\n", ret, pname); + } else if (WIFSIGNALED(status) && sig && WTERMSIG(status) != sig) { + fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status)); + ret = -1; + } + return ret; +} + +int run_program(int argc, char **argv, int wait, pid_t *pid, char *outpath) +{ + int i; + int err; + pid_t _pid; + posix_spawn_file_actions_t facts; + posix_spawn_file_actions_t *factp = NULL; + + if (outpath != NULL) { + posix_spawn_file_actions_init(&facts); + posix_spawn_file_actions_addopen(&facts, 1, outpath, O_WRONLY|O_CREAT|O_TRUNC, 0600); + factp = &facts; + } + + fprintf(stderr, "Start"); + for (i = 0; i < argc; i++) + fprintf(stderr, " %s", argv[i]); + fprintf(stderr, "\n"); + + err = posix_spawnp(&_pid, argv[0], factp, NULL, argv, environ); + if (err != 0) { + fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err)); + } else if (wait) { + err = wait_program(_pid, argv[0], 0); + } else if (!pid) { + fprintf(stderr, "Warning: %s (%ld): Not saving pid and not waiting for it.\n", + argv[0], (long)_pid); + } else { + *pid = _pid; + } + return err; +} + +int wait_for_tracers(int sig) +{ + int err; + if (blktrace_pid != 0) { + err = wait_program(blktrace_pid, "blktrace", sig); + if (err) + exit(1); + blktrace_pid = 0; + } + if (mpstat_pid != 0) { + err = wait_program(mpstat_pid, "mpstat", sig); + if (err) + exit(1); + mpstat_pid = 0; + } + return 0; +} + +int start_mpstat(char *path) +{ + int ret; + int argc = 4; + char *argv[] = { + "mpstat", + "-P", "ALL", "1", + NULL, + }; + + ret = run_program(argc, argv, 0, &mpstat_pid, path); + return ret; +} |