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 void region_init(struct region_info *reg)
24 INIT_LIST_HEAD(®->qranges);
25 INIT_LIST_HEAD(®->cranges);
28 static inline void __region_exit(struct list_head *range_head)
30 struct list_head *p, *q;
31 struct range_info *rip;
33 list_for_each_safe(p, q, range_head) {
34 rip = list_entry(p, struct range_info, head);
39 static inline void region_exit(struct region_info *reg)
41 __region_exit(®->qranges);
42 __region_exit(®->cranges);
45 static inline void update_range(struct list_head *head_p, __u64 time)
47 struct range_info *rip;
49 if (!list_empty(head_p)) {
50 rip = list_entry(head_p->prev, struct range_info, head);
55 if (BIT_TIME(time - rip->end) < range_delta) {
61 rip = malloc(sizeof(*rip));
62 rip->start = rip->end = time;
63 list_add_tail(&rip->head, head_p);
66 static inline void update_qregion(struct region_info *reg, __u64 time)
68 update_range(®->qranges, time);
71 static inline void update_cregion(struct region_info *reg, __u64 time)
73 update_range(®->cranges, time);
76 static inline void avg_update(struct avg_info *ap, __u64 t)
79 ap->min = ap->total = ap->max = t;
89 static inline void avg_update_n(struct avg_info *ap, __u64 t, int n)
92 ap->min = ap->max = t;
100 ap->total += (n * t);
106 static inline void avg_unupdate(struct avg_info *ap, __u64 t)
112 static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
114 if (*last_q != ((__u64)-1))
115 avg_update(avg, (time > *last_q) ? time - *last_q : 1);
119 static inline void dip_update_q(struct d_info *dip, struct io *iop)
121 update_lq(&dip->last_q, &dip->avgs.q2q, iop->t.time);
122 update_qregion(&dip->regions, iop->t.time);
125 static inline struct io *io_alloc(void)
129 if (!list_empty(&free_ios)) {
130 iop = list_entry(free_ios.prev, struct io, f_head);
131 LIST_DEL(&iop->f_head);
133 # if defined(COUNT_IOS)
138 iop = malloc(sizeof(struct io));
140 # if defined(COUNT_IOS)
145 memset(iop, 0, sizeof(struct io));
148 iop->f_head.next = LIST_POISON1;
151 # if defined(COUNT_IOS)
152 list_add_tail(&iop->cio_head, &cios);
158 static inline void io_free(struct io *iop)
160 # if defined(COUNT_IOS)
162 LIST_DEL(&iop->cio_head);
166 memset(iop, 0, sizeof(*iop));
169 list_add_tail(&iop->f_head, &free_ios);
172 static inline void io_free_all(void)
175 struct list_head *p, *q;
177 list_for_each_safe(p, q, &free_ios) {
178 iop = list_entry(p, struct io, f_head);
183 static inline int io_setup(struct io *iop, enum iop_type type)
186 iop->dip = dip_add(iop->t.device, iop);
188 iop->pip = find_process(iop->t.pid, NULL);
189 iop->bytes_left = iop->t.bytes;
195 static inline void io_release(struct io *iop)
197 ASSERT(iop->f_head.next == LIST_POISON1);
207 #define UPDATE_AVGS(_avg, _iop, _pip, _time) do { \
208 avg_update(&all_avgs. _avg , _time); \
209 avg_update(&_iop->dip->avgs. _avg , _time); \
210 if (_pip) avg_update(&_pip->avgs. _avg , _time); \
213 #define UPDATE_AVGS_N(_avg, _iop, _pip, _time, _n) do { \
214 avg_update_n(&all_avgs. _avg , _time, _n); \
215 avg_update_n(&_iop->dip->avgs. _avg , _time, _n); \
216 if (_pip) avg_update_n(&_pip->avgs. _avg , _time,_n); \
219 #define UNUPDATE_AVGS(_avg, _iop, _pip, _time) do { \
220 avg_unupdate(&all_avgs. _avg , _time); \
221 avg_unupdate(&_iop->dip->avgs. _avg , _time); \
222 if (_pip) avg_unupdate(&_pip->avgs. _avg , _time); \
225 static inline void update_q2c(struct io *iop, __u64 c_time)
229 fprintf(per_io_ofp, "q2c %13.9f\n", BIT_TIME(c_time));
231 UPDATE_AVGS(q2c, iop, iop->pip, c_time);
234 static inline void update_q2a(struct io *iop, __u64 a_time)
238 fprintf(per_io_ofp, "q2a %13.9f\n", BIT_TIME(a_time));
240 UPDATE_AVGS(q2a, iop, iop->pip, a_time);
243 static inline void update_q2i(struct io *iop, __u64 i_time)
247 fprintf(per_io_ofp, "q2i %13.9f\n", BIT_TIME(i_time));
250 UPDATE_AVGS(q2i, iop, iop->pip, i_time);
253 static inline void unupdate_q2i(struct io *iop, __u64 i_time)
255 UNUPDATE_AVGS(q2i, iop, iop->pip, i_time);
258 static inline void update_i2d(struct io *iop, __u64 d_time)
262 fprintf(per_io_ofp, "i2d %13.9f\n", BIT_TIME(d_time));
265 UPDATE_AVGS(i2d, iop, iop->pip, d_time);
268 static inline void unupdate_i2d(struct io *iop, __u64 d_time)
270 UNUPDATE_AVGS(i2d, iop, iop->pip, d_time);
273 static inline void update_d2c(struct io *iop, __u64 c_time)
277 fprintf(per_io_ofp, "d2c %13.9f\n", BIT_TIME(c_time));
280 UPDATE_AVGS(d2c, iop, iop->pip, c_time);
283 static inline void update_blks(struct io *iop)
285 __u64 nblks = iop->t.bytes >> 9;
286 avg_update(&all_avgs.blks, nblks);
287 ASSERT(iop->dip != NULL);
288 avg_update(&iop->dip->avgs.blks, nblks);
290 avg_update(&iop->pip->avgs.blks, nblks);
293 static inline struct rb_root *__get_root(struct d_info *dip, enum iop_type type)
295 struct rb_root *roots = dip->heads;
299 static inline int dip_rb_ins(struct d_info *dip, struct io *iop)
301 return rb_insert(__get_root(dip, iop->type), iop);
304 static inline void dip_rb_rem(struct io *iop)
306 rb_erase(&iop->rb_node, __get_root(iop->dip, iop->type));
313 static inline void dip_rb_fe(struct d_info *dip, enum iop_type type,
315 void (*fnc)(struct io *iop, struct io *this),
316 struct list_head *head)
318 rb_foreach(__get_root(dip, type)->rb_node, iop, fnc, head);
321 static inline struct io *dip_rb_find_sec(struct d_info *dip,
322 enum iop_type type, __u64 sec)
324 return rb_find_sec(__get_root(dip, type), sec);
327 static inline __u64 tdelta(__u64 from, __u64 to)
329 return (from < to) ? (to - from) : 1;
332 static inline int remapper_dev(__u32 dev)
334 int mjr = MAJOR(dev);
335 return mjr == 9 || mjr == 253 || mjr == 254;
338 static inline int type2c(enum iop_type type)
343 case IOP_Q: c = 'Q'; break;
344 case IOP_X: c = 'X'; break;
345 case IOP_A: c = 'A'; break;
346 case IOP_I: c = 'I'; break;
347 case IOP_M: c = 'M'; break;
348 case IOP_D: c = 'D'; break;
349 case IOP_C: c = 'C'; break;
350 case IOP_R: c = 'R'; break;
351 case IOP_G: c = 'G'; break;
352 default : c = '?'; break;
358 static inline int histo_idx(__u64 nbytes)
360 int idx = (nbytes >> 9) - 1;
361 return min(idx, N_HIST_BKTS-1);
364 static inline void update_q_histo(__u64 nbytes)
366 q_histo[histo_idx(nbytes)]++;
369 static inline void update_d_histo(__u64 nbytes)
371 d_histo[histo_idx(nbytes)]++;
374 static inline struct io *io_first_list(struct list_head *head)
376 if (list_empty(head))
379 return list_entry(head->next, struct io, f_head);
382 static inline void __dump_iop(FILE *ofp, struct io *iop, int extra_nl)
384 fprintf(ofp, "%5d.%09lu %3d,%-3d %c %10llu+%-4u\n",
385 (int)SECONDS(iop->t.time),
386 (unsigned long)NANO_SECONDS(iop->t.time),
387 MAJOR(iop->t.device), MINOR(iop->t.device), type2c(iop->type),
388 (unsigned long long)iop->t.sector, t_sec(&iop->t));
389 if (extra_nl) fprintf(ofp, "\n");
392 static inline void __dump_iop2(FILE *ofp, struct io *a_iop, struct io *l_iop)
394 fprintf(ofp, "%5d.%09lu %3d,%-3d %c %10llu+%-4u <- (%3d,%-3d) %10llu\n",
395 (int)SECONDS(a_iop->t.time),
396 (unsigned long)NANO_SECONDS(a_iop->t.time),
397 MAJOR(a_iop->t.device), MINOR(a_iop->t.device),
398 type2c(a_iop->type), (unsigned long long)a_iop->t.sector,
399 t_sec(&a_iop->t), MAJOR(l_iop->t.device),
400 MINOR(l_iop->t.device), (unsigned long long)l_iop->t.sector);