- Improved error handling
[blktrace.git] / blkparse.c
CommitLineData
d0ca268b
JA
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <fcntl.h>
6#include <stdlib.h>
8fc0abbc 7#include <string.h>
d0ca268b 8
8fc0abbc
JA
9#include "blktrace.h"
10#include "rbtree.h"
d0ca268b 11
fd92da24 12#define MAX_CPUS (512)
d0ca268b
JA
13
14struct per_file_info {
15 int cpu;
16 int nelems;
d0ca268b
JA
17
18 int fd;
87b72777 19 char fname[128];
d0ca268b 20
87b72777
JA
21 FILE *ofp;
22 char ofname[128];
8fc0abbc 23
d0ca268b
JA
24 unsigned long long start_time;
25};
26
8fc0abbc
JA
27static struct rb_root rb_root;
28
29struct trace {
30 struct blk_io_trace *bit;
31 struct rb_node rb_node;
32};
33
87b72777
JA
34static struct per_file_info per_file_info[MAX_CPUS];
35static struct per_file_info *cur_file;
d0ca268b
JA
36
37static unsigned long qreads, qwrites, creads, cwrites, mreads, mwrites;
38static unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
87b72777
JA
39static unsigned long long events;
40
41static int max_cpus;
d0ca268b
JA
42
43static inline void account_m(int rw, unsigned int bytes)
44{
45 if (rw) {
46 mwrites++;
47 qwrite_kb += bytes >> 10;
48 } else {
49 mreads++;
50 qread_kb += bytes >> 10;
51 }
52}
53
54static inline void account_q(int rw, unsigned int bytes)
55{
56 if (rw) {
57 qwrites++;
58 qwrite_kb += bytes >> 10;
59 } else {
60 qreads++;
61 qread_kb += bytes >> 10;
62 }
63}
64
65static inline void account_c(int rw, unsigned int bytes)
66{
67 if (rw) {
68 cwrites++;
69 cwrite_kb += bytes >> 10;
70 } else {
71 creads++;
72 cread_kb += bytes >> 10;
73 }
74}
75
3aabcd89 76static void output(char *s)
d0ca268b
JA
77{
78 printf("%s", s);
3aabcd89 79 fprintf(cur_file->ofp,"%s",s);
d0ca268b
JA
80}
81
3aabcd89
JA
82static char hstring[256];
83static char tstring[256];
d0ca268b 84
3aabcd89 85static inline char *setup_header(struct blk_io_trace *t, char act)
d0ca268b
JA
86{
87 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
88 int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
89 int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
90 char rwbs[4];
91 int i = 0;
92
93 if (w)
94 rwbs[i++] = 'W';
95 else
96 rwbs[i++] = 'R';
97 if (b)
98 rwbs[i++] = 'B';
99 if (s)
100 rwbs[i++] = 'S';
101
102 rwbs[i] = '\0';
103
3aabcd89 104 sprintf(hstring, "%3d %15ld %12Lu %5u %c %3s", cur_file->cpu,
d0ca268b
JA
105 (unsigned long)t->sequence, (unsigned long long)t->time, t->pid,
106 act, rwbs);
107
108 return hstring;
109}
110
3aabcd89 111static void log_complete(struct blk_io_trace *t, char act)
d0ca268b
JA
112{
113 sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(t, act),
114 (unsigned long long)t->sector, t->bytes >> 9, t->error);
115 output(tstring);
116}
117
3aabcd89 118static void log_queue(struct blk_io_trace *t, char act)
d0ca268b
JA
119{
120 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
121 (unsigned long long)t->sector, t->bytes >> 9);
122 output(tstring);
123}
124
3aabcd89 125static void log_issue(struct blk_io_trace *t, char act)
d0ca268b
JA
126{
127 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
128 (unsigned long long)t->sector, t->bytes >> 9);
129 output(tstring);
130}
131
3aabcd89 132static void log_merge(struct blk_io_trace *t, char act)
d0ca268b
JA
133{
134 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
135 (unsigned long long)t->sector, t->bytes >> 9);
136 output(tstring);
137}
138
3aabcd89 139static void log_generic(struct blk_io_trace *t, char act)
d0ca268b
JA
140{
141 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
142 (unsigned long long)t->sector, t->bytes >> 9);
143 output(tstring);
144}
145
87b72777 146static int log_pc(struct blk_io_trace *t, char act)
d0ca268b 147{
87b72777
JA
148 unsigned char *buf;
149 int i;
d0ca268b 150
87b72777 151 sprintf(tstring,"%s ", setup_header(t, act));
d0ca268b
JA
152 output(tstring);
153
87b72777 154 buf = (unsigned char *) t + sizeof(*t);
d0ca268b
JA
155 for (i = 0; i < t->pdu_len; i++) {
156 sprintf(tstring,"%02x ", buf[i]);
157 output(tstring);
158 }
159
160 if (act == 'C') {
161 sprintf(tstring,"[%d]", t->error);
162 output(tstring);
163 }
164
165 printf("\n");
87b72777 166 return 0;
d0ca268b
JA
167}
168
87b72777 169static int dump_trace_pc(struct blk_io_trace *t)
d0ca268b 170{
87b72777
JA
171 int ret = 0;
172
d0ca268b
JA
173 switch (t->action & 0xffff) {
174 case __BLK_TA_QUEUE:
175 log_generic(t, 'Q');
176 break;
177 case __BLK_TA_GETRQ:
178 log_generic(t, 'G');
179 break;
180 case __BLK_TA_SLEEPRQ:
181 log_generic(t, 'S');
182 break;
183 case __BLK_TA_REQUEUE:
184 log_generic(t, 'R');
185 break;
186 case __BLK_TA_ISSUE:
87b72777 187 ret = log_pc(t, 'D');
d0ca268b
JA
188 break;
189 case __BLK_TA_COMPLETE:
190 log_pc(t, 'C');
191 break;
192 default:
193 fprintf(stderr, "Bad pc action %x\n", t->action);
87b72777
JA
194 ret = 1;
195 break;
d0ca268b
JA
196 }
197
87b72777 198 return ret;
d0ca268b
JA
199}
200
3aabcd89 201static void dump_trace_fs(struct blk_io_trace *t)
d0ca268b
JA
202{
203 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
204
205 switch (t->action & 0xffff) {
206 case __BLK_TA_QUEUE:
207 account_q(w, t->bytes);
208 log_queue(t, 'Q');
209 break;
210 case __BLK_TA_BACKMERGE:
211 account_m(w, t->bytes);
212 log_merge(t, 'M');
213 break;
214 case __BLK_TA_FRONTMERGE:
215 account_m(w, t->bytes);
216 log_merge(t, 'F');
217 break;
218 case __BLK_TA_GETRQ:
219 log_generic(t, 'G');
220 break;
221 case __BLK_TA_SLEEPRQ:
222 log_generic(t, 'S');
223 break;
224 case __BLK_TA_REQUEUE:
225 log_queue(t, 'R');
226 break;
227 case __BLK_TA_ISSUE:
228 log_issue(t, 'D');
229 break;
230 case __BLK_TA_COMPLETE:
231 account_c(w, t->bytes);
232 log_complete(t, 'C');
233 break;
234 default:
235 fprintf(stderr, "Bad fs action %x\n", t->action);
236 return;
237 }
d0ca268b
JA
238}
239
87b72777 240static int dump_trace(struct blk_io_trace *t)
d0ca268b 241{
87b72777
JA
242 int ret = 0;
243
d0ca268b 244 if (t->action & BLK_TC_ACT(BLK_TC_PC))
87b72777 245 ret = dump_trace_pc(t);
d0ca268b
JA
246 else
247 dump_trace_fs(t);
87b72777
JA
248
249 events++;
250 return ret;
d0ca268b
JA
251}
252
3aabcd89 253static void show_stats(void)
d0ca268b
JA
254{
255 printf("\nReads:");
256 printf("\tQueued: %'8lu, %'8LuKiB\n", qreads, qread_kb);
257 printf("\tCompleted: %'8lu, %'8LuKiB\n", creads, cread_kb);
258 printf("\tMerges: %'8lu\n", mreads);
259
260 printf("Writes:");
261 printf("\tQueued: %'8lu, %'8LuKiB\n", qwrites, qwrite_kb);
262 printf("\tCompleted: %'8lu, %'8LuKiB\n", cwrites, cwrite_kb);
263 printf("\tMerges: %'8lu\n", mwrites);
264
265 printf("Events: %'Lu\n", events);
d0ca268b
JA
266}
267
3aabcd89 268static inline int trace_rb_insert(struct trace *t)
8fc0abbc
JA
269{
270 struct rb_node **p = &rb_root.rb_node;
271 struct rb_node *parent = NULL;
272 struct trace *__t;
273
274 while (*p) {
275 parent = *p;
276 __t = rb_entry(parent, struct trace, rb_node);
277
278 if (t->bit->sequence < __t->bit->sequence)
279 p = &(*p)->rb_left;
280 else if (t->bit->sequence > __t->bit->sequence)
281 p = &(*p)->rb_right;
282 else {
87b72777 283 fprintf(stderr, "sequence alias!\n");
8fc0abbc
JA
284 return 1;
285 }
286 }
287
288 rb_link_node(&t->rb_node, parent, p);
289 rb_insert_color(&t->rb_node, &rb_root);
290 return 0;
291}
292
3aabcd89 293static int sort_entries(void *traces, unsigned long offset)
8fc0abbc
JA
294{
295 struct blk_io_trace *bit;
296 struct trace *t;
297 void *start = traces;
298 int nelems = 0;
299
300 memset(&rb_root, 0, sizeof(rb_root));
301
302 do {
303 bit = traces;
304 t = malloc(sizeof(*t));
305 t->bit = bit;
306 memset(&t->rb_node, 0, sizeof(t->rb_node));
307
308 if (trace_rb_insert(t))
309 return -1;
310
311 traces += sizeof(*bit) + bit->pdu_len;
312 nelems++;
87b72777 313 } while (traces < start + offset + sizeof(*bit));
8fc0abbc
JA
314
315 return nelems;
316}
317
3aabcd89 318static void show_entries(void)
8fc0abbc 319{
8fc0abbc 320 struct blk_io_trace *bit;
3aabcd89 321 struct rb_node *n;
8fc0abbc
JA
322 struct trace *t;
323 int cpu;
324
3aabcd89
JA
325 n = rb_first(&rb_root);
326 if (!n)
327 return;
8fc0abbc 328
3aabcd89 329 do {
8fc0abbc
JA
330 t = rb_entry(n, struct trace, rb_node);
331 bit = t->bit;
332
333 cpu = bit->magic;
87b72777 334 if (cpu > max_cpus) {
8fc0abbc 335 fprintf(stderr, "CPU number too large (%d)\n", cpu);
87b72777 336 break;
8fc0abbc
JA
337 }
338
3aabcd89 339 cur_file = &per_file_info[cpu];
8fc0abbc
JA
340
341 /*
342 * offset time by first trace event.
343 *
344 * NOTE: This is *cpu* relative, thus you can not
345 * compare times ACROSS cpus.
346 */
3aabcd89
JA
347 if (cur_file->start_time == 0)
348 cur_file->start_time = bit->time;
8fc0abbc 349
3aabcd89 350 bit->time -= cur_file->start_time;
8fc0abbc 351
87b72777
JA
352 if (dump_trace(bit))
353 break;
354
8fc0abbc
JA
355 } while ((n = rb_next(n)) != NULL);
356}
357
d0ca268b
JA
358int main(int argc, char *argv[])
359{
3aabcd89
JA
360 int i, nfiles, ret;
361 char *dev;
d0ca268b
JA
362
363 if (argc != 2) {
87b72777 364 fprintf(stderr, "Usage: %s <dev>\n", argv[0]);
d0ca268b
JA
365 return 1;
366 }
367
368 dev = argv[1];
369
87b72777
JA
370 for (max_cpus = 0, i = 0, nfiles = 0; i < MAX_CPUS; i++) {
371 struct per_file_info *pfi = &per_file_info[i];
372 struct stat st;
373 void *tb;
374
d0ca268b
JA
375 pfi->cpu = i;
376 pfi->start_time = 0;
377
87b72777
JA
378 snprintf(pfi->fname, sizeof(pfi->fname)-1,"%s_out.%d", dev, i);
379 if (stat(pfi->fname, &st) < 0)
d0ca268b 380 break;
d0ca268b 381
87b72777 382 snprintf(pfi->ofname, sizeof(pfi->ofname)-1, "%s_log.%d", dev, i);
d0ca268b
JA
383 pfi->ofp = fopen(pfi->ofname, "w");
384 if (pfi->ofp == NULL) {
385 perror(pfi->ofname);
3aabcd89 386 break;
d0ca268b
JA
387 }
388
8fc0abbc
JA
389 printf("Processing %s\n", pfi->fname);
390
87b72777 391 tb = malloc(st.st_size);
8fc0abbc
JA
392
393 pfi->fd = open(pfi->fname, O_RDONLY);
394 if (pfi->fd < 0) {
d0ca268b 395 perror(pfi->fname);
3aabcd89 396 break;
d0ca268b 397 }
87b72777 398 if (read(pfi->fd, tb, st.st_size) != st.st_size) {
8fc0abbc 399 fprintf(stderr, "error reading\n");
3aabcd89 400 break;
fd92da24 401 }
d0ca268b 402
87b72777 403 ret = sort_entries(tb, st.st_size);
8fc0abbc 404 if (ret == -1)
3aabcd89 405 break;
d0ca268b 406
8fc0abbc
JA
407 close(pfi->fd);
408 nfiles++;
87b72777 409 max_cpus++;
8fc0abbc 410 pfi->nelems = ret;
8fc0abbc 411 printf("\t%2d %10s %15d\n", i, pfi->fname, pfi->nelems);
d0ca268b 412
d0ca268b
JA
413 }
414
3aabcd89
JA
415 if (nfiles) {
416 show_entries();
417 show_stats();
418 return 0;
419 }
8fc0abbc 420
3aabcd89
JA
421 fprintf(stderr, "No files found\n");
422 return 1;
d0ca268b 423}