[PATCH] BTT patch: (2/3) per-IO stream output
[blktrace.git] / btt / trace.c
1 /*
2  * blktrace output analysis: generate a timeline & gather statistics
3  *
4  * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21 #include "globals.h"
22
23 int dump_level;
24 LIST_HEAD(retries);
25
26 static inline void dump_dev(FILE *ofp, __u32 dev)
27 {
28         fprintf(ofp, "%3d,%-3d ", MAJOR(dev), MINOR(dev));
29 }
30
31 static inline void dump_desc(FILE *ofp, struct io *iop)
32 {
33         fprintf(ofp, "%10llu+%-4u ", (unsigned long long)iop->t.sector, 
34                 t_sec(&iop->t));
35 }
36
37 void dump_iop(FILE *ofp, struct io *to_iop, struct io *from_iop, int indent)
38 {
39         int i, c;
40
41         if (!ofp) return;
42         if (to_iop->displayed) return;
43
44         fprintf(ofp, "%5d.%09lu ", (int)SECONDS(to_iop->t.time),
45                 (unsigned long)NANO_SECONDS(to_iop->t.time));
46
47         for (i = 0; i < ((dump_level * 4) + indent); i++)
48                 fprintf(ofp, " ");
49
50         dump_dev(ofp, to_iop->t.device);
51
52         switch (to_iop->type) {
53         case IOP_Q: c = 'Q'; break;
54         case IOP_L: c = 'L'; break;
55         case IOP_A: c = 'A'; break;
56         case IOP_I: c = 'I'; break;
57         case IOP_M: c = 'M'; break;
58         case IOP_D: c = 'D'; break;
59         case IOP_C: c = 'C'; break;
60         default   : c = '?'; break;
61         }
62
63         fprintf(ofp, "%c ", c);
64         dump_desc(ofp, to_iop);
65         if (from_iop) {
66                 fprintf(ofp, "<- ");
67                 dump_dev(ofp, from_iop->t.device);
68                 dump_desc(ofp, from_iop);
69         }
70                 
71         fprintf(ofp, "\n");
72
73         to_iop->displayed = 1;
74 }
75
76 void release_iops(struct list_head *del_head)
77 {
78         struct io *x_iop;
79         struct list_head *p, *q;
80
81         list_for_each_safe(p, q, del_head) {
82                 x_iop = list_entry(p, struct io, f_head);
83                 LIST_DEL(&x_iop->f_head);
84                 io_release(x_iop);
85         }
86 }
87
88 static void do_retries(void)
89 {
90         struct io *iop;
91         struct list_head *p, *q;
92
93         list_for_each_safe(p, q, &retries) {
94                 iop = list_entry(p, struct io, retry);
95                 // iop could be gone after call...
96                 if (iop->type == IOP_C) 
97                         retry_complete(iop);
98                 else
99                         retry_requeue(iop);
100         }
101 }
102
103 static void __add_trace(struct io *iop)
104 {
105         time_t now = time(NULL);
106
107         n_traces++;
108         iostat_check_time(iop->t.time);
109
110         if (verbose && ((now - last_vtrace) > 0)) {
111                 printf("%10lu t\r", n_traces);
112                 if ((n_traces % 1000000) == 0) printf("\n");
113                 fflush(stdout);
114                 last_vtrace = now;
115         }
116
117         switch (iop->t.action & 0xffff) {
118         case __BLK_TA_QUEUE:            trace_queue(iop); break;
119         case __BLK_TA_REMAP:            trace_remap(iop); break;
120         case __BLK_TA_INSERT:           trace_insert(iop); break;
121         case __BLK_TA_BACKMERGE:        trace_merge(iop); break;
122         case __BLK_TA_FRONTMERGE:       trace_merge(iop); break;
123         case __BLK_TA_REQUEUE:          trace_requeue(iop); break;
124         case __BLK_TA_ISSUE:            trace_issue(iop); break;
125         case __BLK_TA_COMPLETE:         trace_complete(iop); break;
126         default:                        
127                 io_release(iop); 
128                 return;
129         }
130
131         if (((iop->t.action & 0xffff) != __BLK_TA_REQUEUE) && 
132                                                 !list_empty(&retries))
133                 do_retries();
134 }
135
136 void add_trace(struct io *iop)
137 {
138         if (iop->t.time == 15717167961) dbg_ping();
139         if (iop->t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) {
140                 char *slash = strchr(iop->pdu, '/');
141
142                 if (slash)
143                         *slash = '\0';
144
145                 add_process(iop->t.pid, iop->pdu);
146                 io_release(iop);
147         }
148         else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC))
149                 io_release(iop);
150         else
151                 __add_trace(iop);
152 }