/* * blktrace output analysis: generate a timeline & gather statistics * * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <time.h> #include "globals.h" char bt_timeline_version[] = "2.09"; char *devices, *exes, *input_name, *output_name, *seek_name, *bno_dump_name; char *d2c_name, *q2c_name, *per_io_name, *unplug_hist_name; char *sps_name, *aqd_name, *q2d_name, *per_io_trees; FILE *rngs_ofp, *avgs_ofp, *xavgs_ofp, *per_io_ofp, *msgs_ofp; int verbose, done, time_bounded, output_all_data, seek_absolute; int easy_parse_avgs, ignore_remaps, do_p_live; double t_astart, t_aend, last_t_seen; unsigned long n_traces; struct avgs_info all_avgs; unsigned int n_devs; time_t genesis, last_vtrace; LIST_HEAD(all_devs); LIST_HEAD(all_procs); LIST_HEAD(all_ios); LIST_HEAD(free_ios); LIST_HEAD(free_bilinks); __u64 q_histo[N_HIST_BKTS], d_histo[N_HIST_BKTS]; double plat_freq = 0.0; double range_delta = 0.1; __u64 last_q = (__u64)-1; struct region_info all_regions = { .qranges = LIST_HEAD_INIT(all_regions.qranges), .cranges = LIST_HEAD_INIT(all_regions.cranges), }; int process(void); int main(int argc, char *argv[]) { handle_args(argc, argv); init_dev_heads(); iostat_init(); if (!rstat_init()) return 1; if (process() || output_avgs(avgs_ofp) || output_ranges(rngs_ofp)) return 1; if (iostat_ofp) { fprintf(iostat_ofp, "\n"); iostat_dump_stats(iostat_last_stamp, 1); } if (msgs_ofp != stdout) fclose(msgs_ofp); if (rngs_ofp != stdout) fclose(rngs_ofp); if (avgs_ofp != stdout) fclose(avgs_ofp); if (xavgs_ofp) fclose(xavgs_ofp); dip_cleanup(); dev_map_exit(); dip_exit(); rstat_exit(); pip_exit(); io_free_all(); region_exit(&all_regions); p_live_exit(); clean_allocs(); return 0; } static inline double tv2dbl(struct timeval *tv) { return (double)tv->tv_sec + (((double)tv->tv_usec) / (1000.0 * 1000.0)); } int process(void) { int ret = 0; struct io *iop = io_alloc(); struct timeval tvs, tve; genesis = last_vtrace = time(NULL); gettimeofday(&tvs, NULL); while (!done && next_trace(&iop->t, &iop->pdu)) { add_trace(iop); iop = io_alloc(); } io_release(iop); gettimeofday(&tve, NULL); if (verbose) { double tps, dt_input = tv2dbl(&tve) - tv2dbl(&tvs); tps = (double)n_traces / dt_input; printf("\r " " \r"); printf("%10lu traces @ %.1lf Ktps in %.6lf seconds\n", n_traces, tps/1000.0, dt_input); } return ret; }