• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 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 "mpstat.h"
37 
38 char line[1024];
39 int line_len = 1024;
40 
41 static char record_header[] = "CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle\n";
42 static char record_header_v2[] = "CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle\n";
43 
44 int record_header_len = sizeof(record_header);
45 int record_header_v2_len = sizeof(record_header_v2);
46 
past_eof(struct trace * trace,char * cur)47 static 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 
next_mpstat_line(struct trace * trace)54 int 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 
next_mpstat(struct trace * trace)69 char *next_mpstat(struct trace *trace)
70 {
71 	char *cur;
72 
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 	}
81 	if (!cur)
82 		return NULL;
83 
84 	if (past_eof(trace, cur))
85 		return NULL;
86 	trace->mpstat_cur = cur;
87 	return cur;
88 }
89 
first_mpstat(struct trace * trace)90 char *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 
find_last_mpstat_time(struct trace * trace)102 static 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 
guess_mpstat_cpus(struct trace * trace)118 static int guess_mpstat_cpus(struct trace *trace)
119 {
120 	char *cur;
121 	int ret;
122 	int count = 0;
123 
124 	cur = first_mpstat(trace);
125 	if (!cur)
126 		return 0;
127 
128 	while (1) {
129 		ret = next_mpstat_line(trace);
130 		if (ret)
131 			break;
132 
133 		cur = trace->mpstat_cur;
134 		count++;
135 
136 		if (!cur)
137 			break;
138 
139 		if (cur[0] == '\n')
140 			break;
141 	}
142 	trace->mpstat_num_cpus = count - 1;
143 	return 0;
144 }
145 
count_mpstat_cpus(struct trace * trace)146 static int count_mpstat_cpus(struct trace *trace)
147 {
148 	char *cur = trace->mpstat_start;
149 	char *cpu;
150 	char *record;
151 	int len; char *line;
152 
153 	first_mpstat(trace);
154 	cpu = strstr(cur, " CPU)");
155 	if (!cpu)
156 		return guess_mpstat_cpus(trace);
157 
158 	line = strndup(cur, cpu - cur);
159 
160 	record = strrchr(line, '(');
161 	if (!record) {
162 		free(line);
163 		return 0;
164 	}
165 	record++;
166 
167 	len = line + strlen(line) - record;
168 
169 	cur = strndup(record, len);
170 	trace->mpstat_num_cpus = atoi(cur);
171 	first_mpstat(trace);
172 	free(line);
173 
174 	return trace->mpstat_num_cpus;
175 }
176 
guess_filename(char * trace_name)177 static char *guess_filename(char *trace_name)
178 {
179 	struct stat st;
180 	int ret;
181 	char *cur;
182 	char *tmp;
183 
184 	snprintf(line, line_len, "%s.mpstat", trace_name);
185 	ret = stat(line, &st);
186 	if (ret == 0)
187 		return trace_name;
188 
189 	cur = strrchr(trace_name, '.');
190 	if (!cur) {
191 		return trace_name;
192 	}
193 
194 	tmp = strndup(trace_name, cur - trace_name);
195 	snprintf(line, line_len, "%s.mpstat", tmp);
196 	ret = stat(line, &st);
197 	if (ret == 0)
198 		return tmp;
199 
200 	free(tmp);
201 	return trace_name;
202 }
203 
read_mpstat(struct trace * trace,char * trace_name)204 int read_mpstat(struct trace *trace, char *trace_name)
205 {
206 	int fd;
207 	struct stat st;
208 	int ret;
209 	char *p;
210 
211 	if (record_header_len == 0) {
212 		record_header_len = strlen(record_header);
213 	}
214 
215 	snprintf(line, line_len, "%s.mpstat", guess_filename(trace_name));
216 	fd = open(line, O_RDONLY);
217 	if (fd < 0)
218 		return 0;
219 
220 	ret = fstat(fd, &st);
221 	if (ret < 0) {
222 		fprintf(stderr, "stat failed on %s err %s\n", line, strerror(errno));
223 		goto fail_fd;
224 	}
225 	p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
226 	if (p == MAP_FAILED) {
227 		fprintf(stderr, "Unable to mmap trace file %s, err %s\n", line, strerror(errno));
228 		goto fail_fd;
229 	}
230 	trace->mpstat_start = p;
231 	trace->mpstat_len = st.st_size;
232 	trace->mpstat_cur = p;
233 	trace->mpstat_fd = fd;
234 	find_last_mpstat_time(trace);
235 	count_mpstat_cpus(trace);
236 
237 	first_mpstat(trace);
238 
239 	return 0;
240 
241 fail_fd:
242 	close(fd);
243 	return 0;
244 }
245 
246 /*
247  * 09:56:26 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
248  *
249  * or
250  *
251  * 10:18:51 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
252  *
253  *
254  * this reads just one line in the mpstat
255  */
read_mpstat_event(struct trace * trace,double * user,double * sys,double * iowait,double * irq,double * soft)256 int read_mpstat_event(struct trace *trace, double *user,
257 		      double *sys, double *iowait, double *irq,
258 		      double *soft)
259 {
260 	char *cur = trace->mpstat_cur;
261 	char *nptr;
262 	double val;
263 
264 	/* jump past the date and CPU number */
265 	cur += 16;
266 	if (past_eof(trace, cur))
267 		return 1;
268 
269 	/* usr time */
270 	val = strtod(cur, &nptr);
271 	if (val == 0 && cur == nptr)
272 		return 1;
273 	*user = val;
274 
275 	/* nice time, pitch this one */
276 	cur = nptr;
277 	val = strtod(cur, &nptr);
278 	if (val == 0 && cur == nptr)
279 		return 1;
280 
281 	/* system time */
282 	cur = nptr;
283 	val = strtod(cur, &nptr);
284 	if (val == 0 && cur == nptr)
285 		return 1;
286 	*sys = val;
287 
288 	cur = nptr;
289 	val = strtod(cur, &nptr);
290 	if (val == 0 && cur == nptr)
291 		return 1;
292 	*iowait = val;
293 
294 	cur = nptr;
295 	val = strtod(cur, &nptr);
296 	if (val == 0 && cur == nptr)
297 		return 1;
298 	*irq = val;
299 
300 	cur = nptr;
301 	val = strtod(cur, &nptr);
302 	if (val == 0 && cur == nptr)
303 		return 1;
304 	*soft = val;
305 
306 	return 0;
307 }
308 
add_mpstat_gld(int time,double sys,struct graph_line_data * gld)309 int add_mpstat_gld(int time, double sys, struct graph_line_data *gld)
310 {
311 	gld->data[time].sum = sys;
312 	gld->data[time].count = 1;
313 	return 0;
314 
315 }
316