2 * block queue tracing parse application
4 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <sys/types.h>
32 #define MAX_CPUS (512)
34 #define SECONDS(x) ((unsigned long long)(x) / 1000000000)
35 #define NANO_SECONDS(x) ((unsigned long long)(x) % 1000000000)
38 unsigned long long genesis_time, last_reported_time;
39 struct per_file_info {
49 unsigned long qreads, qwrites, creads, cwrites, mreads, mwrites;
50 unsigned long ireads, iwrites;
51 unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
52 unsigned long long iread_kb, iwrite_kb;
55 static struct rb_root rb_root;
58 struct blk_io_trace *bit;
60 struct rb_node rb_node;
63 static struct per_file_info per_file_info[MAX_CPUS];
64 static struct per_file_info *cur_file;
66 static unsigned long long events;
70 static inline void check_time(struct blk_io_trace *bit)
72 unsigned long long this = bit->time;
73 unsigned long long last = last_reported_time;
75 backwards = (this < last) ? 'B' : ' ';
76 last_reported_time = this;
79 static inline void account_m(struct per_file_info *pfi, int rw,
84 pfi->qwrite_kb += bytes >> 10;
87 pfi->qread_kb += bytes >> 10;
91 static inline void account_q(struct per_file_info *pfi, int rw,
96 pfi->qwrite_kb += bytes >> 10;
99 pfi->qread_kb += bytes >> 10;
103 static inline void account_c(struct per_file_info *pfi, int rw,
108 pfi->cwrite_kb += bytes >> 10;
111 pfi->cread_kb += bytes >> 10;
115 static inline void account_i(struct per_file_info *pfi, int rw,
120 pfi->iwrite_kb += bytes >> 10;
123 pfi->iread_kb += bytes >> 10;
127 static void output(char *s)
130 fprintf(cur_file->ofp,"%s",s);
133 static char hstring[256];
134 static char tstring[256];
136 static inline char *setup_header(struct blk_io_trace *t, char act)
138 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
139 int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
140 int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
155 sprintf(hstring, "%c %3d %15ld %5Lu.%09Lu %5u %c %3s", backwards,
157 (unsigned long)t->sequence, SECONDS(t->time),
158 NANO_SECONDS(t->time), t->pid, act, rwbs);
163 static void log_complete(struct blk_io_trace *t, char act)
165 sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(t, act),
166 (unsigned long long)t->sector, t->bytes >> 9, t->error);
170 static void log_queue(struct blk_io_trace *t, char act)
172 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
173 (unsigned long long)t->sector, t->bytes >> 9);
177 static void log_issue(struct blk_io_trace *t, char act)
179 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
180 (unsigned long long)t->sector, t->bytes >> 9);
184 static void log_merge(struct blk_io_trace *t, char act)
186 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
187 (unsigned long long)t->sector, t->bytes >> 9);
191 static void log_generic(struct blk_io_trace *t, char act)
193 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
194 (unsigned long long)t->sector, t->bytes >> 9);
198 static int log_pc(struct blk_io_trace *t, char act)
203 sprintf(tstring,"%s ", setup_header(t, act));
206 buf = (unsigned char *) t + sizeof(*t);
207 for (i = 0; i < t->pdu_len; i++) {
208 sprintf(tstring,"%02x ", buf[i]);
213 sprintf(tstring,"[%d]", t->error);
221 static int dump_trace_pc(struct blk_io_trace *t, struct per_file_info *pfi)
225 switch (t->action & 0xffff) {
232 case __BLK_TA_SLEEPRQ:
235 case __BLK_TA_REQUEUE:
239 ret = log_pc(t, 'D');
241 case __BLK_TA_COMPLETE:
245 fprintf(stderr, "Bad pc action %x\n", t->action);
253 static void dump_trace_fs(struct blk_io_trace *t, struct per_file_info *pfi)
255 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
257 switch (t->action & 0xffff) {
259 account_q(pfi, w, t->bytes);
262 case __BLK_TA_BACKMERGE:
263 account_m(pfi, w, t->bytes);
266 case __BLK_TA_FRONTMERGE:
267 account_m(pfi, w, t->bytes);
273 case __BLK_TA_SLEEPRQ:
276 case __BLK_TA_REQUEUE:
277 account_c(pfi, w, -t->bytes);
281 account_i(pfi, w, t->bytes);
284 case __BLK_TA_COMPLETE:
285 account_c(pfi, w, t->bytes);
286 log_complete(t, 'C');
289 fprintf(stderr, "Bad fs action %x\n", t->action);
294 static int dump_trace(struct blk_io_trace *t, struct per_file_info *pfi)
298 if (t->action & BLK_TC_ACT(BLK_TC_PC))
299 ret = dump_trace_pc(t, pfi);
301 dump_trace_fs(t, pfi);
307 static void dump_pfi_stats(struct per_file_info *pfi)
309 printf("\tReads:\n");
310 printf("\t\tQueued: %'8lu, %'8LuKiB\n", pfi->qreads, pfi->qread_kb);
311 printf("\t\tDispatched %'8lu, %'8LuKiB\n", pfi->ireads, pfi->iread_kb);
312 printf("\t\tCompleted: %'8lu, %'8LuKiB\n", pfi->creads, pfi->cread_kb);
313 printf("\t\tMerges: %'8lu\n", pfi->mreads);
315 printf("\tWrites:\n");
316 printf("\t\tQueued: %'8lu, %'8LuKiB\n", pfi->qwrites,pfi->qwrite_kb);
317 printf("\t\tDispatched %'8lu, %'8LuKiB\n", pfi->iwrites,pfi->iwrite_kb);
318 printf("\t\tCompleted: %'8lu, %'8LuKiB\n", pfi->cwrites,pfi->cwrite_kb);
319 printf("\t\tMerges: %'8lu\n", pfi->mwrites);
322 static void show_stats(int nfiles)
324 struct per_file_info foo, *pfi;
327 memset(&foo, 0, sizeof(foo));
329 for (i = 0; i < nfiles; i++) {
330 pfi = &per_file_info[i];
335 foo.qreads += pfi->qreads;
336 foo.qwrites += pfi->qwrites;
337 foo.creads += pfi->creads;
338 foo.cwrites += pfi->cwrites;
339 foo.mreads += pfi->mreads;
340 foo.mwrites += pfi->mwrites;
341 foo.qread_kb += pfi->qread_kb;
342 foo.qwrite_kb += pfi->qwrite_kb;
343 foo.cread_kb += pfi->cread_kb;
344 foo.cwrite_kb += pfi->cwrite_kb;
346 printf("CPU%d:\n", i);
352 dump_pfi_stats(&foo);
355 printf("Events: %'Lu\n", events);
358 static inline int trace_rb_insert(struct trace *t)
360 struct rb_node **p = &rb_root.rb_node;
361 struct rb_node *parent = NULL;
366 __t = rb_entry(parent, struct trace, rb_node);
368 if (t->bit->sequence < __t->bit->sequence)
370 else if (t->bit->sequence > __t->bit->sequence)
373 fprintf(stderr, "sequence alias!\n");
378 rb_link_node(&t->rb_node, parent, p);
379 rb_insert_color(&t->rb_node, &rb_root);
383 static int sort_entries(void *traces, unsigned long offset, int cpu)
385 struct blk_io_trace *bit;
387 void *start = traces;
390 while (traces - start <= offset - sizeof(*bit)) {
393 t = malloc(sizeof(*t));
396 memset(&t->rb_node, 0, sizeof(t->rb_node));
400 if (verify_trace(bit))
403 if (trace_rb_insert(t))
406 traces += sizeof(*bit) + bit->pdu_len;
413 static void show_entries(void)
415 struct blk_io_trace *bit;
420 n = rb_first(&rb_root);
425 t = rb_entry(n, struct trace, rb_node);
429 if (cpu > max_cpus) {
430 fprintf(stderr, "CPU number too large (%d)\n", cpu);
434 cur_file = &per_file_info[cpu];
436 if (genesis_time == 0)
437 genesis_time = bit->time;
438 bit->time -= genesis_time;
442 if (dump_trace(bit, cur_file))
445 } while ((n = rb_next(n)) != NULL);
448 int main(int argc, char *argv[])
454 fprintf(stderr, "Usage: %s <dev>\n", argv[0]);
460 memset(&rb_root, 0, sizeof(rb_root));
461 memset(per_file_info, 0, sizeof(per_file_info));
463 for (max_cpus = 0, i = 0, nfiles = 0; i < MAX_CPUS; i++, nfiles++, max_cpus++) {
464 struct per_file_info *pfi = &per_file_info[i];
470 snprintf(pfi->fname, sizeof(pfi->fname)-1,"%s_out.%d", dev, i);
471 if (stat(pfi->fname, &st) < 0)
476 snprintf(pfi->ofname, sizeof(pfi->ofname)-1, "%s_log.%d", dev, i);
477 pfi->ofp = fopen(pfi->ofname, "w");
478 if (pfi->ofp == NULL) {
483 printf("Processing %s\n", pfi->fname);
485 tb = malloc(st.st_size);
487 pfi->fd = open(pfi->fname, O_RDONLY);
493 if (read(pfi->fd, tb, st.st_size) != st.st_size) {
494 fprintf(stderr, "error reading\n");
498 ret = sort_entries(tb, st.st_size, i);
504 printf("\t%2d %10s %15d\n", i, pfi->fname, pfi->nelems);
514 fprintf(stderr, "No files found\n");