OBJS = args.o bt_timeline.o devmap.o devs.o dip_rb.o iostat.o latency.o \
misc.o output.o proc.o seek.o trace.o trace_complete.o trace_im.o \
trace_issue.o trace_queue.o trace_remap.o trace_requeue.o \
- ../rbtree.o mmap.o trace_plug.o bno_dump.o unplug_hist.o
+ ../rbtree.o mmap.o trace_plug.o bno_dump.o unplug_hist.o q2d.o
all: depend $(PROGS)
seeki_exit(dip->q2q_handle);
bno_dump_exit(dip->bno_dump_handle);
unplug_hist_exit(dip->unplug_hist_handle);
+ if (output_all_data)
+ q2d_release(dip->q2d_priv);
free(dip);
}
}
list_add_tail(&dip->all_head, &all_devs);
dip->start_time = BIT_TIME(iop->t.time);
dip->pre_culling = 1;
+ if (output_all_data)
+ dip->q2d_priv = q2d_init();
n_devs++;
}
\item[Per Device Averages] The average columns from the above charts,
are also presented in their own chart.
+
+ \item[Q2D Histogram] A display of histogram buckets for the Q to D times
+ -- basically, from where an IO enters the block IO layer for a given
+ device, and when it is dispatched. The buckets are arranged via the
+ time in seconds, as in:
+
+\begin{verbatim}
+==================== Q2D Histogram ====================
+
+ DEV | <.005 <.010 <.025 <.050 <.075 <.100 <.250 <.500 < 1.0 >=1.0
+ --------- | ===== ===== ===== ===== ===== ===== ===== ===== ===== =====
+ ( 66, 80) | 61.2 7.9 12.1 7.9 3.0 1.4 1.5 0.2 0.0 4.6
+ ( 65,192) | 42.3 5.0 8.7 30.0 8.9 3.0 1.8 0.1 0.0 0.1
+ ( 65,128) | 34.3 5.3 8.9 32.0 9.7 3.7 5.3 0.6 0.0 0.1
+...
+ ( 65, 64) | 59.9 4.2 6.0 24.6 4.2 0.8 0.1 0.0 0.0 0.1
+ ( 66, 64) | 62.6 8.1 12.7 7.9 2.4 0.6 0.1 0.0 0.0 5.4
+========== | ===== ===== ===== ===== ===== ===== ===== ===== ===== =====
+ AVG | 52.9 6.2 10.0 20.1 5.3 1.7 1.4 0.2 0.0 2.1
+\end{verbatim}
+
\end{description}
\newpage\section{\label{sec:data-files}Data Files Output}
struct region_info regions;
struct devmap *map;
void *q2q_handle, *seek_handle, *bno_dump_handle, *unplug_hist_handle;
+ void *q2d_priv;
FILE *d2c_ofp, *q2c_ofp;
struct avgs_info avgs;
struct stats stats, all_stats;
void bno_dump_add(void *handle, struct io *iop);
void bno_dump_clean(void);
+/* q2d.c */
+void q2d_histo_add(void *priv, __u64 q2d);
+void *q2d_init(void);
+void q2d_release(void *priv);
+void q2d_display_header(FILE *fp);
+void q2d_display_dashes(FILE *fp);
+void q2d_display(FILE *fp, void *priv);
+int q2d_ok(void *priv);
+void q2d_acc(void *a1, void *a2);
+
/* seek.c */
void *seeki_init(char *str);
void seeki_exit(void *param);
fprintf(ofp, "\n");
}
+struct __q2d {
+ FILE *ofp;
+ void *q2d_all;
+ int n;
+};
+void __output_q2d_histo(struct d_info *dip, void *arg)
+{
+ struct __q2d *q2dp = arg;
+
+ if (q2d_ok(dip->q2d_priv)) {
+ char scratch[15];
+ FILE *ofp = q2dp->ofp;
+
+ fprintf(q2dp->ofp, "%10s | ", make_dev_hdr(scratch, 15, dip));
+ q2d_display(ofp, dip->q2d_priv);
+ q2d_acc(q2dp->q2d_all, dip->q2d_priv);
+ q2dp->n++;
+ }
+}
+
+void output_q2d_histo(FILE *ofp)
+{
+ struct __q2d __q2d = {
+ .ofp = ofp,
+ .q2d_all = q2d_init(),
+ .n = 0
+ };
+
+ fprintf(ofp, "%10s | ", "DEV");
+ q2d_display_header(ofp);
+ fprintf(ofp, "--------- | ");
+ q2d_display_dashes(ofp);
+ dip_foreach_out(__output_q2d_histo, &__q2d);
+
+ if (__q2d.n) {
+ fprintf(ofp, "========== | ");
+ q2d_display_dashes(ofp);
+ fprintf(ofp, "%10s | ", "AVG");
+ q2d_display(ofp, __q2d.q2d_all);
+ fprintf(ofp, "\n");
+ }
+}
+
int n_merges = 0;
struct {
unsigned long long nq, nd, blkmin, blkmax, total;
output_histos();
+ if (output_all_data) {
+ output_section_hdr(ofp, "Q2D Histogram");
+ output_q2d_histo(ofp);
+ }
+
return 0;
}
--- /dev/null
+/*
+ * blktrace output analysis: generate a timeline & gather statistics
+ *
+ * (C) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "globals.h"
+
+#define Q2D_MAX_HISTO 9
+struct q2d_info {
+ unsigned long nhistos;
+ unsigned long histos[Q2D_MAX_HISTO + 1];
+};
+
+void q2d_histo_add(void *priv, __u64 q2d_in)
+{
+ int index;
+ struct q2d_info *q2dp = priv;
+ double q2d = BIT_TIME(q2d_in);
+ long msec = (long)(q2d / 0.001);
+
+ switch (msec) {
+ default: index = 9; break;
+ case 500 ... 999: index = 8; break;
+ case 250 ... 499: index = 7; break;
+ case 100 ... 249: index = 6; break;
+ case 75 ... 99: index = 5; break;
+ case 50 ... 74: index = 4; break;
+ case 25 ... 49: index = 3; break;
+ case 10 ... 24: index = 2; break;
+ case 5 ... 9: index = 1; break;
+ case 0 ... 4: index = 0; break;
+ }
+
+ q2dp->histos[index]++;
+ q2dp->nhistos++;
+}
+
+void *q2d_init(void)
+{
+ struct q2d_info *q2dp = malloc(sizeof(*q2dp));
+
+ return memset(q2dp, 0, sizeof(*q2dp));
+}
+
+void q2d_release(void *priv)
+{
+ free(priv);
+}
+
+void q2d_display_header(FILE *fp)
+{
+ fprintf(fp, "%5s ", "<.005");
+ fprintf(fp, "%5s ", "<.010");
+ fprintf(fp, "%5s ", "<.025");
+ fprintf(fp, "%5s ", "<.050");
+ fprintf(fp, "%5s ", "<.075");
+ fprintf(fp, "%5s ", "<.100");
+ fprintf(fp, "%5s ", "<.250");
+ fprintf(fp, "%5s ", "<.500");
+ fprintf(fp, "%5s ", "< 1.0");
+ fprintf(fp, "%5s ", ">=1.0\n");
+}
+
+void q2d_display_dashes(FILE *fp)
+{
+ int i;
+
+ for (i = 0; i <= Q2D_MAX_HISTO; i++)
+ fprintf(fp, "===== ");
+ fprintf(fp, "\n");
+}
+
+void q2d_display(FILE *fp, void *priv)
+{
+ int i;
+ struct q2d_info *q2dp = priv;
+ double nh = (double)q2dp->nhistos;
+
+ for (i = 0; i <= Q2D_MAX_HISTO; i++) {
+ double p = 100.0 * (double)q2dp->histos[i] / nh;
+ fprintf(fp, "%5.1lf ", p);
+ }
+ fprintf(fp, "\n");
+}
+
+int q2d_ok(void *priv)
+{
+ struct q2d_info *q2dp = priv;
+
+ return q2dp && q2dp->nhistos > 0;
+}
+
+void q2d_acc(void *a1, void *a2)
+{
+ int i;
+ struct q2d_info *ap = a1;
+ struct q2d_info *tp = a2;
+
+ for (i = 0; i <= Q2D_MAX_HISTO; i++)
+ ap->histos[i] += tp->histos[i];
+ ap->nhistos += tp->nhistos;
+}
q_iop->d_time = d_iop->t.time;
q_iop->d_sec = d_iop->t.sector;
q_iop->d_nsec = t_sec(&d_iop->t);
+
+ if (output_all_data)
+ q2d_histo_add(q_iop->dip->q2d_priv,
+ d_iop->t.time - q_iop->t.time);
}
assert(d_iop->bytes_left == 0);