[PATCH] Added store_barrier() for S390
[blktrace.git] / btt / output.c
CommitLineData
63eba147
JA
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
24typedef struct avg_info *ai_dip_t;
25ai_dip_t dip_q2q_avg(struct d_info *dip) { return &dip->avgs.q2q; }
26ai_dip_t dip_q2c_avg(struct d_info *dip) { return &dip->avgs.q2c; }
27ai_dip_t dip_q2a_avg(struct d_info *dip) { return &dip->avgs.q2a; }
28ai_dip_t dip_q2i_avg(struct d_info *dip) { return &dip->avgs.q2i; }
29ai_dip_t dip_i2d_avg(struct d_info *dip) { return &dip->avgs.i2d; }
30ai_dip_t dip_d2c_avg(struct d_info *dip) { return &dip->avgs.d2c; }
31
32typedef struct avg_info *ai_pip_t;
33ai_pip_t pip_q2q_avg(struct p_info *pip) { return &pip->avgs.q2q; }
34ai_pip_t pip_q2c_avg(struct p_info *pip) { return &pip->avgs.q2c; }
35ai_pip_t pip_q2a_avg(struct p_info *pip) { return &pip->avgs.q2a; }
36ai_pip_t pip_q2i_avg(struct p_info *pip) { return &pip->avgs.q2i; }
37ai_pip_t pip_i2d_avg(struct p_info *pip) { return &pip->avgs.i2d; }
38ai_pip_t pip_d2c_avg(struct p_info *pip) { return &pip->avgs.d2c; }
39
40void output_section_hdr(FILE *ofp, char *hdr)
41{
42 fprintf(ofp, "==================== ");
43 fprintf(ofp, hdr);
44 fprintf(ofp, " ====================\n\n");
45}
46
47void output_hdr(FILE *ofp, char *hdr)
48{
49 fprintf(ofp, "%12s %13s %13s %13s %11s\n",
50 hdr, "MIN", "AVG", "MAX", "N" );
51 fprintf(ofp, "------------ ------------- ------------- ------------- -----------\n");
52}
53
54void __output_avg(FILE *ofp, char *hdr, struct avg_info *ap)
55{
56 if (ap->n > 0) {
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);
60 }
61}
62
63void output_hdr2(FILE *ofp, char*hdr)
64{
65 fprintf(ofp, "%12s %13s %13s %13s %13s %13s %13s\n", hdr, "Q2Q", "Q2A", "Q2I", "I2D", "D2C", "Q2C");
66 fprintf(ofp, "------------ ------------- ------------- ------------- ------------- ------------- -------------\n");
67}
68
69static inline char *avg2string(struct avg_info *ap, char *string)
70{
71 if (ap->n > 0)
72 sprintf(string, "%13.9f", ap->avg);
73 else
74 sprintf(string, " ");
75 return string;
76}
77
78void __output_avg2(FILE *ofp, char *hdr, struct avgs_info *ap)
79{
80 char c1[16], c2[16], c3[16], c4[16], c5[16], c6[16];
81
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));
88 }
89}
90
91char *make_dev_hdr(char *pad, size_t len, struct d_info *dip)
92{
93 if (dip->map == NULL) {
94 snprintf(pad, len, "(%3d,%3d)",
95 MAJOR(dip->device), MINOR(dip->device));
96 }
97 else {
98 snprintf(pad, len, "[%3d,%3d]",
99 dip->map->host, dip->map->target);
100 }
101
102 return pad;
103}
104
105void __output_dip_avg(FILE *ofp, struct d_info *dip, struct avg_info *ap)
106{
107 if (ap->n > 0) {
108 char dev_info[12];
109 ap->avg = BIT_TIME(ap->total) / (double)ap->n;
110 __output_avg(ofp, make_dev_hdr(dev_info, 12, dip), ap);
111 }
112}
113
114void output_dip_avg(FILE *ofp, char *hdr, ai_dip_t (*func)(struct d_info *))
115{
116 struct d_info *dip;
117
118 output_hdr(ofp, hdr);
119 if (devices == NULL) {
120 struct list_head *p;
121
122 __list_for_each(p, &all_devs) {
123 dip = list_entry(p, struct d_info, head);
124 __output_dip_avg(ofp, dip, func(dip));
125 }
126 }
127 else {
128 int i;
129 unsigned int mjr, mnr;
130 char *p = devices;
131
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));
135
136 p = strchr(p, ';');
137 if (p) p++;
138 }
139 }
140
141 fprintf(ofp, "\n");
142}
143
144void __output_dip_merge_ratio(FILE *ofp, struct d_info *dip)
145{
146 double blks_avg;
147 char scratch[12];
148 double ratio, q2c_n = dip->avgs.q2c.n, d2c_n = dip->n_ds;
149
150 if (q2c_n > 0.0 && d2c_n > 0.0) {
151 ratio = q2c_n / d2c_n;
9f11c1a7 152 blks_avg = (double)dip->avgs.blks.total / d2c_n;
63eba147
JA
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,
157 ratio,
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);
162
163 }
164}
165
166void output_dip_merge_ratio(FILE *ofp)
167{
168 struct d_info *dip;
169
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) {
173 struct list_head *p;
174
175 __list_for_each(p, &all_devs) {
176 dip = list_entry(p, struct d_info, head);
177 __output_dip_merge_ratio(ofp, dip);
178 }
179 }
180 else {
181 int i;
182 unsigned int mjr, mnr;
183 char *p = devices;
184
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);
188
189 p = strchr(p, ';');
190 if (p) p++;
191 }
192 }
193
194 fprintf(ofp, "\n");
195}
196
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) / \
200 (double)(ap)->n))
201char *q2i_v_q2C(struct d_info *dip, char *s)
202{
203 double q2c;
204
205 if (dip->avgs.q2i.n == 0) return " ";
206
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));
209
210 return s;
211}
212
213char *i2d_v_q2C(struct d_info *dip, char *s)
214{
215 double q2c;
216
217 if (dip->avgs.i2d.n == 0) return " ";
218
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));
221
222 return s;
223}
224
225char *d2c_v_q2C(struct d_info *dip, char *s)
226{
227 double q2c;
228
aa994ec5 229 if (dip->avgs.d2c.n == 0) return " ";
63eba147
JA
230
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));
233
234 return s;
235}
236
237void __output_dip_prep_ohead(FILE *ofp, struct d_info *dip)
238{
239 char dev_info[12];
240 char s1[16], s2[16], s3[16];
241
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);
247
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),
251 d2c_v_q2C(dip, s3));
252 }
253}
254
255void output_dip_prep_ohead(FILE *ofp)
256{
257 struct d_info *dip;
258
259 fprintf(ofp, "%10s | %6s %6s %6s\n", "DEV", "Q2I", "I2D", "D2C");
260 fprintf(ofp, "---------- | ------ ------ ------\n");
261
262 if (devices == NULL) {
263 struct list_head *p;
264
265 __list_for_each(p, &all_devs) {
266 dip = list_entry(p, struct d_info, head);
267 __output_dip_prep_ohead(ofp, dip);
268 }
269 }
270 else {
271 int i;
272 unsigned int mjr, mnr;
273 char *p = devices;
274
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);
278
279 p = strchr(p, ';');
280 if (p) p++;
281 }
282 }
283
284 fprintf(ofp, "\n");
285}
286
287void __output_pip_avg(FILE *ofp, struct p_info *pip, struct avg_info *ap)
288{
289 if (ap->n > 0) {
290 char proc_name[12];
291 snprintf(proc_name, 12, pip->name);
292
293 ap->avg = BIT_TIME(ap->total) / (double)ap->n;
294 __output_avg(ofp, proc_name, ap);
295 }
296}
297
298void output_pip_avg(FILE *ofp, char *hdr, ai_pip_t (*func)(struct p_info *))
299{
300 struct p_info *pip;
301
302 output_hdr(ofp, hdr);
303 if (exes == NULL) {
304 struct list_head *p;
305
306 __list_for_each(p, &all_procs) {
307 pip = list_entry(p, struct p_info, head);
308 __output_pip_avg(ofp, pip, func(pip));
309 }
310 }
311 else {
312 char *exe, *p, *next, *exes_save = strdup(exes);
313
314 p = exes_save;
315 while (exes_save != NULL) {
316 exe = exes_save;
317 if ((next = strchr(exes_save, ',')) != NULL) {
318 *next = '\0';
319 exes_save = next+1;
320 }
321 else
322 exes_save = NULL;
323
324 pip = find_process((__u32)-1, exe);
325 if (pip)
326 __output_pip_avg(ofp, pip, func(pip));
327 }
328 }
329
330 fprintf(ofp, "\n");
331}
332
333void output_dip_avgs(FILE *ofp)
334{
335 char dev_info[12];
336 struct d_info *dip;
337
338 output_hdr2(ofp,"Dev");
339 if (devices == NULL) {
340 struct list_head *p;
341
342 __list_for_each(p, &all_devs) {
343 dip = list_entry(p, struct d_info, head);
344 __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
345 &dip->avgs);
346 }
347 }
348 else {
349 int i;
350 unsigned int mjr, mnr;
351 char *p = devices;
352
353 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
354 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
355 __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
356 &dip->avgs);
357
358 p = strchr(p, ';');
359 if (p) p++;
360 }
361 }
362
363 fprintf(ofp, "\n");
364}
365
366void output_pip_avgs(FILE *ofp)
367{
368 char exe[16];
369 struct p_info *pip;
370
371 output_hdr2(ofp,"Exe");
372 if (exes == NULL) {
373 struct list_head *p;
374
375 __list_for_each(p, &all_procs) {
376 pip = list_entry(p, struct p_info, head);
377 snprintf(exe, 12, pip->name);
378 __output_avg2(ofp, exe, &pip->avgs);
379 }
380 }
381 else {
382 char *exe, *p, *next, *exes_save = strdup(exes);
383
384 p = exes_save;
385 while (exes_save != NULL && *exes_save != '\0') {
386 exe = exes_save;
387 if ((next = strchr(exes_save, ',')) != NULL) {
388 *next = '\0';
389 exes_save = next+1;
390 }
391 else
392 exes_save = NULL;
393
394 pip = find_process((__u32)-1, exe);
395 if (pip) {
396 snprintf(exe, 12, pip->name);
397 __output_avg2(ofp, exe, &pip->avgs);
398 }
399 }
400 }
401
402 fprintf(ofp, "\n");
403}
404
405int output_avgs(FILE *ofp)
406{
407 if (exes == NULL || *exes != '\0') {
408 output_section_hdr(ofp, "Per Process");
409 output_pip_avg(ofp, "Q2Q", pip_q2q_avg);
410 output_pip_avg(ofp, "Q2A", pip_q2a_avg);
411 output_pip_avg(ofp, "Q2I", pip_q2i_avg);
412 output_pip_avg(ofp, "I2D", pip_i2d_avg);
413 output_pip_avg(ofp, "D2C", pip_d2c_avg);
414 output_pip_avg(ofp, "Q2C", pip_q2c_avg);
415 }
416
417 output_section_hdr(ofp, "Per Device");
418 output_dip_avg(ofp, "Q2Q", dip_q2q_avg);
419 output_dip_avg(ofp, "Q2A", dip_q2a_avg);
420 output_dip_avg(ofp, "Q2I", dip_q2i_avg);
421 output_dip_avg(ofp, "I2D", dip_i2d_avg);
422 output_dip_avg(ofp, "D2C", dip_d2c_avg);
423 output_dip_avg(ofp, "Q2C", dip_q2c_avg);
424
425 output_section_hdr(ofp, "All Devices");
426 output_hdr(ofp, "ALL");
427 __output_avg(ofp, "Q2Q", &all_avgs.q2q);
428 __output_avg(ofp, "Q2A", &all_avgs.q2a);
429 __output_avg(ofp, "Q2I", &all_avgs.q2i);
430 __output_avg(ofp, "I2D", &all_avgs.i2d);
431 __output_avg(ofp, "D2C", &all_avgs.d2c);
432 __output_avg(ofp, "Q2C", &all_avgs.q2c);
433
434 if (exes == NULL || *exes != '\0') {
435 output_section_hdr(ofp, "Per Process (avgs)");
436 output_pip_avgs(ofp);
437 }
438
439 output_section_hdr(ofp, "Per Device (avgs)");
440 output_dip_avgs(ofp);
441
442 output_section_hdr(ofp, "Device Merge Information");
443 output_dip_merge_ratio(ofp);
444
445 output_section_hdr(ofp, "Device Overhead");
446 output_dip_prep_ohead(ofp);
447
448 return 0;
449}
450
451void __output_ranges(FILE *ofp, struct list_head *head_p, float base)
452{
453 struct range_info *rip;
454 struct list_head *p;
455 float limit = base + 0.4;
456
457 __list_for_each(p, head_p) {
458 rip = list_entry(p, struct range_info, head);
459 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->start), base);
460 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->start), limit);
461 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->end), limit);
462 fprintf(ofp, "%13.9lf %5.1f\n", BIT_TIME(rip->end), base);
463 }
464}
465
466int output_regions(FILE *ofp, char *header, struct region_info *reg,
467 float base)
468{
469 if (reg->qr_cur != NULL)
470 list_add_tail(&reg->qr_cur->head, &reg->qranges);
471 if (reg->cr_cur != NULL)
472 list_add_tail(&reg->cr_cur->head, &reg->cranges);
473
474 if (list_len(&reg->qranges) == 0 && list_len(&reg->cranges) == 0)
475 return 0;
476
477 fprintf(ofp, "# %16s : q activity\n", header);
478 __output_ranges(ofp, &reg->qranges, base);
479 fprintf(ofp, "\n");
480
481 fprintf(ofp, "# %16s : c activity\n", header);
482 __output_ranges(ofp, &reg->cranges, base + 0.5);
483 fprintf(ofp, "\n");
484
485 return 1;
486}
487
488float __output_dev(FILE *ofp, struct d_info *dip, float base)
489{
490 char header[128];
491 sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
492 if (output_regions(ofp, header, &dip->regions, base))
493 base += 1.0;
494
495 return base;
496}
497
498float output_devs(FILE *ofp, float base)
499{
500 struct d_info *dip;
501
502 fprintf(ofp, "# Per device\n" );
503 if (devices == NULL) {
504 struct list_head *p;
505 __list_for_each(p, &all_devs) {
506 dip = list_entry(p, struct d_info, head);
507 base = __output_dev(ofp, dip, base);
508 }
509 }
510 else {
511 int i;
512 unsigned int mjr, mnr;
513 char *p = devices;
514
515 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
516 dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
517 ASSERT(dip);
518
519 base = __output_dev(ofp, dip, base);
520
521 p = strchr(p, ';');
522 if (p) p++;
523 }
524 }
525
526 return base;
527}
528
529static inline int exe_match(char *exe, char *name)
530{
531 return (exe == NULL) || (strstr(name, exe) != NULL);
532}
533
534float __output_procs(FILE *ofp, float base, char *match)
535{
536 struct p_info *pip;
537 struct list_head *p;
538
539 __list_for_each(p, &all_procs) {
540 pip = list_entry(p, struct p_info, head);
541
542 if (exe_match(match, pip->name) &&
543 output_regions(ofp, pip->name,
544 &pip->regions, base))
545 base += 1.0;
546 }
547
548 return base;
549}
550
551float output_procs(FILE *ofp, float base)
552{
553 fprintf(ofp, "# Per process\n" );
554 if (exes == NULL)
555 base = __output_procs(ofp, base, NULL);
556 else {
557 char *exe, *next, *p, *exes_save = strdup(exes);
558
559 p = exes_save;
560 while (exes_save != NULL) {
561 exe = exes_save;
562 if ((next = strchr(exes_save, ',')) != NULL) {
563 *next = '\0';
564 exes_save = next+1;
565 }
566 else
567 exes_save = NULL;
568
569 base = __output_procs(ofp, base, exe);
570 }
571 free(p);
572 }
573
574 return base;
575}
576
577int output_ranges(FILE *ofp)
578{
579 float base = 0.0;
580
581 fprintf(ofp, "# %s\n", "Total System");
582 if (output_regions(ofp, "Total System", &all_regions, base))
583 base += 1.0;
584
585 if (n_devs > 1)
586 base = output_devs(ofp, base);
587
588 base = output_procs(ofp, base);
589
590 return 0;
591}