iowatcher: Handle traces to more than once device at a time
[blktrace.git] / iowatcher / mpstat.c
CommitLineData
fd70186d
CM
1/*
2 * Copyright (C) 2012 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "mpstat.h"
37
38char line[1024];
39int line_len = 1024;
40
2203e914
CM
41static char record_header[] = "CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle\n";
42static char record_header_v2[] = "CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle\n";
43
44int record_header_len = sizeof(record_header);
45int record_header_v2_len = sizeof(record_header_v2);
fd70186d
CM
46
47static int past_eof(struct trace *trace, char *cur)
48{
49 if (cur >= trace->mpstat_start + trace->mpstat_len)
50 return 1;
51 return 0;
52}
53
54int next_mpstat_line(struct trace *trace)
55{
56 char *next;
57 char *cur = trace->mpstat_cur;
58
59 next = strchr(cur, '\n');
60 if (!next)
61 return 1;
62 next++;
63 if (past_eof(trace, next))
64 return 1;
65 trace->mpstat_cur = next;
66 return 0;
67}
68
69char *next_mpstat(struct trace *trace)
70{
71 char *cur = trace->mpstat_cur;
72
2203e914
CM
73 cur = strstr(trace->mpstat_cur, record_header);
74 if (cur) {
75 cur += record_header_len;
76 } else {
77 cur = strstr(trace->mpstat_cur, record_header_v2);
78 if (cur)
79 cur += record_header_v2_len;
80 }
fd70186d
CM
81 if (!cur)
82 return NULL;
83
fd70186d
CM
84 if (past_eof(trace, cur))
85 return NULL;
86 trace->mpstat_cur = cur;
87 return cur;
88}
89
90char *first_mpstat(struct trace *trace)
91{
92 char *cur = trace->mpstat_cur;
93
94 trace->mpstat_cur = trace->mpstat_start;
95
96 cur = next_mpstat(trace);
97 if (!cur)
98 return NULL;
99 return cur;
100}
101
102static void find_last_mpstat_time(struct trace *trace)
103{
104 int num_mpstats = 0;
105 char *cur;
106
107 first_mpstat(trace);
108
109 cur = first_mpstat(trace);
110 while (cur) {
111 num_mpstats++;
112 cur = next_mpstat(trace);
113 }
114 first_mpstat(trace);
115 trace->mpstat_seconds = num_mpstats;
116}
117
118static int count_mpstat_cpus(struct trace *trace)
119{
120 char *cur = trace->mpstat_start;
121 char *cpu;
122 char *record;
2203e914 123 int len; char *line;
fd70186d
CM
124
125 first_mpstat(trace);
126
127 cpu = strstr(cur, " CPU)");
128 if (!cpu)
129 return 0;
130 line = strndup(cur, cpu - cur);
131
132 record = strrchr(line, '(');
133 if (!record) {
134 free(line);
135 return 0;
136 }
137 record++;
138
139 len = line + strlen(line) - record;
140
141 cur = strndup(record, len);
142 trace->mpstat_num_cpus = atoi(cur);
143 first_mpstat(trace);
144 free(line);
2203e914 145
fd70186d
CM
146 return trace->mpstat_num_cpus;
147}
148
149static char *guess_filename(char *trace_name)
150{
151 struct stat st;
152 int ret;
153 char *cur;
154 char *tmp;
155
156 snprintf(line, line_len, "%s.mpstat", trace_name);
157 ret = stat(line, &st);
158 if (ret == 0)
159 return trace_name;
160
161 cur = strrchr(trace_name, '.');
162 if (!cur) {
163 return trace_name;
164 }
165
166 tmp = strndup(trace_name, cur - trace_name);
167 snprintf(line, line_len, "%s.mpstat", tmp);
168 ret = stat(line, &st);
169 if (ret == 0)
170 return tmp;
171
172 free(tmp);
173 return trace_name;
174}
175
176int read_mpstat(struct trace *trace, char *trace_name)
177{
178 int fd;
179 struct stat st;
180 int ret;
181 char *p;
182
183 if (record_header_len == 0) {
184 record_header_len = strlen(record_header);
185 }
186
187 snprintf(line, line_len, "%s.mpstat", guess_filename(trace_name));
fd70186d
CM
188 fd = open(line, O_RDONLY);
189 if (fd < 0)
190 return 0;
191
192 ret = fstat(fd, &st);
193 if (ret < 0) {
194 fprintf(stderr, "stat failed on %s err %s\n", line, strerror(errno));
195 goto fail_fd;
196 }
197 p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
198 if (p == MAP_FAILED) {
199 fprintf(stderr, "Unable to mmap trace file %s, err %s\n", line, strerror(errno));
200 goto fail_fd;
201 }
fd70186d
CM
202 trace->mpstat_start = p;
203 trace->mpstat_len = st.st_size;
204 trace->mpstat_cur = p;
205 trace->mpstat_fd = fd;
206 find_last_mpstat_time(trace);
207 count_mpstat_cpus(trace);
208
209 first_mpstat(trace);
210
211 return 0;
212
213fail_fd:
214 close(fd);
215 return 0;
216}
217
218/*
219 * 09:56:26 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
220 *
2203e914
CM
221 * or
222 *
223 * 10:18:51 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
224 *
225 *
fd70186d
CM
226 * this reads just one line in the mpstat
227 */
228int read_mpstat_event(struct trace *trace, double *user,
229 double *sys, double *iowait, double *irq,
230 double *soft)
231{
232 char *cur = trace->mpstat_cur;
233 char *nptr;
234 double val;
235
236 /* jump past the date and CPU number */
237 cur += 16;
238 if (past_eof(trace, cur))
239 return 1;
240
241 /* usr time */
242 val = strtod(cur, &nptr);
243 if (val == 0 && cur == nptr)
244 return 1;
245 *user = val;
246
247 /* nice time, pitch this one */
248 cur = nptr;
249 val = strtod(cur, &nptr);
250 if (val == 0 && cur == nptr)
251 return 1;
252
253 /* system time */
254 cur = nptr;
255 val = strtod(cur, &nptr);
256 if (val == 0 && cur == nptr)
257 return 1;
258 *sys = val;
259
260 cur = nptr;
261 val = strtod(cur, &nptr);
262 if (val == 0 && cur == nptr)
263 return 1;
264 *iowait = val;
265
266 cur = nptr;
267 val = strtod(cur, &nptr);
268 if (val == 0 && cur == nptr)
269 return 1;
270 *irq = val;
271
272 cur = nptr;
273 val = strtod(cur, &nptr);
274 if (val == 0 && cur == nptr)
275 return 1;
276 *soft = val;
277
278 return 0;
279}
280
281int add_mpstat_gld(int time, double sys, struct graph_line_data *gld)
282{
283 gld->data[time].sum = sys;
284 gld->data[time].count = 1;
285 return 0;
286
287}