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