[PATCH] Convert to using on-the-fly RB trees, no post-traversal.
[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 void im2d_func(struct io *d_iop, struct io *im_iop)
24 {
25         update_i2d(im_iop, d_iop->t.time - im_iop->t.time);
26 }
27
28 void q2c_func(struct io *c_iop, struct io *q_iop)
29 {
30         __u64 q2c = c_iop->t.time - q_iop->t.time;
31
32         update_q2c(q_iop, q2c);
33         latency_q2c(q_iop->dip, q_iop->t.time, q2c);
34 }
35
36 static inline void handle_im(struct io *im_iop)
37 {
38         struct io *q_iop;
39
40         q_iop = dip_find_sec(im_iop->dip, IOP_Q, BIT_START(im_iop));
41         if (q_iop)
42                 update_q2i(q_iop, im_iop->t.time - q_iop->t.time);
43 }
44
45 void handle_queue(struct io *q_iop)
46 {
47         io_setup(q_iop, IOP_Q, 1);
48         update_lq(&last_q, &all_avgs.q2q, q_iop->t.time);
49         update_qregion(&all_regions, q_iop->t.time);
50         dip_update_q(q_iop->dip, q_iop);
51         pip_update_q(q_iop);
52 }
53
54 void handle_remap(struct io *a_iop)
55 {
56         struct io *q_iop;
57         struct blk_io_trace_remap *rp = a_iop->pdu;
58         struct d_info *dip = __dip_find(be32_to_cpu(rp->device));
59
60         io_setup(a_iop, IOP_A, 0);
61         q_iop = dip_find_sec(dip, IOP_Q, be64_to_cpu(rp->sector));
62         if (q_iop)
63                 update_q2a(q_iop, a_iop->t.time - q_iop->t.time);
64         io_release(a_iop);
65 }
66
67 void handle_insert(struct io *i_iop)
68 {
69         io_setup(i_iop, IOP_I, 1);
70         iostat_insert(i_iop);
71         handle_im(i_iop);
72 }
73
74 void handle_merge(struct io *m_iop)
75 {
76         io_setup(m_iop, IOP_M, 1);
77         iostat_merge(m_iop);
78         handle_im(m_iop);
79 }
80
81 void handle_issue(struct io *d_iop)
82 {
83         io_setup(d_iop, IOP_D, 1);
84         d_iop->dip->n_ds++;
85
86         dip_foreach(d_iop, IOP_I, im2d_func, 0);
87         dip_foreach(d_iop, IOP_M, im2d_func, 0);
88
89         if (seek_name)
90                 seeki_add(d_iop->dip->seek_handle, d_iop);
91         iostat_issue(d_iop);
92 }
93
94 void handle_complete(struct io *c_iop)
95 {
96         struct io *d_iop;
97
98         io_setup(c_iop, IOP_C, 0);
99         update_blks(c_iop);
100         update_cregion(&all_regions, c_iop->t.time);
101         update_cregion(&c_iop->dip->regions, c_iop->t.time);
102         if (c_iop->pip)
103                 update_cregion(&c_iop->pip->regions, c_iop->t.time);
104
105         d_iop = dip_find_sec(c_iop->dip, IOP_D, BIT_START(c_iop));
106         if (d_iop) {
107                 __u64 d2c = c_iop->t.time - d_iop->t.time;
108                 update_d2c(d_iop, d2c);
109                 latency_d2c(d_iop->dip, c_iop->t.time, d2c);
110                 iostat_complete(d_iop, c_iop);
111                 dip_foreach(d_iop, IOP_I, NULL, 1);
112                 dip_foreach(d_iop, IOP_M, NULL, 1);
113                 io_release(d_iop);
114         }
115
116         dip_foreach(c_iop, IOP_Q, q2c_func, 1);
117         io_release(c_iop);
118 }
119
120 void rq_im2d_func(struct io *d_iop, struct io *im_iop)
121 {
122         unupdate_i2d(im_iop, d_iop->t.time - im_iop->t.time);
123 }
124
125 /*
126  * Careful surgery
127  * (1) Need to remove D & its I & M's
128  * (2) Need to leave I's Q and M's Q's
129  * (3) XXX: Need to downward adjust stats, but we don't carry PREVIOUS
130  *     XXX: min/maxes?! We'll just adjust what we can, and hope that 
131  *     XXX: the min/maxes are "pretty close". (REQUEUEs are rare, right?)
132  */
133 void handle_requeue(struct io *r_iop)
134 {
135         struct io *d_iop;
136
137         io_setup(r_iop, IOP_R, 0);
138         d_iop = dip_find_sec(r_iop->dip, IOP_D, BIT_START(r_iop));
139         if (d_iop) {
140                 dip_foreach(d_iop, IOP_I, rq_im2d_func, 1);
141                 dip_foreach(d_iop, IOP_M, rq_im2d_func, 1);
142                 iostat_unissue(d_iop);
143                 io_release(d_iop);
144         }
145         io_release(r_iop);
146 }
147
148 void __add_trace(struct io *iop)
149 {
150         time_t now = time(NULL);
151
152         n_traces++;
153         iostat_check_time(iop->t.time);
154
155         if (verbose && ((now - last_vtrace) > 0)) {
156                 printf("%10lu t\r", n_traces);
157                 if ((n_traces % 1000000) == 0) printf("\n");
158                 fflush(stdout);
159                 last_vtrace = now;
160         }
161
162         switch (iop->t.action & 0xffff) {
163         case __BLK_TA_QUEUE:            handle_queue(iop); break;
164         case __BLK_TA_BACKMERGE:        handle_merge(iop); break;
165         case __BLK_TA_FRONTMERGE:       handle_merge(iop); break;
166         case __BLK_TA_ISSUE:            handle_issue(iop); break;
167         case __BLK_TA_COMPLETE:         handle_complete(iop); break;
168         case __BLK_TA_INSERT:           handle_insert(iop); break;
169         case __BLK_TA_REMAP:            handle_remap(iop); break;
170         case __BLK_TA_REQUEUE:          handle_requeue(iop); break;
171         default:                        io_release(iop); break;
172         }
173 }
174
175 void add_trace(struct io *iop)
176 {
177         if (iop->t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) {
178                 char *slash = strchr(iop->pdu, '/');
179
180                 if (slash)
181                         *slash = '\0';
182
183                 add_process(iop->t.pid, iop->pdu);
184                 io_release(iop);
185         }
186         else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC))
187                 io_release(iop);
188         else
189                 __add_trace(iop);
190 }