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
24 typedef struct avg_info *ai_dip_t;
25 ai_dip_t dip_q2q_avg(struct d_info *dip) { return &dip->avgs.q2q; }
26 ai_dip_t dip_q2c_avg(struct d_info *dip) { return &dip->avgs.q2c; }
27 ai_dip_t dip_q2a_avg(struct d_info *dip) { return &dip->avgs.q2a; }
28 ai_dip_t dip_q2i_avg(struct d_info *dip) { return &dip->avgs.q2i; }
29 ai_dip_t dip_i2d_avg(struct d_info *dip) { return &dip->avgs.i2d; }
30 ai_dip_t dip_d2c_avg(struct d_info *dip) { return &dip->avgs.d2c; }
32 typedef struct avg_info *ai_pip_t;
33 ai_pip_t pip_q2q_avg(struct p_info *pip) { return &pip->avgs.q2q; }
34 ai_pip_t pip_q2c_avg(struct p_info *pip) { return &pip->avgs.q2c; }
35 ai_pip_t pip_q2a_avg(struct p_info *pip) { return &pip->avgs.q2a; }
36 ai_pip_t pip_q2i_avg(struct p_info *pip) { return &pip->avgs.q2i; }
37 ai_pip_t pip_i2d_avg(struct p_info *pip) { return &pip->avgs.i2d; }
38 ai_pip_t pip_d2c_avg(struct p_info *pip) { return &pip->avgs.d2c; }
40 void output_section_hdr(FILE *ofp, char *hdr)
42 fprintf(ofp, "==================== ");
44 fprintf(ofp, " ====================\n\n");
47 void output_hdr(FILE *ofp, char *hdr)
49 fprintf(ofp, "%12s %13s %13s %13s %11s\n",
50 hdr, "MIN", "AVG", "MAX", "N" );
51 fprintf(ofp, "------------ ------------- ------------- ------------- -----------\n");
54 void __output_avg(FILE *ofp, char *hdr, struct avg_info *ap)
57 ap->avg = BIT_TIME(ap->total) / (double)ap->n;
58 fprintf(ofp, "%-12s %13.9f %13.9f %13.9f %11d\n", hdr,
59 BIT_TIME(ap->min), ap->avg, BIT_TIME(ap->max), ap->n);
63 void output_hdr2(FILE *ofp, char*hdr)
65 fprintf(ofp, "%12s %13s %13s %13s %13s %13s %13s\n", hdr, "Q2Q", "Q2A", "Q2I", "I2D", "D2C", "Q2C");
66 fprintf(ofp, "------------ ------------- ------------- ------------- ------------- ------------- -------------\n");
69 static inline char *avg2string(struct avg_info *ap, char *string)
72 sprintf(string, "%13.9f", ap->avg);
78 void __output_avg2(FILE *ofp, char *hdr, struct avgs_info *ap)
80 char c1[16], c2[16], c3[16], c4[16], c5[16], c6[16];
82 if (ap->q2q.n > 0 || ap->q2a.n > 0 || ap->q2i.n > 0 ||
83 ap->i2d.n > 0 || ap->d2c.n > 0 || ap->q2c.n > 0) {
84 fprintf(ofp, "%-12s %13s %13s %13s %13s %13s %13s\n", hdr,
85 avg2string(&ap->q2q,c1), avg2string(&ap->q2a,c2),
86 avg2string(&ap->q2i,c3), avg2string(&ap->i2d,c4),
87 avg2string(&ap->d2c,c5), avg2string(&ap->q2c,c6));
91 char *make_dev_hdr(char *pad, size_t len, struct d_info *dip)
93 if (dip->map == NULL) {
94 snprintf(pad, len, "(%3d,%3d)",
95 MAJOR(dip->device), MINOR(dip->device));
98 snprintf(pad, len, "[%3d,%3d]",
99 dip->map->host, dip->map->target);
105 void __output_dip_avg(FILE *ofp, struct d_info *dip, struct avg_info *ap)
109 ap->avg = BIT_TIME(ap->total) / (double)ap->n;
110 __output_avg(ofp, make_dev_hdr(dev_info, 12, dip), ap);
114 void output_dip_avg(FILE *ofp, char *hdr, ai_dip_t (*func)(struct d_info *))
118 output_hdr(ofp, hdr);
119 if (devices == NULL) {
122 __list_for_each(p, &all_devs) {
123 dip = list_entry(p, struct d_info, head);
124 __output_dip_avg(ofp, dip, func(dip));
129 unsigned int mjr, mnr;
132 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
133 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
134 __output_dip_avg(ofp, dip, func(dip));
144 void __output_dip_merge_ratio(FILE *ofp, struct d_info *dip)
148 double ratio, q2c_n = dip->avgs.q2c.n, d2c_n = dip->n_ds;
150 if (q2c_n > 0.0 && d2c_n > 0.0) {
151 ratio = q2c_n / d2c_n;
152 blks_avg = (double)dip->avgs.blks.total / d2c_n;
153 fprintf(ofp, "%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
154 make_dev_hdr(scratch, 12, dip),
155 (unsigned long long)dip->avgs.q2c.n,
156 (unsigned long long)dip->n_ds,
158 (unsigned long long)dip->avgs.blks.min,
159 (unsigned long long)blks_avg,
160 (unsigned long long)dip->avgs.blks.max,
161 (unsigned long long)dip->avgs.blks.total);
166 void output_dip_merge_ratio(FILE *ofp)
170 fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
171 fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
172 if (devices == NULL) {
175 __list_for_each(p, &all_devs) {
176 dip = list_entry(p, struct d_info, head);
177 __output_dip_merge_ratio(ofp, dip);
182 unsigned int mjr, mnr;
185 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
186 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
187 __output_dip_merge_ratio(ofp, dip);
197 #define AVG(a,b) (100.0 * ((double)(a) / (double)(b)))
198 #define CALC_AVG(ap) (ap)->avg = ((ap)->n == 0 ? 0.0 : \
199 (BIT_TIME((ap)->total) / \
201 char *q2i_v_q2C(struct d_info *dip, char *s)
205 if (dip->avgs.q2i.n == 0) return " ";
207 q2c = dip->avgs.q2i.avg + dip->avgs.i2d.avg + dip->avgs.d2c.avg;
208 sprintf(s, "%5.1lf%%", AVG(dip->avgs.q2i.avg, q2c));
213 char *i2d_v_q2C(struct d_info *dip, char *s)
217 if (dip->avgs.d2c.n == 0) return " ";
219 q2c = dip->avgs.q2i.avg + dip->avgs.i2d.avg + dip->avgs.d2c.avg;
220 sprintf(s, "%5.1lf%%", AVG(dip->avgs.i2d.avg, q2c));
225 char *d2c_v_q2C(struct d_info *dip, char *s)
229 if (dip->avgs.d2c.n == 0) return " ";
231 q2c = dip->avgs.q2i.avg + dip->avgs.i2d.avg + dip->avgs.d2c.avg;
232 sprintf(s, "%5.1lf%%", AVG(dip->avgs.d2c.avg, q2c));
237 void __output_dip_prep_ohead(FILE *ofp, struct d_info *dip)
240 char s1[16], s2[16], s3[16];
242 if ((dip->avgs.q2i.n > 0 && dip->avgs.i2d.n > 0 &&
243 dip->avgs.d2c.n > 0)) {
244 CALC_AVG(&dip->avgs.q2i);
245 CALC_AVG(&dip->avgs.i2d);
246 CALC_AVG(&dip->avgs.d2c);
248 fprintf(ofp, "%10s | %6s %6s %6s\n",
249 make_dev_hdr(dev_info, 12, dip),
250 q2i_v_q2C(dip, s1), i2d_v_q2C(dip, s2),
255 void output_dip_prep_ohead(FILE *ofp)
259 fprintf(ofp, "%10s | %6s %6s %6s\n", "DEV", "Q2I", "I2D", "D2C");
260 fprintf(ofp, "---------- | ------ ------ ------\n");
262 if (devices == NULL) {
265 __list_for_each(p, &all_devs) {
266 dip = list_entry(p, struct d_info, head);
267 __output_dip_prep_ohead(ofp, dip);
272 unsigned int mjr, mnr;
275 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
276 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
277 __output_dip_prep_ohead(ofp, dip);
287 void __output_dip_seek_info(FILE *ofp, struct d_info *dip)
290 int i, nmodes, most_seeks;
293 long long median, *modes;
295 nseeks = seeki_nseeks(dip->seek_handle);
297 mean = seeki_mean(dip->seek_handle);
298 median = seeki_median(dip->seek_handle);
299 nmodes = seeki_mode(dip->seek_handle, &modes, &most_seeks);
301 fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
302 make_dev_hdr(dev_info, 12, dip), nseeks, mean, median,
303 nmodes > 0 ? modes[0] : 0, most_seeks);
304 for (i = 1; i < nmodes; i++)
305 fprintf(ofp, " %lld", modes[i]);
310 void output_dip_seek_info(FILE *ofp)
314 fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS",
315 "MEAN", "MEDIAN", "MODE");
316 fprintf(ofp, "---------- "
317 "| --------------- --------------- --------------- "
318 "| ---------------\n");
320 if (devices == NULL) {
323 __list_for_each(p, &all_devs) {
324 dip = list_entry(p, struct d_info, head);
325 __output_dip_seek_info(ofp, dip);
330 unsigned int mjr, mnr;
333 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
334 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
335 __output_dip_seek_info(ofp, dip);
345 void __output_pip_avg(FILE *ofp, struct p_info *pip, struct avg_info *ap)
349 snprintf(proc_name, 12, pip->name);
351 ap->avg = BIT_TIME(ap->total) / (double)ap->n;
352 __output_avg(ofp, proc_name, ap);
356 void output_pip_avg(FILE *ofp, char *hdr, ai_pip_t (*func)(struct p_info *))
360 output_hdr(ofp, hdr);
364 __list_for_each(p, &all_procs) {
365 pip = list_entry(p, struct p_info, head);
366 __output_pip_avg(ofp, pip, func(pip));
370 char *exe, *p, *next, *exes_save = strdup(exes);
373 while (exes_save != NULL) {
375 if ((next = strchr(exes_save, ',')) != NULL) {
382 pip = find_process((__u32)-1, exe);
384 __output_pip_avg(ofp, pip, func(pip));
391 void output_dip_avgs(FILE *ofp)
396 output_hdr2(ofp,"Dev");
397 if (devices == NULL) {
400 __list_for_each(p, &all_devs) {
401 dip = list_entry(p, struct d_info, head);
402 __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
408 unsigned int mjr, mnr;
411 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
412 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
413 __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
424 void output_pip_avgs(FILE *ofp)
429 output_hdr2(ofp,"Exe");
433 __list_for_each(p, &all_procs) {
434 pip = list_entry(p, struct p_info, head);
435 snprintf(exe, 12, pip->name);
436 __output_avg2(ofp, exe, &pip->avgs);
440 char *exe, *p, *next, *exes_save = strdup(exes);
443 while (exes_save != NULL && *exes_save != '\0') {
445 if ((next = strchr(exes_save, ',')) != NULL) {
452 pip = find_process((__u32)-1, exe);
454 snprintf(exe, 12, pip->name);
455 __output_avg2(ofp, exe, &pip->avgs);
463 int output_avgs(FILE *ofp)
465 if (exes == NULL || *exes != '\0') {
466 output_section_hdr(ofp, "Per Process");
467 output_pip_avg(ofp, "Q2Q", pip_q2q_avg);
468 output_pip_avg(ofp, "Q2A", pip_q2a_avg);
469 output_pip_avg(ofp, "Q2I", pip_q2i_avg);
470 output_pip_avg(ofp, "I2D", pip_i2d_avg);
471 output_pip_avg(ofp, "D2C", pip_d2c_avg);
472 output_pip_avg(ofp, "Q2C", pip_q2c_avg);
475 output_section_hdr(ofp, "Per Device");
476 output_dip_avg(ofp, "Q2Q", dip_q2q_avg);
477 output_dip_avg(ofp, "Q2A", dip_q2a_avg);
478 output_dip_avg(ofp, "Q2I", dip_q2i_avg);
479 output_dip_avg(ofp, "I2D", dip_i2d_avg);
480 output_dip_avg(ofp, "D2C", dip_d2c_avg);
481 output_dip_avg(ofp, "Q2C", dip_q2c_avg);
483 output_section_hdr(ofp, "All Devices");
484 output_hdr(ofp, "ALL");
485 __output_avg(ofp, "Q2Q", &all_avgs.q2q);
486 __output_avg(ofp, "Q2A", &all_avgs.q2a);
487 __output_avg(ofp, "Q2I", &all_avgs.q2i);
488 __output_avg(ofp, "I2D", &all_avgs.i2d);
489 __output_avg(ofp, "D2C", &all_avgs.d2c);
490 __output_avg(ofp, "Q2C", &all_avgs.q2c);
492 if (exes == NULL || *exes != '\0') {
493 output_section_hdr(ofp, "Per Process (avgs)");
494 output_pip_avgs(ofp);
497 output_section_hdr(ofp, "Per Device (avgs)");
498 output_dip_avgs(ofp);
500 output_section_hdr(ofp, "Device Merge Information");
501 output_dip_merge_ratio(ofp);
503 output_section_hdr(ofp, "Device Overhead");
504 output_dip_prep_ohead(ofp);
506 output_section_hdr(ofp, "Device Seek Information");
507 output_dip_seek_info(ofp);
512 void __output_ranges(FILE *ofp, struct list_head *head_p, float base)
514 struct range_info *rip;
516 float limit = base + 0.4;
518 __list_for_each(p, head_p) {
519 rip = list_entry(p, struct range_info, head);
520 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->start), base);
521 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->start), limit);
522 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->end), limit);
523 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->end), base);
527 int output_regions(FILE *ofp, char *header, struct region_info *reg,
530 if (reg->qr_cur != NULL)
531 list_add_tail(®->qr_cur->head, ®->qranges);
532 if (reg->cr_cur != NULL)
533 list_add_tail(®->cr_cur->head, ®->cranges);
535 if (list_len(®->qranges) == 0 && list_len(®->cranges) == 0)
538 fprintf(ofp, "# %16s : q activity\n", header);
539 __output_ranges(ofp, ®->qranges, base);
542 fprintf(ofp, "# %16s : c activity\n", header);
543 __output_ranges(ofp, ®->cranges, base + 0.5);
549 float __output_dev(FILE *ofp, struct d_info *dip, float base)
552 sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
553 if (output_regions(ofp, header, &dip->regions, base))
559 float output_devs(FILE *ofp, float base)
563 fprintf(ofp, "# Per device\n" );
564 if (devices == NULL) {
566 __list_for_each(p, &all_devs) {
567 dip = list_entry(p, struct d_info, head);
568 base = __output_dev(ofp, dip, base);
573 unsigned int mjr, mnr;
576 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
577 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
580 base = __output_dev(ofp, dip, base);
590 static inline int exe_match(char *exe, char *name)
592 return (exe == NULL) || (strstr(name, exe) != NULL);
595 float __output_procs(FILE *ofp, float base, char *match)
600 __list_for_each(p, &all_procs) {
601 pip = list_entry(p, struct p_info, head);
603 if (exe_match(match, pip->name) &&
604 output_regions(ofp, pip->name,
605 &pip->regions, base))
612 float output_procs(FILE *ofp, float base)
614 fprintf(ofp, "# Per process\n" );
616 base = __output_procs(ofp, base, NULL);
618 char *exe, *next, *p, *exes_save = strdup(exes);
621 while (exes_save != NULL) {
623 if ((next = strchr(exes_save, ',')) != NULL) {
630 base = __output_procs(ofp, base, exe);
638 int output_ranges(FILE *ofp)
642 fprintf(ofp, "# %s\n", "Total System");
643 if (output_regions(ofp, "Total System", &all_regions, base))
647 base = output_devs(ofp, base);
649 base = output_procs(ofp, base);