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