[PATCH] Add in measuring of Plug and Unplug traces.
[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 void __dump_iop(FILE *ofp, struct io *iop, int extra_nl)
27 {
28         fprintf(ofp, "%5d.%09lu %3d,%-3d %c %10llu+%-4u\n",
29                 (int)SECONDS(iop->t.time),
30                 (unsigned long)NANO_SECONDS(iop->t.time),
31                 MAJOR(iop->t.device), MINOR(iop->t.device), type2c(iop->type),
32                 (unsigned long long)iop->t.sector, t_sec(&iop->t));
33         if (extra_nl) fprintf(ofp, "\n");
34 }
35
36 void __dump_iop2(FILE *ofp, struct io *a_iop, struct io *l_iop)
37 {
38         fprintf(ofp, "%5d.%09lu %3d,%-3d %c %10llu+%-4u <- (%3d,%-3d) %10llu\n",
39                 (int)SECONDS(a_iop->t.time),
40                 (unsigned long)NANO_SECONDS(a_iop->t.time),
41                 MAJOR(a_iop->t.device), MINOR(a_iop->t.device), 
42                 type2c(a_iop->type), (unsigned long long)a_iop->t.sector, 
43                 t_sec(&a_iop->t), MAJOR(l_iop->t.device), 
44                 MINOR(l_iop->t.device), (unsigned long long)l_iop->t.sector);
45 }
46
47 void release_iops(struct list_head *rmhd)
48 {
49         struct io *x_iop;
50         struct list_head *p, *q;
51
52         list_for_each_safe(p, q, rmhd) {
53                 x_iop = list_entry(p, struct io, f_head);
54                 LIST_DEL(&x_iop->f_head);
55                 io_release(x_iop);
56         }
57 }
58
59 void do_retries(__u64 now)
60 {
61         struct io *iop;
62         struct list_head *p, *q;
63
64         list_for_each_safe(p, q, &retries) {
65                 iop = list_entry(p, struct io, retry);
66                 ASSERT(iop->type == IOP_C);
67
68                 // iop could be gone after call...
69                 retry_complete(iop, now);
70         }
71 }
72
73 static inline int retry_check_time(__u64 t)
74 {
75         return next_retry_check && (t > next_retry_check);
76 }
77
78 static void __add_trace(struct io *iop)
79 {
80         time_t now = time(NULL);
81         __u64 tstamp = iop->t.time;
82         int run_retry = retry_check_time(iop->t.time);
83
84         n_traces++;
85         iostat_check_time(iop->t.time);
86
87         if (verbose && ((now - last_vtrace) > 0)) {
88 #if defined(DEBUG)
89                 printf("%10lu t\tretries=|%10d|\ttree size=|%10d|\r", 
90                         n_traces, list_len(&retries), rb_tree_size);
91 #else
92                 printf("%10lu t\r", n_traces);
93 #endif
94                 if ((n_traces % 1000000) == 0) printf("\n");
95                 fflush(stdout);
96                 last_vtrace = now;
97         }
98
99         switch (iop->t.action & 0xffff) {
100         case __BLK_TA_QUEUE:            trace_queue(iop); break;
101         case __BLK_TA_REMAP:            trace_remap(iop); break;
102         case __BLK_TA_GETRQ:            trace_insert(iop); break;
103         case __BLK_TA_BACKMERGE:        trace_merge(iop); break;
104         case __BLK_TA_FRONTMERGE:       trace_merge(iop); break;
105         case __BLK_TA_REQUEUE:          trace_requeue(iop); break;
106         case __BLK_TA_ISSUE:            trace_issue(iop); break;
107         case __BLK_TA_COMPLETE:         trace_complete(iop); break;
108         case __BLK_TA_PLUG:             trace_plug(iop); break;
109         case __BLK_TA_UNPLUG_IO:        trace_unplug_io(iop); break;
110         case __BLK_TA_UNPLUG_TIMER:     trace_unplug_timer(iop); break;
111         default:                        
112                 io_release(iop); 
113                 return;
114         }
115
116         if (run_retry && !list_empty(&retries)) {
117                 do_retries(tstamp);
118                 bump_retry(tstamp);
119         }
120 }
121
122 void add_trace(struct io *iop)
123 {
124         if (iop->t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) {
125                 if (iop->t.pid == 0) 
126                         add_process(0, "kernel");
127                 else {
128                         char *slash = strchr(iop->pdu, '/');
129                         if (slash)
130                                 *slash = '\0';
131
132                         add_process(iop->t.pid, iop->pdu);
133                 }
134                 io_release(iop);
135         }
136         else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC))
137                 io_release(iop);
138         else {
139                 if (time_bounded) {
140                         if (BIT_TIME(iop->t.time) < t_astart) {
141                                 io_release(iop);
142                                 return;
143                         }
144                         else if (BIT_TIME(iop->t.time) > t_aend) {
145                                 io_release(iop);
146                                 done = 1;
147                                 return;
148                         }
149                 }
150                 __add_trace(iop);
151         }
152 }