Home | History | Annotate | Download | only in btt
      1 /*
      2  * blktrace output analysis: generate a timeline & gather statistics
      3  *
      4  * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle (at) 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 <stdio.h>
     22 #include "globals.h"
     23 
     24 typedef struct avg_info *ai_dip_t;
     25 ai_dip_t dip_q2q_dm_avg(struct d_info *dip) { return &dip->avgs.q2q_dm; }
     26 ai_dip_t dip_q2a_dm_avg(struct d_info *dip) { return &dip->avgs.q2a_dm; }
     27 ai_dip_t dip_q2c_dm_avg(struct d_info *dip) { return &dip->avgs.q2c_dm; }
     28 
     29 ai_dip_t dip_q2q_avg(struct d_info *dip) { return &dip->avgs.q2q; }
     30 ai_dip_t dip_q2c_avg(struct d_info *dip) { return &dip->avgs.q2c; }
     31 ai_dip_t dip_q2a_avg(struct d_info *dip) { return &dip->avgs.q2a; }
     32 ai_dip_t dip_q2g_avg(struct d_info *dip) { return &dip->avgs.q2g; }
     33 ai_dip_t dip_s2g_avg(struct d_info *dip) { return &dip->avgs.s2g; }
     34 ai_dip_t dip_g2i_avg(struct d_info *dip) { return &dip->avgs.g2i; }
     35 ai_dip_t dip_q2m_avg(struct d_info *dip) { return &dip->avgs.q2m; }
     36 ai_dip_t dip_i2d_avg(struct d_info *dip) { return &dip->avgs.i2d; }
     37 ai_dip_t dip_d2c_avg(struct d_info *dip) { return &dip->avgs.d2c; }
     38 
     39 typedef struct avg_info *ai_pip_t;
     40 ai_pip_t pip_q2q_dm_avg(struct p_info *pip) { return &pip->avgs.q2q_dm; }
     41 ai_pip_t pip_q2a_dm_avg(struct p_info *pip) { return &pip->avgs.q2a_dm; }
     42 ai_pip_t pip_q2c_dm_avg(struct p_info *pip) { return &pip->avgs.q2c_dm; }
     43 
     44 ai_pip_t pip_q2q_avg(struct p_info *pip) { return &pip->avgs.q2q; }
     45 ai_pip_t pip_q2c_avg(struct p_info *pip) { return &pip->avgs.q2c; }
     46 ai_pip_t pip_q2a_avg(struct p_info *pip) { return &pip->avgs.q2a; }
     47 ai_pip_t pip_q2g_avg(struct p_info *pip) { return &pip->avgs.q2g; }
     48 ai_pip_t pip_s2g_avg(struct p_info *pip) { return &pip->avgs.s2g; }
     49 ai_pip_t pip_g2i_avg(struct p_info *pip) { return &pip->avgs.g2i; }
     50 ai_pip_t pip_q2m_avg(struct p_info *pip) { return &pip->avgs.q2m; }
     51 ai_pip_t pip_i2d_avg(struct p_info *pip) { return &pip->avgs.i2d; }
     52 ai_pip_t pip_d2c_avg(struct p_info *pip) { return &pip->avgs.d2c; }
     53 
     54 void output_section_hdr(FILE *ofp, char *hdr)
     55 {
     56 	fprintf(ofp, "==================== ");
     57 	fprintf(ofp, "%s", hdr);
     58 	fprintf(ofp, " ====================\n\n");
     59 }
     60 
     61 void output_hdr(FILE *ofp, char *hdr)
     62 {
     63 	fprintf(ofp, "%15s %13s %13s %13s %11s\n",
     64 	        hdr, "MIN", "AVG", "MAX", "N" );
     65 	fprintf(ofp, "--------------- ------------- ------------- ------------- -----------\n");
     66 }
     67 
     68 void __output_avg(FILE *ofp, char *hdr, struct avg_info *ap, int do_easy)
     69 {
     70 	if (ap->n > 0) {
     71 		ap->avg = BIT_TIME(ap->total) / (double)ap->n;
     72 		fprintf(ofp, "%-15s %13.9f %13.9f %13.9f %11d\n", hdr,
     73 			BIT_TIME(ap->min), ap->avg, BIT_TIME(ap->max), ap->n);
     74 
     75 		if (do_easy && easy_parse_avgs) {
     76 			fprintf(xavgs_ofp,
     77 				"%s %.9lf %.9lf %.9lf %d\n",
     78 				hdr, BIT_TIME(ap->min), ap->avg,
     79 						BIT_TIME(ap->max), ap->n);
     80 		}
     81 	}
     82 }
     83 
     84 static inline char *avg2string(struct avg_info *ap, char *string)
     85 {
     86 	if (ap->n > 0)
     87 		sprintf(string, "%13.9f", ap->avg);
     88 	else
     89 		sprintf(string, " ");
     90 	return string;
     91 }
     92 
     93 struct __oda {
     94 	FILE *ofp;
     95 	ai_dip_t (*func)(struct d_info *);
     96 };
     97 void __output_dip_avg(struct d_info *dip, void *arg)
     98 {
     99 	struct __oda *odap = arg;
    100 	ai_dip_t ap = odap->func(dip);
    101 	if (ap->n > 0) {
    102 		char dev_info[15];
    103 		ap->avg = BIT_TIME(ap->total) / (double)ap->n;
    104 		__output_avg(odap->ofp, make_dev_hdr(dev_info, 15, dip, 1),
    105 				ap, 0);
    106 	}
    107 }
    108 
    109 void output_dip_avg(FILE *ofp, char *hdr, ai_dip_t (*func)(struct d_info *))
    110 {
    111 	struct __oda oda = { .ofp = ofp, .func = func};
    112 	output_hdr(ofp, hdr);
    113 	dip_foreach_out(__output_dip_avg, &oda);
    114 	fprintf(ofp, "\n");
    115 }
    116 
    117 struct __q2d {
    118 	FILE *ofp;
    119 	void *q2d_all;
    120 	int n;
    121 };
    122 void __output_q2d_histo(struct d_info *dip, void *arg)
    123 {
    124 	struct __q2d *q2dp = arg;
    125 
    126 	if (q2d_ok(dip->q2d_priv)) {
    127 		char dev_info[15];
    128 		FILE *ofp = q2dp->ofp;
    129 
    130 		fprintf(q2dp->ofp, "%10s | ",
    131 					make_dev_hdr(dev_info, 15, dip, 1));
    132 		q2d_display(ofp, dip->q2d_priv);
    133 		q2d_acc(q2dp->q2d_all, dip->q2d_priv);
    134 		q2dp->n++;
    135 	}
    136 }
    137 
    138 void output_q2d_histo(FILE *ofp)
    139 {
    140 	struct __q2d __q2d = {
    141 		.ofp = ofp,
    142 		.q2d_all = q2d_alloc(),
    143 		.n = 0
    144 	};
    145 
    146 	fprintf(ofp, "%10s | ", "DEV");
    147 	q2d_display_header(ofp);
    148 	fprintf(ofp, "--------- | ");
    149 	q2d_display_dashes(ofp);
    150 	dip_foreach_out(__output_q2d_histo, &__q2d);
    151 
    152 	if (__q2d.n) {
    153 		fprintf(ofp, "========== | ");
    154 		q2d_display_dashes(ofp);
    155 		fprintf(ofp, "%10s | ", "AVG");
    156 		q2d_display(ofp, __q2d.q2d_all);
    157 		fprintf(ofp, "\n");
    158 	}
    159 
    160 	q2d_free(__q2d.q2d_all);
    161 }
    162 
    163 int n_merges = 0;
    164 struct {
    165 	unsigned long long nq, nd, blkmin, blkmax, total;
    166 } merge_data;
    167 void __output_dip_merge_ratio(struct d_info *dip, void *arg)
    168 {
    169 	double blks_avg;
    170 	char dev_info[15];
    171 	double ratio, q2c_n, d2c_n;
    172 
    173 	if (dip->n_qs == 0 || dip->n_ds == 0)
    174 		return;
    175 	else if (dip->n_qs < dip->n_ds)
    176 		dip->n_qs = dip->n_ds;
    177 
    178 	q2c_n = dip->n_qs;
    179 	d2c_n = dip->n_ds;
    180 	if (q2c_n > 0.0 && d2c_n > 0.0) {
    181 		if (q2c_n < d2c_n)
    182 			ratio = 1.0;
    183 		else
    184 			ratio = q2c_n / d2c_n;
    185 		blks_avg = (double)dip->avgs.blks.total / d2c_n;
    186 		fprintf((FILE *)arg,
    187 			"%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
    188 			make_dev_hdr(dev_info, 15, dip, 1),
    189 			(unsigned long long)dip->n_qs,
    190 			(unsigned long long)dip->n_ds,
    191 			ratio,
    192 			(unsigned long long)dip->avgs.blks.min,
    193 			(unsigned long long)blks_avg,
    194 			(unsigned long long)dip->avgs.blks.max,
    195 			(unsigned long long)dip->avgs.blks.total);
    196 
    197 		if (easy_parse_avgs) {
    198 			fprintf(xavgs_ofp,
    199 				"DMI %s %llu %llu %.9lf %llu %llu %llu %llu\n",
    200 				make_dev_hdr(dev_info, 15, dip, 0),
    201 				(unsigned long long)dip->n_qs,
    202 				(unsigned long long)dip->n_ds,
    203 				ratio,
    204 				(unsigned long long)dip->avgs.blks.min,
    205 				(unsigned long long)blks_avg,
    206 				(unsigned long long)dip->avgs.blks.max,
    207 				(unsigned long long)dip->avgs.blks.total);
    208 		}
    209 
    210 		if (n_merges++ == 0) {
    211 			merge_data.blkmin = dip->avgs.blks.min;
    212 			merge_data.blkmax = dip->avgs.blks.max;
    213 		}
    214 
    215 		merge_data.nq += dip->n_qs;
    216 		merge_data.nd += dip->n_ds;
    217 		merge_data.total += dip->avgs.blks.total;
    218 		if (dip->avgs.blks.min < merge_data.blkmin)
    219 			merge_data.blkmin = dip->avgs.blks.min;
    220 		if (dip->avgs.blks.max > merge_data.blkmax)
    221 			merge_data.blkmax = dip->avgs.blks.max;
    222 	}
    223 }
    224 
    225 void output_dip_merge_ratio(FILE *ofp)
    226 {
    227 	fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
    228 	fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
    229 	dip_foreach_out(__output_dip_merge_ratio, ofp);
    230 	if (n_merges > 1) {
    231 		fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
    232 		fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
    233 		fprintf((FILE *)ofp,
    234 			"%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
    235 			"TOTAL", merge_data.nq, merge_data.nd,
    236 			(float)merge_data.nq / (float)merge_data.nd,
    237 			merge_data.blkmin,
    238 			merge_data.total / merge_data.nd,
    239 			merge_data.blkmax, merge_data.total);
    240 	}
    241 	fprintf(ofp, "\n");
    242 }
    243 
    244 struct __ohead_data {
    245 	__u64 total;
    246 	int n;
    247 };
    248 
    249 struct ohead_data {
    250 	FILE *ofp;
    251 	struct __ohead_data q2g, g2i, q2m, i2d, d2c, q2c;
    252 };
    253 
    254 #define __update_odp(odp, dip, fld)					\
    255 	do {								\
    256 		(odp)-> fld .total += dip->avgs. fld . total;		\
    257 		(odp)-> fld .n     += dip->avgs. fld . n;		\
    258 	} while (0)
    259 
    260 void __output_dip_prep_ohead(struct d_info *dip, void *arg)
    261 {
    262 	if (dip->avgs.q2c.n > 0 && dip->avgs.q2c.total > 0) {
    263 		char dev_info[15];
    264 		struct ohead_data *odp = arg;
    265 		double q2c_total = (double)(dip->avgs.q2c.total);
    266 
    267 		fprintf(odp->ofp,
    268 			"%10s | %8.4lf%% %8.4lf%% %8.4lf%% %8.4lf%% %8.4lf%%\n",
    269 			make_dev_hdr(dev_info, 15, dip, 1),
    270 			100.0 * (double)(dip->avgs.q2g.total) / q2c_total,
    271 			100.0 * (double)(dip->avgs.g2i.total) / q2c_total,
    272 			100.0 * (double)(dip->avgs.q2m.total) / q2c_total,
    273 			100.0 * (double)(dip->avgs.i2d.total) / q2c_total,
    274 			100.0 * (double)(dip->avgs.d2c.total) / q2c_total);
    275 
    276 		__update_odp(odp, dip, q2g);
    277 		__update_odp(odp, dip, g2i);
    278 		__update_odp(odp, dip, q2m);
    279 		__update_odp(odp, dip, i2d);
    280 		__update_odp(odp, dip, d2c);
    281 		__update_odp(odp, dip, q2c);
    282 	}
    283 }
    284 
    285 #define OD_AVG(od, fld, q2c)						\
    286 	(od. fld .n == 0) ? (double)0.0 :				\
    287 		(100.0 * ((double)((od). fld . total) / q2c))
    288 
    289 void output_dip_prep_ohead(FILE *ofp)
    290 {
    291 	double q2c;
    292 	struct ohead_data od;
    293 
    294 	memset(&od, 0, sizeof(od));
    295 	od.ofp = ofp;
    296 
    297 	fprintf(ofp, "%10s | %9s %9s %9s %9s %9s\n",
    298 				"DEV", "Q2G", "G2I", "Q2M", "I2D", "D2C");
    299 	fprintf(ofp, "---------- | --------- --------- --------- --------- ---------\n");
    300 	dip_foreach_out(__output_dip_prep_ohead, &od);
    301 
    302 	if (od.q2g.n == 0 && od.g2i.n == 0 && od.q2m.n == 0 &&
    303 						od.i2d.n == 0 && od.d2c.n == 0)
    304 		goto out;
    305 
    306 	q2c = od.q2c.total;
    307 	fprintf(ofp, "---------- | --------- --------- --------- --------- ---------\n");
    308 	fprintf(ofp, "%10s | %8.4lf%% %8.4lf%% %8.4lf%% %8.4lf%% %8.4lf%%\n", "Overall",
    309 			OD_AVG(od, q2g, q2c), OD_AVG(od, g2i, q2c),
    310 			OD_AVG(od, q2m, q2c), OD_AVG(od, i2d, q2c),
    311 			OD_AVG(od, d2c, q2c));
    312 
    313 out:
    314 	fprintf(ofp, "\n");
    315 }
    316 
    317 struct seek_mode_info {
    318 	struct seek_mode_info *next;
    319 	long long mode;
    320 	int nseeks;
    321 };
    322 struct o_seek_info {
    323 	long long nseeks, median;
    324 	double mean;
    325 	struct seek_mode_info *head;
    326 } seek_info;
    327 int n_seeks;
    328 
    329 void output_seek_mode_info(FILE *ofp, struct o_seek_info *sip)
    330 {
    331 	struct seek_mode_info *p, *this, *new_list = NULL;
    332 
    333 	while ((this = sip->head) != NULL) {
    334 		sip->head = this->next;
    335 		this->next = NULL;
    336 
    337 		if (new_list == NULL || this->nseeks > new_list->nseeks)
    338 			new_list = this;
    339 		else if (this->nseeks == new_list->nseeks) {
    340 			for (p = new_list; p != NULL; p = p->next)
    341 				if (p->mode == this->mode)
    342 					break;
    343 
    344 			if (p)
    345 				this->nseeks += p->nseeks;
    346 			else
    347 				this->next = new_list;
    348 			new_list = this;
    349 		}
    350 	}
    351 
    352 	fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
    353 	        "Average", sip->nseeks, sip->mean / sip->nseeks,
    354 		sip->median / sip->nseeks, new_list->mode, new_list->nseeks);
    355 
    356 	if (new_list->next) {
    357 		int i = 0;
    358 		for (p = new_list->next; p != NULL; p = p->next)
    359 			i++;
    360 		fprintf(ofp, "\n%10s   %15s %15s %15s   ...(%d more)\n", "", "", "", "", i);
    361 	}
    362 }
    363 
    364 void add_seek_mode_info(struct o_seek_info *sip, struct mode *mp)
    365 {
    366 	int i;
    367 	long long *lp = mp->modes;
    368 	struct seek_mode_info *smip;
    369 
    370 	n_seeks++;
    371 	for (i = 0; i < mp->nmds; i++, lp++) {
    372 		for (smip = sip->head; smip; smip = smip->next) {
    373 			if (smip->mode == *lp) {
    374 				smip->nseeks += mp->most_seeks;
    375 				break;
    376 			}
    377 		}
    378 		if (!smip) {
    379 			struct seek_mode_info *new = malloc(sizeof(*new));
    380 
    381 			new->next = sip->head;
    382 			sip->head = new;
    383 			new->mode = *lp;
    384 			new->nseeks = mp->most_seeks;
    385 
    386 			add_buf(new);
    387 		}
    388 	}
    389 }
    390 
    391 static void do_output_dip_seek_info(struct d_info *dip, FILE *ofp, int is_q2q)
    392 {
    393 	double mean;
    394 	int i, nmodes;
    395 	long long nseeks;
    396 	char dev_info[15];
    397 	long long median;
    398 	struct mode m;
    399 	void *handle = is_q2q ? dip->q2q_handle : dip->seek_handle;
    400 
    401 	nseeks = seeki_nseeks(handle);
    402 	if (nseeks > 0) {
    403 		mean = seeki_mean(handle);
    404 		median = seeki_median(handle);
    405 		nmodes = seeki_mode(handle, &m);
    406 
    407 		fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
    408 			make_dev_hdr(dev_info, 15, dip, 1), nseeks, mean,
    409 			median, nmodes > 0 ? m.modes[0] : 0, m.most_seeks);
    410 		if (nmodes > 2)
    411 			fprintf(ofp, "\n%10s   %15s %15s %15s   ...(%d more)\n", "", "", "", "", nmodes-1);
    412 		else  {
    413 			for (i = 1; i < nmodes; i++)
    414 				fprintf(ofp, " %lld", m.modes[i]);
    415 			fprintf(ofp, "\n");
    416 		}
    417 
    418 		if (easy_parse_avgs) {
    419 			char *rec = is_q2q ? "QSK" : "DSK";
    420 			fprintf(xavgs_ofp,
    421 				"%s %s %lld %.9lf %lld %lld %d",
    422 				rec, make_dev_hdr(dev_info, 15, dip, 0),
    423 				nseeks, mean, median,
    424 				nmodes > 0 ? m.modes[0] : 0, m.most_seeks);
    425 				for (i = 1; i < nmodes; i++)
    426 					fprintf(xavgs_ofp, " %lld", m.modes[i]);
    427 				fprintf(xavgs_ofp, "\n");
    428 		}
    429 
    430 		seek_info.nseeks += nseeks;
    431 		seek_info.mean += (nseeks * mean);
    432 		seek_info.median += (nseeks * median);
    433 		add_seek_mode_info(&seek_info, &m);
    434 		free(m.modes);
    435 	}
    436 }
    437 
    438 void __output_dip_seek_info(struct d_info *dip, void *arg)
    439 {
    440 	do_output_dip_seek_info(dip, (FILE *)arg, 0);
    441 }
    442 
    443 void __output_dip_q2q_seek_info(struct d_info *dip, void *arg)
    444 {
    445 	do_output_dip_seek_info(dip, (FILE *)arg, 1);
    446 }
    447 
    448 void output_dip_seek_info(FILE *ofp)
    449 {
    450 	n_seeks = 1;
    451 	memset(&seek_info, 0, sizeof(seek_info));
    452 
    453 	fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS",
    454 			"MEAN", "MEDIAN", "MODE");
    455 	fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
    456 	dip_foreach_out(__output_dip_seek_info, ofp);
    457 	if (n_seeks > 1) {
    458 		fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
    459 		fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n",
    460 		        "Overall", "NSEEKS", "MEAN", "MEDIAN", "MODE");
    461 		output_seek_mode_info(ofp, &seek_info);
    462 		fprintf(ofp, "\n");
    463 	}
    464 	fprintf(ofp, "\n");
    465 }
    466 
    467 void output_dip_q2q_seek_info(FILE *ofp)
    468 {
    469 	n_seeks = 1;
    470 	memset(&seek_info, 0, sizeof(seek_info));
    471 
    472 	fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS",
    473 			"MEAN", "MEDIAN", "MODE");
    474 	fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
    475 	dip_foreach_out(__output_dip_q2q_seek_info, ofp);
    476 	if (n_seeks > 1) {
    477 		fprintf(ofp, "---------- | --------------- --------------- --------------- | ---------------\n");
    478 		fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n",
    479 		        "Overall", "NSEEKS", "MEAN", "MEDIAN", "MODE");
    480 		output_seek_mode_info(ofp, &seek_info);
    481 		fprintf(ofp, "\n");
    482 	}
    483 	fprintf(ofp, "\n");
    484 }
    485 
    486 struct __opa {
    487 	FILE *ofp;
    488 	ai_pip_t (*func)(struct p_info *);
    489 };
    490 
    491 void __output_pip_avg(struct p_info *pip, void *arg)
    492 {
    493 	struct __opa *opap = arg;
    494 	ai_pip_t ap = opap->func(pip);
    495 
    496 	if (ap->n > 0) {
    497 		char proc_name[15];
    498 		snprintf(proc_name, 15, "%s", pip->name);
    499 
    500 		ap->avg = BIT_TIME(ap->total) / (double)ap->n;
    501 		__output_avg(opap->ofp, proc_name, ap, 0);
    502 	}
    503 }
    504 
    505 void output_pip_avg(FILE *ofp, char *hdr, ai_pip_t (*func)(struct p_info *))
    506 {
    507 	struct __opa opa = { .ofp = ofp, .func = func };
    508 
    509 	output_hdr(ofp, hdr);
    510 	pip_foreach_out(__output_pip_avg, &opa);
    511 	fprintf(ofp, "\n");
    512 }
    513 
    514 int n_plugs;
    515 struct plug_info {
    516 	long n_plugs, n_unplugs_t;
    517 	double t_percent;
    518 } plug_info;
    519 
    520 void __dip_output_plug(struct d_info *dip, void *arg)
    521 {
    522 	char dev_info[15];
    523 	FILE *ofp = arg;
    524 	double delta, pct;
    525 
    526 	if (dip->is_plugged)
    527 		dip_unplug(dip->device, dip->end_time, 0);
    528 	if ((dip->nplugs + dip->nplugs_t) > 0) {
    529 		delta = dip->end_time - dip->start_time;
    530 		pct = 100.0 * (dip->plugged_time / delta);
    531 
    532 		fprintf(ofp, "%10s | %10d(%10d) | %13.9lf%%\n",
    533 			make_dev_hdr(dev_info, 15, dip, 1),
    534 			dip->nplugs, dip->nplugs_t, pct);
    535 
    536 		if (easy_parse_avgs) {
    537 			fprintf(xavgs_ofp,
    538 				"PLG %s %d %d %.9lf\n",
    539 				make_dev_hdr(dev_info, 15, dip, 0),
    540 				dip->nplugs, dip->nplugs_t, pct);
    541 		}
    542 
    543 		n_plugs++;
    544 		plug_info.n_plugs += dip->nplugs;
    545 		plug_info.n_unplugs_t += dip->nplugs_t;
    546 		plug_info.t_percent += pct;
    547 	}
    548 }
    549 
    550 void __dip_output_plug_all(FILE *ofp, struct plug_info *p)
    551 {
    552 	fprintf(ofp, "---------- | ---------- ----------  | ----------------\n");
    553 	fprintf(ofp, "%10s | %10s %10s  | %s\n",
    554 	        "Overall", "# Plugs", "# Timer Us", "% Time Q Plugged");
    555 	fprintf(ofp, "%10s | %10ld(%10ld) | %13.9lf%%\n", "Average",
    556 	        p->n_plugs / n_plugs, p->n_unplugs_t / n_plugs,
    557 		p->t_percent / n_plugs);
    558 
    559 }
    560 
    561 __u64 n_nios_uplugs, n_nios_uplugs_t;
    562 struct nios_plug_info {
    563 	__u64 tot_nios_up, tot_nios_up_t;
    564 } nios_plug_info;
    565 
    566 void __dip_output_plug_nios(struct d_info *dip, void *arg)
    567 {
    568 	char dev_info[15];
    569 	FILE *ofp = arg;
    570 	double a_nios_uplug = 0.0, a_nios_uplug_t = 0.0;
    571 
    572 	if (dip->nios_up && dip->nplugs) {
    573 		a_nios_uplug = (double)dip->nios_up / (double)dip->nplugs;
    574 		n_nios_uplugs += dip->nplugs;
    575 		nios_plug_info.tot_nios_up += dip->nios_up;
    576 	}
    577 	if (dip->nios_upt && dip->nplugs_t) {
    578 		a_nios_uplug_t = (double)dip->nios_upt / (double)dip->nplugs_t;
    579 		n_nios_uplugs_t += dip->nplugs_t;
    580 		nios_plug_info.tot_nios_up_t += dip->nios_upt;
    581 	}
    582 
    583 	fprintf(ofp, "%10s | %10.1lf   %10.1lf\n",
    584 		make_dev_hdr(dev_info, 15, dip, 1),
    585 		a_nios_uplug, a_nios_uplug_t);
    586 
    587 	if (easy_parse_avgs) {
    588 		fprintf(xavgs_ofp,
    589 			"UPG %s %.9lf %.9lf\n",
    590 			make_dev_hdr(dev_info, 15, dip, 0),
    591 			a_nios_uplug, a_nios_uplug_t);
    592 	}
    593 }
    594 
    595 void __dip_output_uplug_all(FILE *ofp, struct nios_plug_info *p)
    596 {
    597 	double ios_unp = 0.0, ios_unp_to = 0.0;
    598 
    599 	if (n_nios_uplugs)
    600 		ios_unp = (double)p->tot_nios_up / (double)n_nios_uplugs;
    601 	if (n_nios_uplugs_t)
    602 		ios_unp_to = (double)p->tot_nios_up_t / (double)n_nios_uplugs_t;
    603 
    604 	fprintf(ofp, "---------- | ----------   ----------\n");
    605 	fprintf(ofp, "%10s | %10s   %10s\n",
    606 		"Overall", "IOs/Unp", "IOs/Unp(to)");
    607 	fprintf(ofp, "%10s | %10.1lf   %10.1lf\n",
    608 		"Average", ios_unp, ios_unp_to);
    609 }
    610 
    611 void output_plug_info(FILE *ofp)
    612 {
    613 	fprintf(ofp, "%10s | %10s %10s  | %s\n",
    614 	        "DEV", "# Plugs", "# Timer Us", "% Time Q Plugged");
    615 	fprintf(ofp, "---------- | ---------- ----------  | ----------------\n");
    616 	dip_foreach_out(__dip_output_plug, ofp);
    617 	if (n_plugs > 1)
    618 		__dip_output_plug_all(ofp, &plug_info);
    619 	fprintf(ofp, "\n");
    620 
    621 	fprintf(ofp, "%10s | %10s   %10s\n",
    622 		"DEV", "IOs/Unp", "IOs/Unp(to)");
    623 	fprintf(ofp, "---------- | ----------   ----------\n");
    624 	dip_foreach_out(__dip_output_plug_nios, ofp);
    625 	if (n_nios_uplugs || n_nios_uplugs_t)
    626 		__dip_output_uplug_all(ofp, &nios_plug_info);
    627 	fprintf(ofp, "\n");
    628 }
    629 
    630 int n_actQs;
    631 struct actQ_info {
    632 	__u64 t_qs;
    633 	__u64 t_act_qs;
    634 } actQ_info;
    635 
    636 void __dip_output_actQ(struct d_info *dip, void *arg)
    637 {
    638 	if (dip->n_qs > 0 && !remapper_dev(dip->device)) {
    639 		char dev_info[15];
    640 		double a_actQs = (double)dip->t_act_q / (double)dip->n_qs;
    641 
    642 		fprintf((FILE *)arg, "%10s | %13.1lf\n",
    643 			make_dev_hdr(dev_info, 15, dip, 1), a_actQs);
    644 
    645 		if (easy_parse_avgs) {
    646 			fprintf(xavgs_ofp,
    647 				"ARQ %s %.9lf\n",
    648 				make_dev_hdr(dev_info, 15, dip, 0), a_actQs);
    649 		}
    650 
    651 		n_actQs++;
    652 		actQ_info.t_qs += dip->n_qs;
    653 		actQ_info.t_act_qs += dip->t_act_q;
    654 	}
    655 }
    656 
    657 void __dip_output_actQ_all(FILE *ofp, struct actQ_info *p)
    658 {
    659 	fprintf(ofp, "---------- | -------------\n");
    660 	fprintf(ofp, "%10s | %13s\n", "Overall", "Avgs Reqs @ Q");
    661 	fprintf(ofp, "%10s | %13.1lf\n", "Average",
    662 		(double)p->t_act_qs / (double)p->t_qs);
    663 }
    664 
    665 void output_actQ_info(FILE *ofp)
    666 {
    667 	fprintf(ofp, "%10s | %13s\n", "DEV", "Avg Reqs @ Q");
    668 	fprintf(ofp, "---------- | -------------\n");
    669 	dip_foreach_out(__dip_output_actQ, ofp);
    670 	if (n_actQs > 1)
    671 		__dip_output_actQ_all(ofp, &actQ_info);
    672 	fprintf(ofp, "\n");
    673 }
    674 
    675 void output_histos(void)
    676 {
    677 	int i;
    678 	FILE *ofp;
    679 	char fname[256];
    680 
    681 	if (output_name == NULL) return;
    682 
    683 	sprintf(fname, "%s_qhist.dat", output_name);
    684 	ofp = my_fopen(fname, "w");
    685 	if (!ofp) {
    686 		perror(fname);
    687 		return;
    688 	}
    689 
    690 	fprintf(ofp, "# BTT histogram data\n");
    691 	fprintf(ofp, "# Q buckets\n");
    692 	for (i = 0; i < (N_HIST_BKTS-1); i++)
    693 		fprintf(ofp, "%4d %lld\n", (i+1), (long long)q_histo[i]);
    694 	fprintf(ofp, "\n# Q bucket for > %d\n%4d %lld\n", (int)N_HIST_BKTS-1,
    695 		N_HIST_BKTS-1, (long long)q_histo[N_HIST_BKTS-1]);
    696 	fclose(ofp);
    697 
    698 	sprintf(fname, "%s_dhist.dat", output_name);
    699 	ofp = my_fopen(fname, "w");
    700 	if (!ofp) {
    701 		perror(fname);
    702 		return;
    703 	}
    704 	fprintf(ofp, "# D buckets\n");
    705 	for (i = 0; i < (N_HIST_BKTS-1); i++)
    706 		fprintf(ofp, "%4d %lld\n", (i+1), (long long)d_histo[i]);
    707 	fprintf(ofp, "\n# D bucket for > %d\n%4d %lld\n", (int)N_HIST_BKTS-1,
    708 		N_HIST_BKTS-1, (long long)d_histo[N_HIST_BKTS-1]);
    709 	fclose(ofp);
    710 }
    711 
    712 int output_avgs(FILE *ofp)
    713 {
    714 	if (output_all_data) {
    715 		if (exes == NULL || *exes != '\0') {
    716 			output_section_hdr(ofp, "Per Process");
    717 			output_pip_avg(ofp, "Q2Qdm", pip_q2q_dm_avg);
    718 			output_pip_avg(ofp, "Q2Adm", pip_q2a_dm_avg);
    719 			output_pip_avg(ofp, "Q2Cdm", pip_q2c_dm_avg);
    720 			fprintf(ofp, "\n");
    721 
    722 			output_pip_avg(ofp, "Q2Q", pip_q2q_avg);
    723 			output_pip_avg(ofp, "Q2A", pip_q2a_avg);
    724 			output_pip_avg(ofp, "Q2G", pip_q2g_avg);
    725 			output_pip_avg(ofp, "S2G", pip_s2g_avg);
    726 			output_pip_avg(ofp, "G2I", pip_g2i_avg);
    727 			output_pip_avg(ofp, "Q2M", pip_q2m_avg);
    728 			output_pip_avg(ofp, "I2D", pip_i2d_avg);
    729 			output_pip_avg(ofp, "D2C", pip_d2c_avg);
    730 			output_pip_avg(ofp, "Q2C", pip_q2c_avg);
    731 		}
    732 
    733 		output_section_hdr(ofp, "Per Device");
    734 		output_dip_avg(ofp, "Q2Qdm", dip_q2q_dm_avg);
    735 		output_dip_avg(ofp, "Q2Adm", dip_q2a_dm_avg);
    736 		output_dip_avg(ofp, "Q2Cdm", dip_q2c_dm_avg);
    737 		fprintf(ofp, "\n");
    738 
    739 		output_dip_avg(ofp, "Q2Q", dip_q2q_avg);
    740 		output_dip_avg(ofp, "Q2A", dip_q2a_avg);
    741 		output_dip_avg(ofp, "Q2G", dip_q2g_avg);
    742 		output_dip_avg(ofp, "S2G", dip_s2g_avg);
    743 		output_dip_avg(ofp, "G2I", dip_g2i_avg);
    744 		output_dip_avg(ofp, "Q2M", dip_q2m_avg);
    745 		output_dip_avg(ofp, "I2D", dip_i2d_avg);
    746 		output_dip_avg(ofp, "D2C", dip_d2c_avg);
    747 		output_dip_avg(ofp, "Q2C", dip_q2c_avg);
    748 	}
    749 
    750 	output_section_hdr(ofp, "All Devices");
    751 	output_hdr(ofp, "ALL");
    752 	__output_avg(ofp, "Q2Qdm", &all_avgs.q2q_dm, 0);
    753 	__output_avg(ofp, "Q2Adm", &all_avgs.q2a_dm, 0);
    754 	__output_avg(ofp, "Q2Cdm", &all_avgs.q2c_dm, 0);
    755 	fprintf(ofp, "\n");
    756 
    757 	__output_avg(ofp, "Q2Q", &all_avgs.q2q, 1);
    758 	__output_avg(ofp, "Q2A", &all_avgs.q2a, 1);
    759 	__output_avg(ofp, "Q2G", &all_avgs.q2g, 1);
    760 	__output_avg(ofp, "S2G", &all_avgs.s2g, 1);
    761 	__output_avg(ofp, "G2I", &all_avgs.g2i, 1);
    762 	__output_avg(ofp, "Q2M", &all_avgs.q2m, 1);
    763 	__output_avg(ofp, "I2D", &all_avgs.i2d, 1);
    764 	__output_avg(ofp, "M2D", &all_avgs.m2d, 1);
    765 	__output_avg(ofp, "D2C", &all_avgs.d2c, 1);
    766 	__output_avg(ofp, "Q2C", &all_avgs.q2c, 1);
    767 	fprintf(ofp, "\n");
    768 
    769 	output_section_hdr(ofp, "Device Overhead");
    770 	output_dip_prep_ohead(ofp);
    771 
    772 	output_section_hdr(ofp, "Device Merge Information");
    773 	output_dip_merge_ratio(ofp);
    774 
    775 	output_section_hdr(ofp, "Device Q2Q Seek Information");
    776 	output_dip_q2q_seek_info(ofp);
    777 
    778 	output_section_hdr(ofp, "Device D2D Seek Information");
    779 	output_dip_seek_info(ofp);
    780 
    781 	output_section_hdr(ofp, "Plug Information");
    782 	output_plug_info(ofp);
    783 
    784 	output_section_hdr(ofp, "Active Requests At Q Information");
    785 	output_actQ_info(ofp);
    786 
    787 	output_histos();
    788 
    789 	if (output_all_data) {
    790 		output_section_hdr(ofp, "Q2D Histogram");
    791 		output_q2d_histo(ofp);
    792 	}
    793 
    794 	return 0;
    795 }
    796 
    797 void __output_ranges(FILE *ofp, struct list_head *head_p, float base)
    798 {
    799 	struct range_info *rip;
    800 	struct list_head *p;
    801 	float limit = base + 0.4;
    802 
    803 	__list_for_each(p, head_p) {
    804 		rip = list_entry(p, struct range_info, head);
    805 		fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->start), base);
    806 		fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->start), limit);
    807 		fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->end), limit);
    808 		fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->end), base);
    809 	}
    810 }
    811 
    812 int output_regions(FILE *ofp, char *header, struct region_info *reg,
    813 			  float base)
    814 {
    815 	if (list_len(&reg->qranges) == 0 && list_len(&reg->cranges) == 0)
    816 		return 0;
    817 
    818 	fprintf(ofp, "# %16s : q activity\n", header);
    819 	__output_ranges(ofp, &reg->qranges, base);
    820 	fprintf(ofp, "\n");
    821 
    822 	fprintf(ofp, "# %16s : c activity\n", header);
    823 	__output_ranges(ofp, &reg->cranges, base + 0.5);
    824 	fprintf(ofp, "\n");
    825 
    826 	return 1;
    827 }
    828 
    829 struct __od {
    830 	FILE *ofp;
    831 	float base;
    832 };
    833 void __output_dev(struct d_info *dip, void *arg)
    834 {
    835 	char header[128];
    836 	struct __od *odp = arg;
    837 
    838 	sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
    839 	if (output_regions(odp->ofp, header, &dip->regions, odp->base))
    840 		odp->base += 1.0;
    841 }
    842 
    843 float output_devs(FILE *ofp, float base)
    844 {
    845 	struct __od od = { .ofp = ofp, .base = base };
    846 
    847 	fprintf(ofp, "# Per device\n" );
    848 	dip_foreach_out(__output_dev, &od);
    849 	return od.base;
    850 }
    851 
    852 static inline int exe_match(char *exe, char *name)
    853 {
    854 	return (exe == NULL) || (strstr(name, exe) != NULL);
    855 }
    856 
    857 struct __op {
    858 	FILE *ofp;
    859 	float base;
    860 };
    861 void __output_procs(struct p_info *pip, void *arg)
    862 {
    863 	struct __op *opp = arg;
    864 	output_regions(opp->ofp, pip->name, &pip->regions, opp->base);
    865 	opp->base += 1.0;
    866 }
    867 
    868 float output_procs(FILE *ofp, float base)
    869 {
    870 	struct __op op = { .ofp = ofp, .base = base };
    871 
    872 	fprintf(ofp, "# Per process\n" );
    873 	pip_foreach_out(__output_procs, &op);
    874 	return op.base;
    875 }
    876 
    877 int output_ranges(FILE *ofp)
    878 {
    879 	float base = 0.0;
    880 
    881 	fprintf(ofp, "# %s\n", "Total System");
    882 	if (output_regions(ofp, "Total System", &all_regions, base))
    883 		base += 1.0;
    884 
    885 	if (n_devs > 1)
    886 		base = output_devs(ofp, base);
    887 
    888 	base = output_procs(ofp, base);
    889 
    890 	return 0;
    891 }
    892