diff options
author | Chris Mason <chris.mason@fusionio.com> | 2012-08-20 14:36:19 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-08-20 14:41:15 -0400 |
commit | 7da341fe2273232c51193d5f2fd9204bbbe13b5d (patch) | |
tree | 08f7f6dec4265ce5e98e8ef292a35316b756365d | |
parent | 4b9e525d6b2d5cbeb3141b2a80668537063c6ad7 (diff) | |
download | iowatcher-7da341fe2273232c51193d5f2fd9204bbbe13b5d.tar.gz |
Add mpstat.[ch] into git
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r-- | mpstat.c | 275 | ||||
-rw-r--r-- | mpstat.h | 28 |
2 files changed, 303 insertions, 0 deletions
diff --git a/mpstat.c b/mpstat.c new file mode 100644 index 0000000..f2292b9 --- /dev/null +++ b/mpstat.c @@ -0,0 +1,275 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#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 <math.h> + +#include "plot.h" +#include "blkparse.h" +#include "list.h" +#include "tracers.h" +#include "mpstat.h" + +char line[1024]; +int line_len = 1024; + +char *record_header = "CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle\n"; +int record_header_len = 0; + +static int past_eof(struct trace *trace, char *cur) +{ + if (cur >= trace->mpstat_start + trace->mpstat_len) + return 1; + return 0; +} + +int next_mpstat_line(struct trace *trace) +{ + char *next; + char *cur = trace->mpstat_cur; + + next = strchr(cur, '\n'); + if (!next) + return 1; + next++; + if (past_eof(trace, next)) + return 1; + trace->mpstat_cur = next; + return 0; +} + +char *next_mpstat(struct trace *trace) +{ + char *cur = trace->mpstat_cur; + + cur = strstr(cur, record_header); + if (!cur) + return NULL; + + cur += record_header_len; + if (past_eof(trace, cur)) + return NULL; + trace->mpstat_cur = cur; + return cur; +} + +char *first_mpstat(struct trace *trace) +{ + char *cur = trace->mpstat_cur; + + trace->mpstat_cur = trace->mpstat_start; + + cur = next_mpstat(trace); + if (!cur) + return NULL; + return cur; +} + +static void find_last_mpstat_time(struct trace *trace) +{ + int num_mpstats = 0; + char *cur; + + first_mpstat(trace); + + cur = first_mpstat(trace); + while (cur) { + num_mpstats++; + cur = next_mpstat(trace); + } + first_mpstat(trace); + trace->mpstat_seconds = num_mpstats; +} + +static int count_mpstat_cpus(struct trace *trace) +{ + char *cur = trace->mpstat_start; + char *cpu; + char *record; + int len; + char *line; + + first_mpstat(trace); + + cpu = strstr(cur, " CPU)"); + if (!cpu) + return 0; + line = strndup(cur, cpu - cur); + + record = strrchr(line, '('); + if (!record) { + free(line); + return 0; + } + record++; + + len = line + strlen(line) - record; + + cur = strndup(record, len); + trace->mpstat_num_cpus = atoi(cur); + first_mpstat(trace); + free(line); + return trace->mpstat_num_cpus; +} + +static char *guess_filename(char *trace_name) +{ + struct stat st; + int ret; + char *cur; + char *tmp; + + snprintf(line, line_len, "%s.mpstat", trace_name); + ret = stat(line, &st); + if (ret == 0) + return trace_name; + + cur = strrchr(trace_name, '.'); + if (!cur) { + return trace_name; + } + + tmp = strndup(trace_name, cur - trace_name); + snprintf(line, line_len, "%s.mpstat", tmp); + ret = stat(line, &st); + if (ret == 0) + return tmp; + + free(tmp); + return trace_name; +} + +int read_mpstat(struct trace *trace, char *trace_name) +{ + int fd; + struct stat st; + int ret; + char *p; + + if (record_header_len == 0) { + record_header_len = strlen(record_header); + } + + snprintf(line, line_len, "%s.mpstat", guess_filename(trace_name)); + + fd = open(line, O_RDONLY); + if (fd < 0) + return 0; + + ret = fstat(fd, &st); + if (ret < 0) { + fprintf(stderr, "stat failed on %s err %s\n", line, strerror(errno)); + goto fail_fd; + } + p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (p == MAP_FAILED) { + fprintf(stderr, "Unable to mmap trace file %s, err %s\n", line, strerror(errno)); + goto fail_fd; + } + + trace->mpstat_start = p; + trace->mpstat_len = st.st_size; + trace->mpstat_cur = p; + trace->mpstat_fd = fd; + find_last_mpstat_time(trace); + count_mpstat_cpus(trace); + + first_mpstat(trace); + + return 0; + +fail_fd: + close(fd); + return 0; +} + +/* + * 09:56:26 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle + * + * this reads just one line in the mpstat + */ +int read_mpstat_event(struct trace *trace, double *user, + double *sys, double *iowait, double *irq, + double *soft) +{ + char *cur = trace->mpstat_cur; + char *nptr; + double val; + + /* jump past the date and CPU number */ + cur += 16; + if (past_eof(trace, cur)) + return 1; + + /* usr time */ + val = strtod(cur, &nptr); + if (val == 0 && cur == nptr) + return 1; + *user = val; + + /* nice time, pitch this one */ + cur = nptr; + val = strtod(cur, &nptr); + if (val == 0 && cur == nptr) + return 1; + + /* system time */ + cur = nptr; + val = strtod(cur, &nptr); + if (val == 0 && cur == nptr) + return 1; + *sys = val; + + cur = nptr; + val = strtod(cur, &nptr); + if (val == 0 && cur == nptr) + return 1; + *iowait = val; + + cur = nptr; + val = strtod(cur, &nptr); + if (val == 0 && cur == nptr) + return 1; + *irq = val; + + cur = nptr; + val = strtod(cur, &nptr); + if (val == 0 && cur == nptr) + return 1; + *soft = val; + + return 0; +} + +int add_mpstat_gld(int time, double sys, struct graph_line_data *gld) +{ + gld->data[time].sum = sys; + gld->data[time].count = 1; + return 0; + +} diff --git a/mpstat.h b/mpstat.h new file mode 100644 index 0000000..cf72351 --- /dev/null +++ b/mpstat.h @@ -0,0 +1,28 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __MPSTAT__ +#define __MPSTAT__ + +int read_mpstat(struct trace *trace, char *trace_name); +char *next_mpstat(struct trace *trace); +char *first_mpstat(struct trace *trace); +int read_mpstat_event(struct trace *trace, double *user, + double *sys, double *iowait, double *irq, + double *soft); +int next_mpstat_line(struct trace *trace); +int add_mpstat_gld(int time, double sys, struct graph_line_data *gld); +#endif |