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