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
past_eof(struct trace * trace,char * cur)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
parse_fio_line(struct trace * trace,int * time,int * rate,int * dir,int * bs)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
next_fio_line(struct trace * trace)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
first_fio(struct trace * trace)92 char *first_fio(struct trace *trace)
93 {
94 trace->fio_cur = trace->fio_start;
95 return trace->fio_cur;
96 }
97
find_last_fio_time(struct trace * trace)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
read_fio(struct trace * trace,char * trace_name)124 static 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
open_fio_trace(char * path)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
read_fio_event(struct trace * trace,int * time_ret,u64 * bw_ret,int * dir_ret)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
add_fio_gld(unsigned int time,u64 bw,struct graph_line_data * gld)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 }
218