2 * blktrace output analysis: generate a timeline & gather statistics
4 * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
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
22 static inline struct range_info *new_cur(__u64 time)
24 struct range_info *cur = malloc(sizeof(struct range_info));
26 INIT_LIST_HEAD(&cur->head);
31 static inline void update_range(struct list_head *head_p,
32 struct range_info **cur_p, __u64 time)
35 *cur_p = new_cur(time);
37 __u64 my_delta = (time > (*cur_p)->end) ? time - (*cur_p)->end : 1;
38 if (BIT_TIME(my_delta) >= range_delta) {
39 list_add_tail(&(*cur_p)->head, head_p);
40 *cur_p = new_cur(time);
47 static inline void init_region(struct region_info *reg)
49 INIT_LIST_HEAD(®->qranges);
50 INIT_LIST_HEAD(®->cranges);
51 reg->qr_cur = reg->cr_cur = NULL;
54 static inline void update_qregion(struct region_info *reg, __u64 time)
56 update_range(®->qranges, ®->qr_cur, time);
59 static inline void update_cregion(struct region_info *reg, __u64 time)
61 update_range(®->cranges, ®->cr_cur, time);
64 static inline void avg_update(struct avg_info *ap, __u64 t)
67 ap->min = ap->total = ap->max = t;
77 static inline void avg_unupdate(struct avg_info *ap, __u64 t)
83 static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
85 if (*last_q != ((__u64)-1))
86 avg_update(avg, (time > *last_q) ? time - *last_q : 1);
90 static inline void dip_update_q(struct d_info *dip, struct io *iop)
92 update_lq(&dip->last_q, &dip->avgs.q2q, iop->t.time);
93 update_qregion(&dip->regions, iop->t.time);
96 static inline struct io *io_alloc(void)
100 if (!list_empty(&free_ios)) {
101 iop = list_entry(free_ios.next, struct io, f_head);
102 LIST_DEL(&iop->f_head);
105 iop = malloc(sizeof(struct io));
107 memset(iop, 0, sizeof(struct io));
112 static inline void io_free(struct io *iop)
115 memset(iop, 0, sizeof(*iop));
117 list_add_tail(&iop->f_head, &free_ios);
120 static inline int io_setup(struct io *iop, enum iop_type type)
123 iop->dip = dip_add(iop->t.device, iop);
125 iop->pip = find_process(iop->t.pid, NULL);
126 INIT_LIST_HEAD(&iop->down_list);
127 INIT_LIST_HEAD(&iop->up_list);
128 iop->bytes_left = iop->t.bytes;
134 static inline void io_release(struct io *iop)
143 #define UPDATE_AVGS(_avg, _iop, _pip, _time) do { \
144 avg_update(&all_avgs. _avg , _time); \
145 avg_update(&_iop->dip->avgs. _avg , _time); \
146 if (_pip) avg_update(&_pip->avgs. _avg , _time); \
149 #define UNUPDATE_AVGS(_avg, _iop, _pip, _time) do { \
150 avg_unupdate(&all_avgs. _avg , _time); \
151 avg_unupdate(&_iop->dip->avgs. _avg , _time); \
152 if (_pip) avg_unupdate(&_pip->avgs. _avg , _time); \
155 static inline void update_q2c(struct io *iop, __u64 c_time)
157 UPDATE_AVGS(q2c, iop, iop->pip, c_time);
160 static inline void update_q2a(struct io *iop, __u64 a_time)
162 UPDATE_AVGS(q2a, iop, iop->pip, a_time);
165 static inline void update_q2i(struct io *iop, __u64 i_time)
167 UPDATE_AVGS(q2i, iop, iop->pip, i_time);
170 static inline void update_i2d(struct io *iop, __u64 d_time)
172 UPDATE_AVGS(i2d, iop, iop->pip, d_time);
175 static inline void unupdate_i2d(struct io *iop, __u64 d_time)
177 UNUPDATE_AVGS(i2d, iop, iop->pip, d_time);
180 static inline void update_d2c(struct io *iop, __u64 c_time)
182 UPDATE_AVGS(d2c, iop, iop->pip, c_time);
185 static inline void update_blks(struct io *iop)
187 __u64 nblks = iop->t.bytes >> 9;
188 avg_update(&all_avgs.blks, nblks);
189 ASSERT(iop->dip != NULL);
190 avg_update(&iop->dip->avgs.blks, nblks);
192 avg_update(&iop->pip->avgs.blks, nblks);
195 static inline struct rb_root *__get_root(struct d_info *dip, enum iop_type type)
197 struct rb_root *roots = dip->heads;
201 static inline void *dip_rb_mkhds(void)
203 size_t len = N_IOP_TYPES * sizeof(struct rb_root);
204 return memset(malloc(len), 0, len);
207 static inline int dip_rb_ins(struct d_info *dip, struct io *iop)
209 return rb_insert(__get_root(dip, iop->type), iop);
212 static inline void dip_rb_rem(struct io *iop)
214 rb_erase(&iop->rb_node, __get_root(iop->dip, iop->type));
217 static inline void dip_rb_fe(struct d_info *dip, enum iop_type type,
219 void (*fnc)(struct io *iop, struct io *this),
220 struct list_head *head)
222 rb_foreach(__get_root(dip, type)->rb_node, iop, fnc, head);
225 static inline struct io *dip_rb_find_sec(struct d_info *dip,
226 enum iop_type type, __u64 sec)
228 return rb_find_sec(__get_root(dip, type), sec);
231 static inline struct io *list_first_down(struct io *iop)
233 struct list_head *p = list_first(&iop->down_list);
234 return p ? list_entry(p, struct io, up_head) : NULL;
237 static inline struct io *list_first_up(struct io *iop)
239 struct list_head *p = list_first(&iop->up_list);
240 return p ? list_entry(p, struct io, down_head) : NULL;
243 static inline int list_empty_up(struct io *iop)
245 return list_empty(&iop->up_list);
248 static inline void __link(struct io *down_iop, struct io *up_iop)
250 list_add_tail(&down_iop->up_head, &up_iop->down_list);
251 list_add_tail(&up_iop->down_head, &down_iop->up_list);
254 static inline void __unlink(struct io *down_iop, struct io *up_iop)
256 LIST_DEL(&down_iop->up_head);
257 LIST_DEL(&up_iop->down_head);
260 static inline void add_retry(struct io *iop)
262 list_add_tail(&iop->retry, &retries);
265 static inline void del_retry(struct io *iop)
267 LIST_DEL(&iop->retry);
270 static inline __u64 tdelta(struct io *iop1, struct io *iop2)
272 __u64 t1 = iop1->t.time;
273 __u64 t2 = iop2->t.time;
274 return (t1 < t2) ? (t2 - t1) : 1;