iowatcher: Make sure we add the xtick labels if we're only plotting IO
[blktrace.git] / iowatcher / main.c
CommitLineData
9e066e23
CM
1/*
2 * Copyright (C) 2012 Fusion-io
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Parts of this file were imported from Jens Axboe's blktrace sources (also GPL)
18 */
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <unistd.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <math.h>
26#include <inttypes.h>
27#include <string.h>
28#include <asm/types.h>
29#include <errno.h>
30#include <sys/mman.h>
31#include <time.h>
32#include <math.h>
33#include <getopt.h>
d140b434
JK
34#include <limits.h>
35#include <float.h>
9e066e23
CM
36
37#include "plot.h"
38#include "blkparse.h"
39#include "list.h"
40#include "tracers.h"
e199d546 41#include "mpstat.h"
9e066e23
CM
42
43LIST_HEAD(all_traces);
44
ba758825
CM
45static char line[1024];
46static int line_len = 1024;
e199d546
CM
47static int found_mpstat = 0;
48static int cpu_color_index = 0;
9e066e23 49static int color_index = 0;
ba758825
CM
50static int make_movie = 0;
51static int opt_graph_width = 0;
52static int opt_graph_height = 0;
53
cc3d54d5 54static int columns = 1;
a78b574c 55static int num_xticks = 7;
1e1e3f04 56static int num_yticks = 4;
cc3d54d5 57
d140b434
JK
58static double min_time = 0;
59static double max_time = DBL_MAX;
60static unsigned long long min_mb = 0;
61static unsigned long long max_mb = ULLONG_MAX >> 20;
62
f2e40ddd
JK
63int plot_io_action = 0;
64
cc3d54d5
CM
65/*
66 * this doesn't include the IO graph,
67 * but it counts the other graphs as they go out
68 */
69static int total_graphs_written = 1;
70
9e066e23
CM
71char *colors[] = {
72 "blue", "darkgreen",
73 "red", "aqua",
74 "orange", "darkviolet",
75 "brown", "#00FF00",
76 "yellow", "coral",
77 "black", "darkred",
78 "fuchsia", "crimson",
79 NULL };
80
81char *pick_color(void) {
82 char *ret = colors[color_index];
83 if (!ret) {
84 color_index = 0;
85 ret = colors[color_index];
86 }
87 color_index++;
88 return ret;
89}
90
91char *pick_cpu_color(void) {
e199d546 92 char *ret = colors[cpu_color_index];
9e066e23
CM
93 if (!ret) {
94 color_index = 0;
e199d546 95 ret = colors[cpu_color_index];
9e066e23 96 }
e199d546 97 cpu_color_index++;
9e066e23
CM
98 return ret;
99}
100
101enum {
102 IO_GRAPH_INDEX = 0,
103 TPUT_GRAPH_INDEX,
e199d546
CM
104 CPU_SYS_GRAPH_INDEX,
105 CPU_IO_GRAPH_INDEX,
106 CPU_IRQ_GRAPH_INDEX,
107 CPU_SOFT_GRAPH_INDEX,
108 CPU_USER_GRAPH_INDEX,
9e066e23
CM
109 LATENCY_GRAPH_INDEX,
110 QUEUE_DEPTH_GRAPH_INDEX,
111 IOPS_GRAPH_INDEX,
112 TOTAL_GRAPHS
113};
114
e199d546
CM
115enum {
116 MPSTAT_SYS = 0,
117 MPSTAT_IRQ,
118 MPSTAT_IO,
119 MPSTAT_SOFT,
120 MPSTAT_USER,
121 MPSTAT_GRAPHS
122};
123
9e066e23
CM
124static char *graphs_by_name[] = {
125 "io",
126 "tput",
e199d546
CM
127 "cpu-sys",
128 "cpu-io",
129 "cpu-irq",
130 "cpu-soft",
131 "cpu-user",
9e066e23
CM
132 "latency",
133 "queue-depth",
134 "iops",
135};
136
abf08f96
CM
137enum {
138 MOVIE_SPINDLE,
139 MOVIE_RECT,
140 NUM_MOVIE_STYLES,
141};
142
143char *movie_styles[] = {
144 "spindle",
145 "rect",
146 NULL
147};
148
149static int movie_style = 0;
150
151static int lookup_movie_style(char *str)
152{
153 int i;
154
155 for (i = 0; i < NUM_MOVIE_STYLES; i++) {
156 if (strcmp(str, movie_styles[i]) == 0)
157 return i;
158 }
159 return -1;
160}
161
9e066e23
CM
162static int active_graphs[TOTAL_GRAPHS];
163static int last_active_graph = IOPS_GRAPH_INDEX;
164
165static int label_index = 0;
166static int num_traces = 0;
167static int longest_label = 0;
168
169struct trace_file {
170 struct list_head list;
171 char *filename;
172 char *label;
173 struct trace *trace;
230f0601
JK
174 int stop_seconds; /* Time when trace stops */
175 int min_seconds; /* Beginning of the interval we should plot */
176 int max_seconds; /* End of the interval we should plot */
9b9fa04b 177 u64 min_offset;
9e066e23
CM
178 u64 max_offset;
179
180 char *read_color;
181 char *write_color;
182
183 struct graph_line_data *tput_gld;
184 struct graph_line_data *iop_gld;
185 struct graph_line_data *latency_gld;
186 struct graph_line_data *queue_depth_gld;
187 struct graph_dot_data *gdd_writes;
188 struct graph_dot_data *gdd_reads;
e199d546 189
230f0601 190 int mpstat_min_seconds;
f752a6eb 191 int mpstat_max_seconds;
e199d546
CM
192 int mpstat_stop_seconds;
193 struct graph_line_data **mpstat_gld;
9e066e23
CM
194};
195
e199d546
CM
196static void alloc_mpstat_gld(struct trace_file *tf)
197{
198 struct graph_line_data **ptr;
199
200 if (tf->trace->mpstat_num_cpus == 0)
201 return;
202
203 ptr = calloc((tf->trace->mpstat_num_cpus + 1) * MPSTAT_GRAPHS,
204 sizeof(struct graph_line_data *));
205 if (!ptr) {
206 perror("Unable to allocate mpstat arrays\n");
207 exit(1);
208 }
209 tf->mpstat_gld = ptr;
210}
211
9e066e23
CM
212static void enable_all_graphs(void)
213{
214 int i;
215 for (i = 0; i < TOTAL_GRAPHS; i++)
216 active_graphs[i] = 1;
217}
218
219static void disable_all_graphs(void)
220{
221 int i;
222 for (i = 0; i < TOTAL_GRAPHS; i++)
223 active_graphs[i] = 0;
224}
225
226static int enable_one_graph(char *name)
227{
228 int i;
229 for (i = 0; i < TOTAL_GRAPHS; i++) {
230 if (strcmp(name, graphs_by_name[i]) == 0) {
231 active_graphs[i] = 1;
232 return 0;
233 }
234 }
235 return -ENOENT;
236}
237
238static int disable_one_graph(char *name)
239{
240 int i;
241 for (i = 0; i < TOTAL_GRAPHS; i++) {
242 if (strcmp(name, graphs_by_name[i]) == 0) {
243 active_graphs[i] = 0;
244 return 0;
245 }
246 }
247 return -ENOENT;
248}
249
250static int last_graph(void)
251{
252 int i;
253 for (i = TOTAL_GRAPHS - 1; i >= 0; i--) {
254 if (active_graphs[i]) {
255 return i;
256 }
257 }
258 return -ENOENT;
259}
cc3d54d5
CM
260
261static int graphs_left(int cur)
262{
263 int i;
264 int left = 0;
265 for (i = cur; i < TOTAL_GRAPHS; i++) {
266 if (active_graphs[i])
267 left++;
268 }
269 return left;
270}
271
9e066e23
CM
272static void add_trace_file(char *filename)
273{
274 struct trace_file *tf;
275
276 tf = calloc(1, sizeof(*tf));
277 if (!tf) {
278 fprintf(stderr, "Unable to allocate memory\n");
279 exit(1);
280 }
e199d546 281 tf->label = "";
9e066e23
CM
282 tf->filename = strdup(filename);
283 list_add_tail(&tf->list, &all_traces);
284 tf->read_color = pick_color();
285 tf->write_color = pick_color();
286 num_traces++;
287}
288
289static void setup_trace_file_graphs(void)
290{
291 struct trace_file *tf;
e199d546 292 int i;
9e066e23
CM
293
294 list_for_each_entry(tf, &all_traces, list) {
230f0601
JK
295 tf->tput_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
296 tf->latency_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
297 tf->queue_depth_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
298 tf->iop_gld = alloc_line_data(tf->min_seconds, tf->max_seconds, tf->stop_seconds);
299 tf->gdd_writes = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds);
300 tf->gdd_reads = alloc_dot_data(tf->min_seconds, tf->max_seconds, tf->min_offset, tf->max_offset, tf->stop_seconds);
e199d546
CM
301
302 if (tf->trace->mpstat_num_cpus == 0)
303 continue;
304
305 alloc_mpstat_gld(tf);
306 for (i = 0; i < (tf->trace->mpstat_num_cpus + 1) * MPSTAT_GRAPHS; i++) {
307 tf->mpstat_gld[i] =
230f0601
JK
308 alloc_line_data(tf->mpstat_min_seconds,
309 tf->mpstat_max_seconds,
f752a6eb 310 tf->mpstat_max_seconds);
e199d546
CM
311 tf->mpstat_gld[i]->max = 100;
312 }
9e066e23
CM
313 }
314}
315
316static void read_traces(void)
317{
318 struct trace_file *tf;
319 struct trace *trace;
320 u64 last_time;
321 u64 ymin;
322 u64 ymax;
bfb0e441
CM
323 u64 max_bank;
324 u64 max_bank_offset;
9e066e23
CM
325
326 list_for_each_entry(tf, &all_traces, list) {
327 trace = open_trace(tf->filename);
328 if (!trace)
329 exit(1);
330
331 last_time = find_last_time(trace);
332 tf->trace = trace;
f752a6eb 333 tf->max_seconds = SECONDS(last_time);
9e066e23 334 tf->stop_seconds = SECONDS(last_time);
9b9fa04b
JK
335 find_extreme_offsets(trace, &tf->min_offset, &tf->max_offset,
336 &max_bank, &max_bank_offset);
337 filter_outliers(trace, tf->min_offset, tf->max_offset, &ymin, &ymax);
338 tf->min_offset = ymin;
9e066e23 339 tf->max_offset = ymax;
e199d546
CM
340
341 read_mpstat(trace, tf->filename);
342 tf->mpstat_stop_seconds = trace->mpstat_seconds;
f752a6eb
JK
343 tf->mpstat_max_seconds = trace->mpstat_seconds;
344 if (tf->mpstat_max_seconds)
e199d546 345 found_mpstat = 1;
9e066e23
CM
346 }
347}
348
349static void read_trace_events(void)
350{
351
352 struct trace_file *tf;
353 struct trace *trace;
354 int ret;
e199d546
CM
355 int i;
356 int time;
357 double user, sys, iowait, irq, soft;
358 double max_user = 0, max_sys = 0, max_iowait = 0,
359 max_irq = 0, max_soft = 0;
9e066e23
CM
360
361 list_for_each_entry(tf, &all_traces, list) {
362 trace = tf->trace;
363 first_record(trace);
364 while (1) {
365 check_record(trace);
366 add_tput(trace, tf->tput_gld);
367 add_iop(trace, tf->iop_gld);
368 add_io(trace, tf->gdd_writes, tf->gdd_reads);
369 add_pending_io(trace, tf->queue_depth_gld);
370 add_completed_io(trace, tf->latency_gld);
371 ret = next_record(trace);
372 if (ret)
373 break;
374 }
375 }
e199d546
CM
376 list_for_each_entry(tf, &all_traces, list) {
377 trace = tf->trace;
378
379 if (trace->mpstat_num_cpus == 0)
380 continue;
381
382 first_mpstat(trace);
383
384 for (time = 0; time < tf->mpstat_stop_seconds; time ++) {
385 for (i = 0; i < (trace->mpstat_num_cpus + 1) * MPSTAT_GRAPHS; i += MPSTAT_GRAPHS) {
386 ret = read_mpstat_event(trace, &user, &sys,
387 &iowait, &irq, &soft);
388 if (ret)
389 goto mpstat_done;
390 if (next_mpstat_line(trace))
391 goto mpstat_done;
392
393 if (sys > max_sys)
394 max_sys = sys;
395 if (user > max_user)
396 max_user = user;
397 if (irq > max_irq)
398 max_irq = irq;
399 if (iowait > max_iowait)
400 max_iowait = iowait;
401
402 add_mpstat_gld(time, sys, tf->mpstat_gld[i + MPSTAT_SYS]);
403 add_mpstat_gld(time, irq, tf->mpstat_gld[i + MPSTAT_IRQ]);
404 add_mpstat_gld(time, soft, tf->mpstat_gld[i + MPSTAT_SOFT]);
405 add_mpstat_gld(time, user, tf->mpstat_gld[i + MPSTAT_USER]);
406 add_mpstat_gld(time, iowait, tf->mpstat_gld[i + MPSTAT_IO]);
407 }
408 if (next_mpstat(trace) == NULL)
409 break;
410 }
411 }
412
413mpstat_done:
414 list_for_each_entry(tf, &all_traces, list) {
415 trace = tf->trace;
416
417 if (trace->mpstat_num_cpus == 0)
418 continue;
419
420 tf->mpstat_gld[MPSTAT_SYS]->max = max_sys;
421 tf->mpstat_gld[MPSTAT_IRQ]->max = max_irq;
422 tf->mpstat_gld[MPSTAT_SOFT]->max = max_soft;
423 tf->mpstat_gld[MPSTAT_USER]->max = max_user;
424 tf->mpstat_gld[MPSTAT_IO]->max = max_iowait;;
425 }
426 return;
9e066e23
CM
427}
428
429static void set_trace_label(char *label)
430{
431 int cur = 0;
432 struct trace_file *tf;
433 int len = strlen(label);
434
435 if (len > longest_label)
436 longest_label = len;
437
438 list_for_each_entry(tf, &all_traces, list) {
439 if (cur == label_index) {
440 tf->label = strdup(label);
441 label_index++;
442 break;
443 }
444 cur++;
445 }
446}
447
448static char *graph_title = "";
449static char *output_filename = "trace.svg";
450static char *blktrace_device = NULL;
451static char *blktrace_outfile = "trace";
452static char *blktrace_dest_dir = ".";
453static char *program_to_run = NULL;
454
455static void set_blktrace_outfile(char *arg)
456{
457 char *s = strdup(arg);
458 char *last_dot = strrchr(s, '.');
459
460 if (last_dot) {
461 if (strcmp(last_dot, ".dump") == 0)
462 *last_dot = '\0';
463 }
464 blktrace_outfile = s;
465}
466
467
f752a6eb 468static void compare_minmax_tf(struct trace_file *tf, int *max_seconds, u64 *min_offset, u64 *max_offset)
9e066e23 469{
f752a6eb
JK
470 if (tf->max_seconds > *max_seconds)
471 *max_seconds = tf->max_seconds;
ba758825
CM
472 if (tf->max_offset > *max_offset)
473 *max_offset = tf->max_offset;
9b9fa04b
JK
474 if (tf->min_offset < *min_offset)
475 *min_offset = tf->min_offset;
9e066e23
CM
476}
477
230f0601 478static void set_all_minmax_tf(int min_seconds, int max_seconds, u64 min_offset, u64 max_offset)
9e066e23 479{
ba758825 480 struct trace_file *tf;
9e066e23 481
ba758825 482 list_for_each_entry(tf, &all_traces, list) {
230f0601 483 tf->min_seconds = min_seconds;
f752a6eb 484 tf->max_seconds = max_seconds;
d140b434
JK
485 if (tf->stop_seconds > max_seconds)
486 tf->stop_seconds = max_seconds;
487 if (tf->mpstat_max_seconds) {
488 tf->mpstat_min_seconds = min_seconds;
489 tf->mpstat_max_seconds = max_seconds;
490 if (tf->mpstat_stop_seconds > max_seconds)
491 tf->mpstat_stop_seconds = max_seconds;
492 }
9b9fa04b 493 tf->min_offset = min_offset;
ba758825
CM
494 tf->max_offset = max_offset;
495 }
496}
9e066e23 497
ba758825
CM
498static char *create_movie_temp_dir(void)
499{
500 char *ret;
abf08f96 501 char *pattern = strdup("io-movie-XXXXXX");;
9e066e23 502
ba758825
CM
503 ret = mkdtemp(pattern);
504 if (!ret) {
505 perror("Unable to create temp directory for movie files");
506 exit(1);
507 }
508 return ret;
509}
9e066e23 510
ba758825
CM
511static struct plot_history *alloc_plot_history(char *color)
512{
513 struct plot_history *ph = calloc(1, sizeof(struct plot_history));
514
515 if (!ph) {
516 perror("memory allocation failed");
517 exit(1);
9e066e23 518 }
ba758825
CM
519 ph->history = calloc(4096, sizeof(double));
520 if (!ph->history) {
521 perror("memory allocation failed");
522 exit(1);
523 }
524 ph->history_len = 4096;
525 ph->color = color;
526 return ph;
9e066e23
CM
527}
528
ba758825
CM
529LIST_HEAD(movie_history_writes);
530LIST_HEAD(movie_history_reads);
531int num_histories = 0;
532
533static void add_history(struct plot_history *ph, struct list_head *list)
9e066e23 534{
ba758825
CM
535 struct plot_history *entry;
536
537 list_add_tail(&ph->list, list);
538 num_histories++;
539
540 if (num_histories > 12) {
541 num_histories--;
542 entry = list_entry(list->next, struct plot_history, list);
543 list_del(&entry->list);
544 free(entry->history);
545 free(entry);
546 }
9e066e23
CM
547}
548
ba758825 549static void plot_movie_history(struct plot *plot, struct list_head *list)
9e066e23 550{
ba758825
CM
551 struct plot_history *ph;
552
abf08f96
CM
553 if (num_histories > 2)
554 rewind_spindle_steps(num_histories - 1);
555
ba758825 556 list_for_each_entry(ph, list, list) {
abf08f96
CM
557 if (movie_style == MOVIE_SPINDLE)
558 svg_io_graph_movie_array_spindle(plot, ph);
559 else
560 svg_io_graph_movie_array(plot, ph);
ba758825
CM
561 }
562}
9e066e23 563
ba758825
CM
564static void free_all_plot_history(struct list_head *head)
565{
566 struct plot_history *entry;
567 while (!list_empty(head)) {
568 entry = list_entry(head->next, struct plot_history, list);
569 list_del(&entry->list);
570 free(entry->history);
571 free(entry);
9e066e23
CM
572 }
573}
574
230f0601 575static void plot_io(struct plot *plot, int min_seconds, int max_seconds, u64 min_offset, u64 max_offset)
9e066e23
CM
576{
577 struct trace_file *tf;
578
cc3d54d5
CM
579 if (active_graphs[IO_GRAPH_INDEX] == 0)
580 return;
581
9e066e23
CM
582 setup_axis(plot);
583
584 svg_alloc_legend(plot, num_traces * 2);
585
586 set_plot_label(plot, "Device IO");
587 set_ylabel(plot, "Offset (MB)");
a78b574c 588 set_yticks(plot, num_yticks, min_offset / (1024 * 1024),
9b9fa04b 589 max_offset / (1024 * 1024), "");
230f0601 590 set_xticks(plot, num_xticks, min_seconds, max_seconds);
9e066e23
CM
591
592 list_for_each_entry(tf, &all_traces, list) {
593 char *label = tf->label;
594
595 if (!label)
596 label = "";
597 svg_io_graph(plot, tf->gdd_reads, tf->read_color);
598 if (tf->gdd_reads->total_ios)
599 svg_add_legend(plot, label, " Reads", tf->read_color);
600
601 svg_io_graph(plot, tf->gdd_writes, tf->write_color);
602 if (tf->gdd_writes->total_ios) {
603 svg_add_legend(plot, label, " Writes", tf->write_color);
604 }
605 }
606 if (plot->add_xlabel)
607 set_xlabel(plot, "Time (seconds)");
608 svg_write_legend(plot);
609 close_plot(plot);
610}
611
230f0601 612static void plot_tput(struct plot *plot, int min_seconds, int max_seconds)
9e066e23
CM
613{
614 struct trace_file *tf;
615 char *units;
616 char line[128];
617 u64 max = 0;
618
cc3d54d5
CM
619 if (active_graphs[TPUT_GRAPH_INDEX] == 0)
620 return;
621
9e066e23
CM
622 if (num_traces > 1)
623 svg_alloc_legend(plot, num_traces);
624 list_for_each_entry(tf, &all_traces, list) {
625 if (tf->tput_gld->max > max)
626 max = tf->tput_gld->max;
627 }
628 list_for_each_entry(tf, &all_traces, list)
629 tf->tput_gld->max = max;
630
9e066e23
CM
631 setup_axis(plot);
632 set_plot_label(plot, "Throughput");
633
634 tf = list_entry(all_traces.next, struct trace_file, list);
635
636 scale_line_graph_bytes(&max, &units, 1024);
637 sprintf(line, "%sB/s", units);
638 set_ylabel(plot, line);
1e1e3f04 639 set_yticks(plot, num_yticks, 0, max, "");
230f0601 640 set_xticks(plot, num_xticks, min_seconds, max_seconds);
9e066e23
CM
641
642 list_for_each_entry(tf, &all_traces, list) {
bfb0e441 643 svg_line_graph(plot, tf->tput_gld, tf->read_color, 0, 0);
9e066e23
CM
644 if (num_traces > 1)
645 svg_add_legend(plot, tf->label, "", tf->read_color);
646 }
647
648 if (plot->add_xlabel)
649 set_xlabel(plot, "Time (seconds)");
650 if (num_traces > 1)
651 svg_write_legend(plot);
652 close_plot(plot);
cc3d54d5 653 total_graphs_written++;
9e066e23
CM
654}
655
f752a6eb 656static void plot_cpu(struct plot *plot, int max_seconds, char *label,
8ed9516f
CM
657 int active_index, int gld_index)
658{
659 struct trace_file *tf;
660 int max = 0;
661 int i;
662 int gld_i;
663 char *color;
664 double avg = 0;
665 int ymax;
666 int plotted = 0;
667
cc3d54d5
CM
668 if (active_graphs[active_index] == 0)
669 return;
670
8ed9516f
CM
671 list_for_each_entry(tf, &all_traces, list) {
672 if (tf->trace->mpstat_num_cpus > max)
673 max = tf->trace->mpstat_num_cpus;
674 }
675 if (max == 0)
cc3d54d5 676 return;
8ed9516f
CM
677
678 tf = list_entry(all_traces.next, struct trace_file, list);
679
680 ymax = tf->mpstat_gld[gld_index]->max;
681 if (ymax == 0)
cc3d54d5 682 return;
8ed9516f
CM
683
684 svg_alloc_legend(plot, num_traces * max);
685
8ed9516f
CM
686 setup_axis(plot);
687 set_plot_label(plot, label);
688
f752a6eb 689 max_seconds = tf->mpstat_max_seconds;
8ed9516f 690
1e1e3f04 691 set_yticks(plot, num_yticks, 0, tf->mpstat_gld[gld_index]->max, "");
8ed9516f 692 set_ylabel(plot, "Percent");
230f0601 693 set_xticks(plot, num_xticks, tf->mpstat_min_seconds, max_seconds);
8ed9516f
CM
694
695 cpu_color_index = 0;
696 list_for_each_entry(tf, &all_traces, list) {
1e1e3f04
CM
697 if (tf->mpstat_gld == 0)
698 break;
230f0601
JK
699 for (i = tf->mpstat_gld[0]->min_seconds;
700 i < tf->mpstat_gld[0]->stop_seconds; i++) {
8ed9516f
CM
701 if (tf->mpstat_gld[gld_index]->data[i].count) {
702 avg += (tf->mpstat_gld[gld_index]->data[i].sum /
703 tf->mpstat_gld[gld_index]->data[i].count);
704 }
705 }
230f0601
JK
706 avg /= tf->mpstat_gld[gld_index]->stop_seconds -
707 tf->mpstat_gld[gld_index]->min_seconds;
8ed9516f
CM
708 color = pick_cpu_color();
709 svg_line_graph(plot, tf->mpstat_gld[0], color, 0, 0);
710 svg_add_legend(plot, tf->label, " avg", color);
711
712 for (i = 1; i < tf->trace->mpstat_num_cpus + 1; i++) {
713 struct graph_line_data *gld = tf->mpstat_gld[i * MPSTAT_GRAPHS + gld_index];
714 double this_avg = 0;
715
230f0601
JK
716 for (gld_i = gld->min_seconds;
717 gld_i < gld->stop_seconds; gld_i++) {
f5f8c982
CM
718 if (gld->data[i].count) {
719 this_avg += gld->data[i].sum /
720 gld->data[i].count;
721 }
722 }
8ed9516f 723
230f0601 724 this_avg /= gld->stop_seconds - gld->min_seconds;
8ed9516f 725
230f0601
JK
726 for (gld_i = gld->min_seconds;
727 gld_i < gld->stop_seconds; gld_i++) {
8ed9516f
CM
728 double val;
729
730 if (gld->data[gld_i].count == 0)
731 continue;
732 val = (double)gld->data[gld_i].sum /
733 gld->data[gld_i].count;
734
735 if (this_avg > avg + 30 || val > 95) {
736 color = pick_cpu_color();
737 svg_line_graph(plot, gld, color, avg + 30, 95);
738 snprintf(line, line_len, " CPU %d\n", i - 1);
739 svg_add_legend(plot, tf->label, line, color);
740 plotted++;
741 break;
742 }
743
744 }
745 }
746 }
747
748 if (plot->add_xlabel)
749 set_xlabel(plot, "Time (seconds)");
750
751 if (!plot->no_legend) {
752 svg_write_legend(plot);
753 svg_free_legend(plot);
754 }
cc3d54d5
CM
755 close_plot(plot);
756 total_graphs_written++;
8ed9516f
CM
757}
758
230f0601 759static void plot_queue_depth(struct plot *plot, int min_seconds, int max_seconds)
8ed9516f
CM
760{
761 struct trace_file *tf;
762
cc3d54d5
CM
763 if (active_graphs[QUEUE_DEPTH_GRAPH_INDEX] == 0)
764 return;
8ed9516f
CM
765
766 setup_axis(plot);
767 set_plot_label(plot, "Queue Depth");
768 if (num_traces > 1)
769 svg_alloc_legend(plot, num_traces);
770
771 tf = list_entry(all_traces.next, struct trace_file, list);
772 set_ylabel(plot, "Pending IO");
1e1e3f04 773 set_yticks(plot, num_yticks, 0, tf->queue_depth_gld->max, "");
230f0601 774 set_xticks(plot, num_xticks, min_seconds, max_seconds);
8ed9516f
CM
775
776 list_for_each_entry(tf, &all_traces, list) {
777 svg_line_graph(plot, tf->queue_depth_gld, tf->read_color, 0, 0);
778 if (num_traces > 1)
779 svg_add_legend(plot, tf->label, "", tf->read_color);
780 }
781
782 if (plot->add_xlabel)
783 set_xlabel(plot, "Time (seconds)");
784 if (num_traces > 1)
785 svg_write_legend(plot);
8ed9516f 786 close_plot(plot);
cc3d54d5 787 total_graphs_written++;
8ed9516f
CM
788}
789
ba758825
CM
790static void convert_movie_files(char *movie_dir)
791{
792 fprintf(stderr, "Converting svg files in %s\n", movie_dir);
793 snprintf(line, line_len, "find %s -name \\*.svg | xargs -I{} -n 1 -P 8 rsvg-convert -o {}.png {}",
794 movie_dir);
795 system(line);
796}
797
798static void mencode_movie(char *movie_dir)
799{
800 fprintf(stderr, "Creating movie %s\n", movie_dir);
abf08f96 801 snprintf(line, line_len, "ffmpeg -r 20 -y -i %s/%%10d-%s.svg.png -b:v 250k "
7a147342 802 "-vcodec libx264 %s", movie_dir, output_filename, output_filename);
ba758825
CM
803 system(line);
804}
805
806static void cleanup_movie(char *movie_dir)
807{
808 fprintf(stderr, "Removing movie dir %s\n", movie_dir);
809 snprintf(line, line_len, "rm %s/*", movie_dir);
810 system(line);
811
812 snprintf(line, line_len, "rmdir %s", movie_dir);
813 system(line);
814}
815
816static void plot_io_movie(struct plot *plot)
817{
818 struct trace_file *tf;
819 char *movie_dir = create_movie_temp_dir();
820 int i;
821 struct plot_history *read_history;
822 struct plot_history *write_history;
823 int batch_i;
824 int movie_len = 30;
abf08f96 825 int movie_frames_per_sec = 20;
ba758825
CM
826 int total_frames = movie_len * movie_frames_per_sec;
827 int rows, cols;
828 int batch_count;
8ed9516f
CM
829 int graph_width_factor = 5;
830 int orig_y_offset;
ba758825
CM
831
832 get_graph_size(&cols, &rows);
833 batch_count = cols / total_frames;
834
835 if (batch_count == 0)
836 batch_count = 1;
837
838 list_for_each_entry(tf, &all_traces, list) {
839 char *label = tf->label;
840 if (!label)
841 label = "";
842
843 i = 0;
844 while (i < cols) {
845 snprintf(line, line_len, "%s/%010d-%s.svg", movie_dir, i, output_filename);
846 set_plot_output(plot, line);
ba758825 847 set_plot_title(plot, graph_title);
8ed9516f
CM
848 orig_y_offset = plot->start_y_offset;
849
850 plot->no_legend = 1;
851
852 set_graph_size(cols / graph_width_factor, rows / 8);
cc3d54d5 853 plot->timeline = i / graph_width_factor;
8ed9516f 854
230f0601
JK
855 plot_tput(plot, tf->gdd_reads->min_seconds,
856 tf->gdd_reads->max_seconds);
8ed9516f 857
f752a6eb 858 plot_cpu(plot, tf->gdd_reads->max_seconds,
cc3d54d5 859 "CPU System Time", CPU_SYS_GRAPH_INDEX, MPSTAT_SYS);
8ed9516f 860
cc3d54d5 861 plot->direction = PLOT_ACROSS;
230f0601
JK
862 plot_queue_depth(plot, tf->gdd_reads->min_seconds,
863 tf->gdd_reads->max_seconds);
8ed9516f
CM
864
865 /* movie graph starts here */
866 plot->start_y_offset = orig_y_offset;
867 set_graph_size(cols - cols / graph_width_factor, rows);
868 plot->no_legend = 0;
cc3d54d5
CM
869 plot->timeline = 0;
870 plot->direction = PLOT_DOWN;;
8ed9516f 871
abf08f96
CM
872 if (movie_style == MOVIE_SPINDLE)
873 setup_axis_spindle(plot);
874 else
875 setup_axis(plot);
876
ba758825
CM
877 svg_alloc_legend(plot, num_traces * 2);
878
879 read_history = alloc_plot_history(tf->read_color);
880 write_history = alloc_plot_history(tf->write_color);
881 read_history->col = i;
882 write_history->col = i;
883
884 if (tf->gdd_reads->total_ios)
885 svg_add_legend(plot, label, " Reads", tf->read_color);
886 if (tf->gdd_writes->total_ios)
887 svg_add_legend(plot, label, " Writes", tf->write_color);
888
889 batch_i = 0;
890 while (i < cols && batch_i < batch_count) {
ba758825 891 svg_io_graph_movie(tf->gdd_reads, read_history, i);
ba758825
CM
892 svg_io_graph_movie(tf->gdd_writes, write_history, i);
893 i++;
894 batch_i++;
895 }
896
897 add_history(read_history, &movie_history_reads);
898 add_history(write_history, &movie_history_writes);
899
900 plot_movie_history(plot, &movie_history_reads);
901 plot_movie_history(plot, &movie_history_writes);
902
903 svg_write_legend(plot);
904 close_plot(plot);
ba758825 905 close_plot(plot);
ba758825 906
abf08f96 907 close_plot_file(plot);
ba758825
CM
908 }
909 free_all_plot_history(&movie_history_reads);
910 free_all_plot_history(&movie_history_writes);
911 }
912 convert_movie_files(movie_dir);
913 mencode_movie(movie_dir);
914 cleanup_movie(movie_dir);
915 free(movie_dir);
916}
917
230f0601 918static void plot_latency(struct plot *plot, int min_seconds, int max_seconds)
9e066e23
CM
919{
920 struct trace_file *tf;
921 char *units;
922 char line[128];
923 u64 max = 0;
924
925 if (active_graphs[LATENCY_GRAPH_INDEX] == 0)
926 return;
927
928 if (num_traces > 1)
929 svg_alloc_legend(plot, num_traces);
1e1e3f04 930
9e066e23
CM
931 list_for_each_entry(tf, &all_traces, list) {
932 if (tf->latency_gld->max > max)
933 max = tf->latency_gld->max;
934 }
1e1e3f04 935
9e066e23
CM
936 list_for_each_entry(tf, &all_traces, list)
937 tf->latency_gld->max = max;
938
9e066e23
CM
939 setup_axis(plot);
940 set_plot_label(plot, "IO Latency");
941
942 tf = list_entry(all_traces.next, struct trace_file, list);
943
944 scale_line_graph_time(&max, &units);
945 sprintf(line, "latency (%ss)", units);
946 set_ylabel(plot, line);
1e1e3f04 947 set_yticks(plot, num_yticks, 0, max, "");
230f0601 948 set_xticks(plot, num_xticks, min_seconds, max_seconds);
9e066e23
CM
949
950 list_for_each_entry(tf, &all_traces, list) {
bfb0e441 951 svg_line_graph(plot, tf->latency_gld, tf->read_color, 0, 0);
9e066e23
CM
952 if (num_traces > 1)
953 svg_add_legend(plot, tf->label, "", tf->read_color);
954 }
955
956 if (plot->add_xlabel)
957 set_xlabel(plot, "Time (seconds)");
958 if (num_traces > 1)
959 svg_write_legend(plot);
960 close_plot(plot);
cc3d54d5 961 total_graphs_written++;
9e066e23
CM
962}
963
230f0601 964static void plot_iops(struct plot *plot, int min_seconds, int max_seconds)
9e066e23
CM
965{
966 struct trace_file *tf;
967 char *units;
968 u64 max = 0;
969
970 if (active_graphs[IOPS_GRAPH_INDEX] == 0)
971 return;
972
973 list_for_each_entry(tf, &all_traces, list) {
974 if (tf->iop_gld->max > max)
975 max = tf->iop_gld->max;
976 }
977
978 list_for_each_entry(tf, &all_traces, list)
979 tf->iop_gld->max = max;
980
9e066e23
CM
981 setup_axis(plot);
982 set_plot_label(plot, "IOPs");
983 if (num_traces > 1)
984 svg_alloc_legend(plot, num_traces);
985
986 tf = list_entry(all_traces.next, struct trace_file, list);
987
988 scale_line_graph_bytes(&max, &units, 1000);
989 set_ylabel(plot, "IO/s");
990
1e1e3f04 991 set_yticks(plot, num_yticks, 0, max, units);
230f0601 992 set_xticks(plot, num_xticks, min_seconds, max_seconds);
9e066e23
CM
993
994 list_for_each_entry(tf, &all_traces, list) {
bfb0e441 995 svg_line_graph(plot, tf->iop_gld, tf->read_color, 0, 0);
9e066e23
CM
996 if (num_traces > 1)
997 svg_add_legend(plot, tf->label, "", tf->read_color);
998 }
999
1000 if (plot->add_xlabel)
1001 set_xlabel(plot, "Time (seconds)");
1002 if (num_traces > 1)
1003 svg_write_legend(plot);
1004
1005 close_plot(plot);
cc3d54d5
CM
1006 total_graphs_written++;
1007}
1008
1009static void check_plot_columns(struct plot *plot, int index)
1010{
1011 int count;
1012
1013 if (columns > 1 && (total_graphs_written == 0 ||
1014 total_graphs_written % columns != 0)) {
1015 count = graphs_left(index);
1016 if (plot->direction == PLOT_DOWN) {
1017 plot->start_x_offset = 0;
1018 if (count <= columns)
1019 plot->add_xlabel = 1;
1020 }
1021 plot->direction = PLOT_ACROSS;
1022
1023 } else {
1024 plot->direction = PLOT_DOWN;
1025 if (index == last_active_graph)
1026 plot->add_xlabel = 1;
1027 }
1028
9e066e23
CM
1029}
1030
ba758825
CM
1031enum {
1032 HELP_LONG_OPT = 1,
1033};
1034
f2e40ddd 1035char *option_string = "T:t:o:l:r:O:N:d:p:m::h:w:c:x:y:a:";
ba758825 1036static struct option long_options[] = {
cc3d54d5 1037 {"columns", required_argument, 0, 'c'},
ba758825
CM
1038 {"title", required_argument, 0, 'T'},
1039 {"trace", required_argument, 0, 't'},
1040 {"output", required_argument, 0, 'o'},
1041 {"label", required_argument, 0, 'l'},
1042 {"rolling", required_argument, 0, 'r'},
1043 {"no-graph", required_argument, 0, 'N'},
1044 {"only-graph", required_argument, 0, 'O'},
1045 {"device", required_argument, 0, 'd'},
1046 {"prog", required_argument, 0, 'p'},
abf08f96 1047 {"movie", optional_argument, 0, 'm'},
ba758825
CM
1048 {"width", required_argument, 0, 'w'},
1049 {"height", required_argument, 0, 'h'},
d140b434
JK
1050 {"xzoom", required_argument, 0, 'x'},
1051 {"yzoom", required_argument, 0, 'y'},
f2e40ddd 1052 {"io-plot-action", required_argument, 0, 'a'},
5a870f23 1053 {"help", no_argument, 0, HELP_LONG_OPT},
ba758825
CM
1054 {0, 0, 0, 0}
1055};
1056
1057static void print_usage(void)
1058{
1059 fprintf(stderr, "iowatcher usage:\n"
1060 "\t-d (--device): device for blktrace to trace\n"
1061 "\t-t (--trace): trace file name (more than one allowed)\n"
1062 "\t-l (--label): trace label in the graph\n"
1063 "\t-o (--output): output file name (SVG only)\n"
1064 "\t-p (--prog): program to run while blktrace is run\n"
c5245584 1065 "\t-m (--movie [=spindle|rect]): create IO animations\n"
ba758825
CM
1066 "\t-r (--rolling): number of seconds in the rolling averge\n"
1067 "\t-T (--title): graph title\n"
5122a20d
CM
1068 "\t-N (--no-graph): skip a single graph (io, tput, latency, queue_depth, \n"
1069 "\t\t\tiops, cpu-sys, cpu-io, cpu-irq cpu-soft cpu-user)\n"
1070 "\t-O (--only-graph): add a single graph to the output\n"
ba758825
CM
1071 "\t-h (--height): set the height of each graph\n"
1072 "\t-w (--width): set the width of each graph\n"
cc3d54d5 1073 "\t-c (--columns): numbers of columns in graph output\n"
d140b434
JK
1074 "\t-x (--xzoom): limit processed time to min:max\n"
1075 "\t-y (--yzoom): limit processed sectors to min:max\n"
f2e40ddd 1076 "\t-a (--io-plot-action): plot given action (one of Q,D,C) in IO graph\n"
ba758825
CM
1077 );
1078 exit(1);
1079}
1080
d140b434
JK
1081static int parse_double_range(char *str, double *min, double *max)
1082{
1083 char *end;
1084
1085 /* Empty lower bound - leave original value */
1086 if (str[0] != ':') {
1087 *min = strtod(str, &end);
1088 if (*min == HUGE_VAL || *min == -HUGE_VAL)
1089 return -ERANGE;
1090 if (*end != ':')
1091 return -EINVAL;
1092 } else
1093 end = str;
1094 /* Empty upper bound - leave original value */
1095 if (end[1]) {
1096 *max = strtod(end+1, &end);
1097 if (*max == HUGE_VAL || *max == -HUGE_VAL)
1098 return -ERANGE;
1099 if (*end != 0)
1100 return -EINVAL;
1101 }
1102 if (*min > *max)
1103 return -EINVAL;
1104 return 0;
1105}
1106
1107static int parse_ull_range(char *str, unsigned long long *min,
1108 unsigned long long *max)
1109{
1110 char *end;
1111
1112 /* Empty lower bound - leave original value */
1113 if (str[0] != ':') {
1114 *min = strtoull(str, &end, 10);
1115 if (*min == ULLONG_MAX && errno == ERANGE)
1116 return -ERANGE;
1117 if (*end != ':')
1118 return -EINVAL;
1119 } else
1120 end = str;
1121 /* Empty upper bound - leave original value */
1122 if (end[1]) {
1123 *max = strtoull(end+1, &end, 10);
1124 if (*max == ULLONG_MAX && errno == ERANGE)
1125 return -ERANGE;
1126 if (*end != 0)
1127 return -EINVAL;
1128 }
1129 if (*min > *max)
1130 return -EINVAL;
1131 return 0;
1132}
1133
ba758825
CM
1134static int parse_options(int ac, char **av)
1135{
1136 int c;
1137 int disabled = 0;
1138
1139 while (1) {
1140 // int this_option_optind = optind ? optind : 1;
1141 int option_index = 0;
1142
1143 c = getopt_long(ac, av, option_string,
1144 long_options, &option_index);
1145
1146 if (c == -1)
1147 break;
1148
1149 switch(c) {
1150 case 'T':
1151 graph_title = strdup(optarg);
1152 break;
1153 case 't':
1154 add_trace_file(optarg);
1155 set_blktrace_outfile(optarg);
1156 break;
1157 case 'o':
1158 output_filename = strdup(optarg);
1159 break;
1160 case 'l':
1161 set_trace_label(optarg);
1162 break;
1163 case 'r':
1164 set_rolling_avg(atoi(optarg));
1165 break;
1166 case 'O':
1167 if (!disabled) {
1168 disable_all_graphs();
1169 disabled = 1;
1170 }
1171 enable_one_graph(optarg);
1172 break;
1173 case 'N':
1174 disable_one_graph(optarg);
1175 break;
1176 case 'd':
1177 blktrace_device = strdup(optarg);
1178 break;
1179 case 'p':
1180 program_to_run = strdup(optarg);
1181 break;
1182 case 'm':
1183 make_movie = 1;
abf08f96
CM
1184 if (optarg) {
1185 movie_style = lookup_movie_style(optarg);
1186 if (movie_style < 0) {
1187 fprintf(stderr, "Unknown movie style %s\n", optarg);
1188 print_usage();
1189 }
1190 }
1191 fprintf(stderr, "Using movie style: %s\n",
1192 movie_styles[movie_style]);
ba758825
CM
1193 break;
1194 case 'h':
1195 opt_graph_height = atoi(optarg);
1196 break;
1197 case 'w':
1198 opt_graph_width = atoi(optarg);
1199 break;
cc3d54d5
CM
1200 case 'c':
1201 columns = atoi(optarg);
1202 break;
d140b434
JK
1203 case 'x':
1204 if (parse_double_range(optarg, &min_time, &max_time)
1205 < 0) {
1206 fprintf(stderr, "Cannot parse time range %s\n",
1207 optarg);
1208 exit(1);
1209 }
1210 break;
1211 case 'y':
1212 if (parse_ull_range(optarg, &min_mb, &max_mb)
1213 < 0) {
1214 fprintf(stderr,
1215 "Cannot parse offset range %s\n",
1216 optarg);
1217 exit(1);
1218 }
1219 if (max_mb > ULLONG_MAX >> 20) {
1220 fprintf(stderr,
1221 "Upper range limit too big."
1222 " Maximum is %llu.\n", ULLONG_MAX >> 20);
1223 exit(1);
1224 }
1225 break;
f2e40ddd
JK
1226 case 'a':
1227 if (strlen(optarg) != 1) {
1228action_err:
1229 fprintf(stderr, "Action must be one of Q, D, C.");
1230 exit(1);
1231 }
1232 plot_io_action = action_char_to_num(optarg[0]);
1233 if (plot_io_action < 0)
1234 goto action_err;
1235 break;
ba758825
CM
1236 case '?':
1237 case HELP_LONG_OPT:
1238 print_usage();
1239 break;
1240 default:
1241 break;
1242 }
1243 }
1244 return 0;
1245}
1246
1247
9e066e23
CM
1248int main(int ac, char **av)
1249{
1250 struct plot *plot;
230f0601 1251 int min_seconds = 0;
f752a6eb 1252 int max_seconds = 0;
9e066e23 1253 u64 max_offset = 0;
9b9fa04b 1254 u64 min_offset = ~(u64)0;
9e066e23
CM
1255 struct trace_file *tf;
1256 int ret;
cc3d54d5 1257 int rows, cols;
9e066e23
CM
1258
1259 init_io_hash_table();
1260
1261 enable_all_graphs();
1262
1263 parse_options(ac, av);
1264
1265 last_active_graph = last_graph();
ba758825
CM
1266 if (make_movie) {
1267 set_io_graph_scale(256);
abf08f96 1268 if (movie_style == MOVIE_SPINDLE)
8ed9516f 1269 set_graph_size(750, 550);
abf08f96
CM
1270 else
1271 set_graph_size(700, 400);
cc3d54d5
CM
1272
1273 /*
1274 * the plots in the movie don't have a seconds
1275 * line yet, this makes us skip it
1276 */
1277 last_active_graph = TOTAL_GRAPHS + 1;
ba758825
CM
1278 }
1279 if (opt_graph_height)
1280 set_graph_height(opt_graph_height);
1281
1282 if (opt_graph_width)
cc3d54d5 1283 set_graph_width(opt_graph_width);
9e066e23
CM
1284
1285 if (list_empty(&all_traces)) {
1286 fprintf(stderr, "No traces found, exiting\n");
1287 exit(1);
1288 }
1289
1290 if (blktrace_device) {
1291 ret = start_blktrace(blktrace_device, blktrace_outfile,
1292 blktrace_dest_dir);
1293 if (ret) {
1294 fprintf(stderr, "exiting due to blktrace failure\n");
1295 exit(1);
1296 }
e199d546 1297 start_mpstat(blktrace_outfile);
9e066e23
CM
1298 if (program_to_run) {
1299 ret = run_program(program_to_run);
1300 if (ret) {
1301 fprintf(stderr, "failed to run %s\n",
1302 program_to_run);
1303 exit(1);
1304 }
1305 wait_for_tracers();
1306 blktrace_to_dump(blktrace_outfile);
1307 } else {
1308 /* no program specified, just wait for
1309 * blktrace to exit
1310 */
1311 wait_for_tracers();
1312 }
1313 }
1314
1315 /* step one, read all the traces */
1316 read_traces();
1317
1318 /* step two, find the maxes for time and offset */
1319 list_for_each_entry(tf, &all_traces, list)
f752a6eb 1320 compare_minmax_tf(tf, &max_seconds, &min_offset, &max_offset);
d140b434
JK
1321 min_seconds = min_time;
1322 if (max_seconds > max_time)
1323 max_seconds = ceil(max_time);
1324 if (min_offset < min_mb << 20)
1325 min_offset = min_mb << 20;
1326 if (max_offset > max_mb << 20)
1327 max_offset = max_mb << 20;
9e066e23
CM
1328
1329 /* push the max we found into all the tfs */
230f0601 1330 set_all_minmax_tf(min_seconds, max_seconds, min_offset, max_offset);
9e066e23
CM
1331
1332 /* alloc graphing structs for all the traces */
1333 setup_trace_file_graphs();
1334
1335 /* run through all the traces and read their events */
1336 read_trace_events();
1337
ba758825
CM
1338 plot = alloc_plot();
1339
1340 if (make_movie) {
1341 plot_io_movie(plot);
1342 exit(0);
9e066e23
CM
1343 }
1344
ba758825 1345 set_plot_output(plot, output_filename);
9e066e23 1346
e199d546 1347 if (active_graphs[IO_GRAPH_INDEX] || found_mpstat)
9e066e23
CM
1348 set_legend_width(longest_label + strlen("writes"));
1349 else if (num_traces > 1)
1350 set_legend_width(longest_label);
1351 else
1352 set_legend_width(0);
1353
cc3d54d5
CM
1354 get_graph_size(&cols, &rows);
1355 if (columns > 1)
1356 plot->add_xlabel = 1;
e4df8968 1357 set_plot_title(plot, graph_title);
cc3d54d5 1358
6d5a91a7 1359 check_plot_columns(plot, IO_GRAPH_INDEX);
230f0601 1360 plot_io(plot, min_seconds, max_seconds, min_offset, max_offset);
cc3d54d5
CM
1361 plot->add_xlabel = 0;
1362
1363 if (columns > 1) {
1364 set_graph_size(cols / columns, rows);
1365 num_xticks /= columns;
1366 if (num_xticks < 2)
1367 num_xticks = 2;
1368 }
1e1e3f04
CM
1369 if (rows <= 50)
1370 num_yticks--;
cc3d54d5
CM
1371
1372 check_plot_columns(plot, TPUT_GRAPH_INDEX);
230f0601 1373 plot_tput(plot, min_seconds, max_seconds);
cc3d54d5
CM
1374
1375 check_plot_columns(plot, CPU_IO_GRAPH_INDEX);
f752a6eb 1376 plot_cpu(plot, max_seconds, "CPU IO Wait Time",
e199d546 1377 CPU_IO_GRAPH_INDEX, MPSTAT_IO);
cc3d54d5
CM
1378
1379 check_plot_columns(plot, CPU_SYS_GRAPH_INDEX);
f752a6eb 1380 plot_cpu(plot, max_seconds, "CPU System Time",
e199d546 1381 CPU_SYS_GRAPH_INDEX, MPSTAT_SYS);
cc3d54d5
CM
1382
1383 check_plot_columns(plot, CPU_IRQ_GRAPH_INDEX);
f752a6eb 1384 plot_cpu(plot, max_seconds, "CPU IRQ Time",
e199d546 1385 CPU_IRQ_GRAPH_INDEX, MPSTAT_IRQ);
cc3d54d5
CM
1386
1387 check_plot_columns(plot, CPU_SOFT_GRAPH_INDEX);
f752a6eb 1388 plot_cpu(plot, max_seconds, "CPU SoftIRQ Time",
e199d546 1389 CPU_SOFT_GRAPH_INDEX, MPSTAT_SOFT);
cc3d54d5
CM
1390
1391 check_plot_columns(plot, CPU_USER_GRAPH_INDEX);
f752a6eb 1392 plot_cpu(plot, max_seconds, "CPU User Time",
e199d546
CM
1393 CPU_USER_GRAPH_INDEX, MPSTAT_USER);
1394
cc3d54d5 1395 check_plot_columns(plot, LATENCY_GRAPH_INDEX);
230f0601 1396 plot_latency(plot, min_seconds, max_seconds);
cc3d54d5
CM
1397
1398 check_plot_columns(plot, QUEUE_DEPTH_GRAPH_INDEX);
230f0601 1399 plot_queue_depth(plot, min_seconds, max_seconds);
cc3d54d5
CM
1400
1401 check_plot_columns(plot, IOPS_GRAPH_INDEX);
230f0601 1402 plot_iops(plot, min_seconds, max_seconds);
9e066e23
CM
1403
1404 /* once for all */
1405 close_plot(plot);
abf08f96 1406 close_plot_file(plot);
9e066e23
CM
1407 return 0;
1408}