#define SETBUFFER_SIZE (64 * 1024)
-#define S_OPTS "aAB:d:D:e:hi:I:l:M:o:p:q:s:S:t:T:u:Vv"
+#define S_OPTS "aAB:d:D:e:hi:I:l:M:o:p:q:s:S:t:T:u:VvX"
static struct option l_opts[] = {
{
.name = "seek-absolute",
.flag = NULL,
.val = 'v'
},
+ {
+ .name = "easy-parse-avgs",
+ .has_arg = no_argument,
+ .flag = NULL,
+ .val = 'X'
+ },
{
.name = NULL,
}
"[ -S <interval> | --iostat-interval=<interval> ]\n" \
"[ -t <sec> | --time-start=<sec> ]\n" \
"[ -T <sec> | --time-end=<sec> ]\n" \
- "[ -u <output name> | --unplug-hist=<output name> ] \n" \
+ "[ -u <output name> | --unplug-hist=<output name> ]\n" \
"[ -V | --version ]\n" \
- "[ -v | --verbose ]\n\n";
+ "[ -v | --verbose ]\n" \
+ "[ -X | --easy-parse-avgs ]\n" \
+ "\n";
static struct file_info *arg_files = NULL;
case 'V':
printf("%s version %s\n", argv[0], bt_timeline_version);
exit(0);
+ case 'X':
+ easy_parse_avgs++;
+ break;
default:
usage(argv[0]);
exit(1);
setup_ifile(input_name);
- if (output_name == NULL)
+ if (output_name == NULL) {
ranges_ofp = avgs_ofp = stdout;
+ easy_parse_avgs = 0;
+ }
else {
char *fname = malloc(strlen(output_name) + 32);
exit(1);
}
if (verbose)
- printf("Sending range data to %s.dat\n", output_name);
+ printf("Sending range data to %s\n", fname);
sprintf(fname, "%s.avg", output_name);
avgs_ofp = fopen(fname, "w");
exit(1);
}
if (verbose)
- printf("Sending stats data to %s.avg\n", output_name);
+ printf("Sending stats data to %s\n", fname);
+
+ if (easy_parse_avgs) {
+ sprintf(fname, "%s.xvg", output_name);
+ xavgs_ofp = fopen(fname, "w");
+ if (avgs_ofp == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ if (verbose)
+ printf("Sending X stats data to %s\n", fname);
+ }
free(fname);
}
#include <time.h>
#include "globals.h"
-char bt_timeline_version[] = "2.02";
+char bt_timeline_version[] = "2.03";
char *devices, *exes, *input_name, *output_name, *seek_name, *bno_dump_name;
char *d2c_name, *q2c_name, *per_io_name, *unplug_hist_name;
-FILE *ranges_ofp, *avgs_ofp, *per_io_ofp;
+FILE *ranges_ofp, *avgs_ofp, *xavgs_ofp, *per_io_ofp;
int verbose, done, time_bounded, output_all_data, seek_absolute;
+int easy_parse_avgs;
double t_astart, t_aend;
unsigned long n_traces;
struct avgs_info all_avgs;
\end{description}
- Besides the default data files output, there are optional data files
- which can be generated by btt. These include:
+ In addition to the default data files output, there are optional data
+ files which can be generated by btt. These include:
\begin{description}
+ \item[subset of \texttt{.avg} data, easily parsed ] When the
+ \texttt{-X} option is specified \emph{and} the \texttt{-o} has also
+ been specified, then a subset of the data produced by default is
+ copied to another file that is \emph{more easily parsed.} Refer to
+ section~\ref{sec:o-X} for full details.
+
\item[iostat] iostat-like data can be distilled by btt, and is
described in section~\ref{sec:iostat}.
\newpage\section{\label{sec:cmd-line}Command Line}
\begin{verbatim}
-Usage: btt 2.01
+Usage: btt 2.03
[ -a | --seek-absolute ]
[ -A | --all-data ]
[ -B <output name> | --dump-blocknos=<output name> ]
[ -u <output name> | --unplug-hist=<output name> ]
[ -V | --version ]
[ -v | --verbose ]
+[ -X | --easy-parse-avgs ]
\end{verbatim}
\subsection{\label{sec:o-a}\texttt{--seek-absolute}/\texttt{-a}}
16.379036+0.000005=16.379041
\end{verbatim}
+\subsection{\label{sec:o-X}\texttt{--easy-parse-avgs}/\texttt{-X}}
+
+ \emph{Some} of the data produced by default can also be shipped
+ simultaneously to another file in an easy to parse form. When
+ the \texttt{-o} option is selected (thus producing a file with a
+ \texttt{.avg} exentsion), \emph{and} the \texttt{-X} flag is present,
+ then \texttt{btt} will generate this file.
+
+ The format is space-delimited values starting with a 3-character
+ \emph{record} indicator, then the device information (either major,minor
+ or the device name when \texttt{-M} is specified), and then a number of
+ fields representing data values. The following table shows the record
+ identifiers and the fields provided:
+
+ \bigskip
+ \begin{tabular}{|l|l|}\hline
+ \textbf{Record} & \textbf{Description}\\\hline
+ \texttt{DMI} & Device Merge Information:\\
+ & \#Q \#D Ratio BLKmin BLKavg BLKmax Total\\\hline
+ \texttt{QSK} & Device Q2Q Seek Information:\\
+ & NSEEKS MEAN MEDIAN MODE N-MODE mode\ldots\\\hline
+ \texttt{DSK} & Device D2D Seek Information:\\
+ & NSEEKS MEAN MEDIAN MODE N-MODE mode\ldots\\\hline
+ \texttt{PLG} & Plug Information:\\
+ & \#Plugs \#TimerUnplugs \%TimeQPlugged\\\hline
+ \texttt{UPG} & Unplug Information:\\
+ & IOsPerUnplug IOsPerUnplugTimeout\\\hline
+ \texttt{ARQ} & Active Requests at Q Information:\\
+ & AvgReqs@Q\\\hline
+ \end{tabular}
+
+ \bigskip
+ A sample output file would look like:
+
+ \begin{verbatim}
+DMI 8,16 310407 106729 2.908366049 0 182 1024 19504768
+QSK 8,16 310407 167141.958551192 0 0 235753
+DSK 8,16 106729 433247.436563633 0 0 33974
+PLG 8,16 40824 382 0.008882101
+UPG 8,16 1.993361748 1.866492147
+ARQ 8,16 22.863331046
+ \end{verbatim}
+
\newpage\section{\label{sec:bno_plot}bno\_plot.py}
Included with the distribution is a simple 3D plotting utility based
extern char *seek_name, *iostat_name, *d2c_name, *q2c_name, *per_io_name;
extern char *bno_dump_name, *unplug_hist_name;
extern double range_delta;
-extern FILE *ranges_ofp, *avgs_ofp, *iostat_ofp, *per_io_ofp;
+extern FILE *ranges_ofp, *avgs_ofp, *xavgs_ofp, *iostat_ofp, *per_io_ofp;
extern int verbose, done, time_bounded, output_all_data, seek_absolute;
+extern int easy_parse_avgs;
extern unsigned int n_devs;
extern unsigned long n_traces;
extern struct list_head all_devs, all_procs;
return pad;
}
+char *make_dev_hdrX(char *pad, size_t len, struct d_info *dip)
+{
+ if (dip->map == NULL)
+ snprintf(pad, len, "%d,%d",
+ MAJOR(dip->device), MINOR(dip->device));
+ else
+ snprintf(pad, len, "%s", dip->map->device);
+
+ return pad;
+}
+
struct __oda {
FILE *ofp;
ai_dip_t (*func)(struct d_info *);
struct __q2d *q2dp = arg;
if (q2d_ok(dip->q2d_priv)) {
- char scratch[15];
+ char dev_info[15];
FILE *ofp = q2dp->ofp;
- fprintf(q2dp->ofp, "%10s | ", make_dev_hdr(scratch, 15, dip));
+ fprintf(q2dp->ofp, "%10s | ", make_dev_hdr(dev_info, 15, dip));
q2d_display(ofp, dip->q2d_priv);
q2d_acc(q2dp->q2d_all, dip->q2d_priv);
q2dp->n++;
void __output_dip_merge_ratio(struct d_info *dip, void *arg)
{
double blks_avg;
- char scratch[15];
+ char dev_info[15];
double ratio, q2c_n, d2c_n;
if (dip->n_qs == 0 || dip->n_ds == 0)
blks_avg = (double)dip->avgs.blks.total / d2c_n;
fprintf((FILE *)arg,
"%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
- make_dev_hdr(scratch, 15, dip),
+ make_dev_hdr(dev_info, 15, dip),
(unsigned long long)dip->n_qs,
(unsigned long long)dip->n_ds,
ratio,
(unsigned long long)dip->avgs.blks.max,
(unsigned long long)dip->avgs.blks.total);
+ if (easy_parse_avgs) {
+ fprintf(xavgs_ofp,
+ "DMI %s %llu %llu %.9lf %llu %llu %llu %llu\n",
+ make_dev_hdrX(dev_info, 15, dip),
+ (unsigned long long)dip->n_qs,
+ (unsigned long long)dip->n_ds,
+ ratio,
+ (unsigned long long)dip->avgs.blks.min,
+ (unsigned long long)blks_avg,
+ (unsigned long long)dip->avgs.blks.max,
+ (unsigned long long)dip->avgs.blks.total);
+ }
+
if (n_merges++ == 0) {
merge_data.blkmin = dip->avgs.blks.min;
merge_data.blkmax = dip->avgs.blks.max;
fprintf(ofp, " %lld", m.modes[i]);
fprintf(ofp, "\n");
+ if (easy_parse_avgs) {
+ char *rec = is_q2q ? "QSK" : "DSK";
+ fprintf(xavgs_ofp,
+ "%s %s %lld %.9lf %lld %lld %d",
+ rec, make_dev_hdrX(dev_info, 15, dip),
+ nseeks, mean, median,
+ nmodes > 0 ? m.modes[0] : 0, m.most_seeks);
+ for (i = 1; i < nmodes; i++)
+ fprintf(xavgs_ofp, " %lld", m.modes[i]);
+ fprintf(xavgs_ofp, "\n");
+ }
+
seek_info.nseeks += nseeks;
seek_info.mean += (nseeks * mean);
seek_info.median += (nseeks * median);
make_dev_hdr(dev_info, 15, dip),
dip->nplugs, dip->n_timer_unplugs, pct);
+ if (easy_parse_avgs) {
+ fprintf(xavgs_ofp,
+ "PLG %s %d %d %.9lf\n",
+ make_dev_hdrX(dev_info, 15, dip),
+ dip->nplugs, dip->n_timer_unplugs, pct);
+ }
+
n_plugs++;
plug_info.n_plugs += dip->nplugs;
plug_info.n_timer_unplugs += dip->n_timer_unplugs;
fprintf(ofp, "%10s | %10.1lf %10.1lf\n",
make_dev_hdr(dev_info, 15, dip),
a_nios_uplug, a_nios_uplug_t);
+
+ if (easy_parse_avgs) {
+ fprintf(xavgs_ofp,
+ "UPG %s %.9lf %.9lf\n",
+ make_dev_hdrX(dev_info, 15, dip),
+ a_nios_uplug, a_nios_uplug_t);
+ }
}
void __dip_output_uplug_all(FILE *ofp, struct nios_plug_info *p)
fprintf((FILE *)arg, "%10s | %13.1lf\n",
make_dev_hdr(dev_info, 15, dip), a_actQs);
+ if (easy_parse_avgs) {
+ fprintf(xavgs_ofp,
+ "ARQ %s %.9lf\n",
+ make_dev_hdrX(dev_info, 15, dip), a_actQs);
+ }
+
n_actQs++;
actQ_info.t_qs += dip->n_qs;
actQ_info.t_act_qs += dip->t_act_q;