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