iowatcher: Make seconds unsigned
[blktrace.git] / iowatcher / fio.c
1 /*
2  * Copyright (C) 2013 Fusion-io
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU General Public
6  *  License v2 as published by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16  */
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <inttypes.h>
25 #include <string.h>
26 #include <asm/types.h>
27 #include <errno.h>
28 #include <sys/mman.h>
29 #include <time.h>
30 #include <math.h>
31
32 #include "plot.h"
33 #include "blkparse.h"
34 #include "list.h"
35 #include "tracers.h"
36 #include "fio.h"
37
38 static int past_eof(struct trace *trace, char *cur)
39 {
40         if (cur >= trace->fio_start + trace->fio_len)
41                 return 1;
42         return 0;
43 }
44
45 static int parse_fio_line(struct trace *trace, int *time, int *rate, int *dir, int *bs)
46 {
47         char *cur = trace->fio_cur;
48         char *p;
49         int *res[] = { time, rate, dir, bs, NULL };
50         int val;
51         int i = 0;
52         int *t;
53         char *end = index(cur, '\n');
54         char *tmp;
55
56         if (!end)
57                 return 1;
58
59         tmp = strndup(cur, end - cur);
60         if (!tmp)
61                 return 1;
62         p = strtok(tmp, ",");
63         while (p && *res) {
64                 val = atoi(p);
65                 t = res[i++];
66                 *t = val;
67                 p = strtok(NULL, ",");
68         }
69
70         free(tmp);
71
72         if (i < 3)
73                 return 1;
74         return 0;
75 }
76
77 int next_fio_line(struct trace *trace)
78 {
79         char *next;
80         char *cur = trace->fio_cur;
81
82         next = strchr(cur, '\n');
83         if (!next)
84                 return 1;
85         next++;
86         if (past_eof(trace, next))
87                 return 1;
88         trace->fio_cur = next;
89         return 0;
90 }
91
92 char *first_fio(struct trace *trace)
93 {
94         trace->fio_cur = trace->fio_start;
95         return trace->fio_cur;
96 }
97
98 static void find_last_fio_time(struct trace *trace)
99 {
100         double d;
101         int time, rate, dir, bs;
102         int ret;
103         int last_time = 0;
104
105         if (trace->fio_len == 0)
106                 return;
107
108         first_fio(trace);
109         while (1) {
110                 ret = parse_fio_line(trace, &time, &rate, &dir, &bs);
111                 if (ret)
112                         break;
113                 if (dir <= 1 && time > last_time)
114                         last_time = time;
115                 ret = next_fio_line(trace);
116                 if (ret)
117                         break;
118         }
119         d = (double)time / 1000;
120         trace->fio_seconds = ceil(d);
121         return;
122 }
123
124 int read_fio(struct trace *trace, char *trace_name)
125 {
126         int fd;
127         struct stat st;
128         int ret;
129         char *p;
130
131         fd = open(trace_name, O_RDONLY);
132         if (fd < 0)
133                 return 1;
134
135         ret = fstat(fd, &st);
136         if (ret < 0) {
137                 fprintf(stderr, "stat failed on %s err %s\n",
138                         trace_name, strerror(errno));
139                 goto fail_fd;
140         }
141         p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
142         if (p == MAP_FAILED) {
143                 fprintf(stderr, "Unable to mmap trace file %s, err %s\n",
144                         trace_name, strerror(errno));
145                 goto fail_fd;
146         }
147         trace->fio_start = p;
148         trace->fio_len = st.st_size;
149         trace->fio_cur = p;
150         trace->fio_fd = fd;
151         find_last_fio_time(trace);
152         first_fio(trace);
153         return 0;
154
155 fail_fd:
156         close(fd);
157         return 1;
158 }
159
160 struct trace *open_fio_trace(char *path)
161 {
162         int ret;
163         struct trace *trace;
164
165         trace = calloc(1, sizeof(*trace));
166         if (!trace) {
167                 fprintf(stderr, "unable to allocate memory for trace\n");
168                 exit(1);
169         }
170
171         ret = read_fio(trace, path);
172         if (ret) {
173                 free(trace);
174                 return NULL;
175         }
176
177         return trace;
178 }
179
180 int read_fio_event(struct trace *trace, int *time_ret, u64 *bw_ret, int *dir_ret)
181 {
182         char *cur = trace->fio_cur;
183         int time, rate, dir, bs;
184         int ret;
185
186         if (past_eof(trace, cur))
187                 return 1;
188
189         ret = parse_fio_line(trace, &time, &rate, &dir, &bs);
190         if (ret)
191                 return 1;
192
193         time = floor((double)time / 1000);
194         *time_ret = time;
195         *bw_ret = (u64)rate * 1024;
196
197         *dir_ret = dir;
198         return 0;
199 }
200
201 int add_fio_gld(unsigned int time, u64 bw, struct graph_line_data *gld)
202 {
203         double val;
204
205         if (time > gld->max_seconds)
206                 return 0;
207
208         gld->data[time].sum += bw;
209         gld->data[time].count++;
210
211         val = ((double)gld->data[time].sum) / gld->data[time].count;
212
213         if (val > gld->max)
214                 gld->max = ceil(val);
215         return 0;
216
217 }