#define SETBUFFER_SIZE (64 * 1024)
-#define S_OPTS "aAB:d:D:e:hi:I:l:L:m:M:o:p:q:Q:s:S:t:T:u:VvXz:"
+#define S_OPTS "aAB:d:D:e:hi:I:l:L:m:M:o:p:P:q:Q:s:S:t:T:u:VvXz:"
static struct option l_opts[] = {
{
.name = "seek-absolute",
.flag = NULL,
.val = 'p'
},
+ {
+ .name = "per-io-trees",
+ .has_arg = required_argument,
+ .flag = NULL,
+ .val = 'P'
+ },
{
.name = "q2c-latencies",
.has_arg = required_argument,
"[ -M <dev map> | --dev-maps=<dev map>\n" \
"[ -o <output name> | --output-file=<output name> ]\n" \
"[ -p <output name> | --per-io-dump=<output name> ]\n" \
+ "[ -P <output name> | --per-io-trees=<output name> ]\n" \
"[ -q <output name> | --q2c-latencies=<output name> ]\n" \
"[ -Q <output name> | --active-queue-depth=<output name> ]\n" \
"[ -s <output name> | --seeks=<output name> ]\n" \
case 'p':
per_io_name = strdup(optarg);
break;
+ case 'P':
+ per_io_trees = strdup(optarg);
+ break;
case 'q':
q2c_name = strdup(optarg);
break;
#include <time.h>
#include "globals.h"
-char bt_timeline_version[] = "2.06";
+char bt_timeline_version[] = "2.07";
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;
+char *sps_name, *aqd_name, *q2d_name, *per_io_trees;
FILE *ranges_ofp, *avgs_ofp, *xavgs_ofp, *per_io_ofp, *msgs_ofp;
int verbose, done, time_bounded, output_all_data, seek_absolute;
int easy_parse_avgs;
unplug_hist_exit(dip->unplug_hist_handle);
if (output_all_data)
q2d_release(dip->q2d_priv);
+ if (dip->pit_fp)
+ fclose(dip->pit_fp);
free(dip);
}
}
return str;
}
+static inline FILE *open_pit(char *str)
+{
+ FILE *fp = fopen(str, "w");
+
+ if (fp == NULL)
+ perror(str);
+
+ return fp;
+}
+
struct d_info *dip_add(__u32 device, struct io *iop)
{
struct d_info *dip = __dip_find(device);
if (output_all_data)
dip->q2d_priv = q2d_init();
n_devs++;
+ if (per_io_trees)
+ dip->pit_fp = open_pit(mkhandle(per_io_trees,
+ device, "_pit.dat"));
}
if (dip->pre_culling) {
\newpage\section{\label{sec:cmd-line}Command Line}
\begin{verbatim}
-Usage: btt 2.06
+Usage: btt 2.07
[ -a | --seek-absolute ]
[ -A | --all-data ]
[ -B <output name> | --dump-blocknos=<output name> ]
[ -M <dev map> | --dev-maps=<dev map>
[ -o <output name> | --output-file=<output name> ]
[ -p <output name> | --per-io-dump=<output name> ]
+[ -P <output name> | --per-io-trees=<output name> ]
[ -q <output name> | --q2c-latencies=<output name> ]
[ -Q <output name> | --active-queue-depth=<output name> ]
[ -s <output name> | --seeks=<output name> ]
This option tells \texttt{btt} to generate the per IO dump file as
discussed in section~\ref{sec:per-io}.
+\subsection{\label{sec:o-P}\texttt{--per-io-tress}/\texttt{-P}}
+
+The \texttt{-P} option will generate a file that contains a list of all IO
+"sequences" - showing only the Q, D \& C operation times. The D \& C
+time values are separated from the Q time values with a vertical bar.
+
\subsection{\label{sec:o-q}\texttt{--q2c-latencies}/\texttt{-q}}
This option instructs \texttt{btt} to generate the Q2C latency file
void *q2q_handle, *seek_handle, *bno_dump_handle, *unplug_hist_handle;
void *q2d_priv, *aqd_handle;
void *q2d_plat_handle, *q2c_plat_handle, *d2c_plat_handle;
- FILE *q2d_ofp, *d2c_ofp, *q2c_ofp;
+ FILE *q2d_ofp, *d2c_ofp, *q2c_ofp, *pit_fp;
struct avgs_info avgs;
struct stats stats, all_stats;
__u64 last_q, n_qs, n_ds;
extern char bt_timeline_version[], *devices, *exes, *input_name, *output_name;
extern char *seek_name, *iostat_name, *d2c_name, *q2c_name, *per_io_name;
extern char *bno_dump_name, *unplug_hist_name, *sps_name, *aqd_name, *q2d_name;
+extern char *per_io_trees;
extern double range_delta, plat_freq;
extern FILE *ranges_ofp, *avgs_ofp, *xavgs_ofp, *iostat_ofp, *per_io_ofp;
extern FILE *msgs_ofp;
{
LIST_HEAD(head);
struct list_head *p, *q;
+ __u64 d_time = (__u64)-1;
+ FILE *pit_fp = c_iop->dip->pit_fp;
update_blks(c_iop);
update_cregion(&all_regions, c_iop->t.time);
update_d2c(q_iop, d2c);
latency_d2c(q_iop->dip, c_iop->t.time, d2c);
iostat_complete(q_iop, c_iop);
+
+ d_time = q_iop->d_time;
}
if (per_io_ofp) {
display_io_track(per_io_ofp, q_iop);
}
+ if (q_iop->dip->pit_fp) {
+ fprintf(pit_fp, "%d.%09lu ",
+ (int)SECONDS(q_iop->t.time),
+ (unsigned long)NANO_SECONDS(q_iop->t.time));
+ }
+
list_del(&q_iop->f_head);
io_release(q_iop);
}
if (per_io_ofp)
fprintf(per_io_ofp,
"-----------------------------------------\n");
+
+ if (c_iop->dip->pit_fp) {
+ fprintf(pit_fp, "| %d.%09lu | %d.%09lu\n",
+ (int)SECONDS(d_time),
+ (unsigned long)NANO_SECONDS(d_time),
+ (int)SECONDS(c_iop->t.time),
+ (unsigned long)NANO_SECONDS(c_iop->t.time));
+ }
}
void trace_complete(struct io *c_iop)
.br
[ \-p <\fIoutput name\fR> | \-\-per\-io\-dump=<\fIoutput name\fR> ]
.br
+[ \-P <\fIoutput name\fR> | \-\-per\-io\-trees=<\fIoutput name\fR> ]
+.br
[ \-q <\fIoutput name\fR> | \-\-q2c\-latencies=<\fIoutput name\fR> ]
.br
[ \-Q <\fIoutput name\fR> | \-\-active\-queue\-depth=<\fIoutput name\fR> ]
"sequences" \- showing the parts of each IO (Q, A, I/M, D, & C).
.RE
+.B \-P <\fIoutput name\fR>
+.br
+.B \-\-per\-io\-trees=<\fIoutput name\fR>
+.RS 4
+The \-P option will generate a file that contains a list of all IO
+"sequences" \- showing only the Q, D & C operation times. The D & C
+time values are separated from the Q time values with a vertical bar.
+.RE
+
.B \-q <\fIoutput name\fR>
.br
.B \-\-q2c\-latencies=<\fIoutput name\fR>