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