Added in -L option - output periodic latency information
authorAlan D. Brunelle <alan.brunelle@hp.com>
Thu, 16 Oct 2008 16:03:45 +0000 (12:03 -0400)
committerAlan D. Brunelle <alan.brunelle@hp.com>
Thu, 16 Oct 2008 16:05:46 +0000 (12:05 -0400)
btt/Makefile
btt/aqd.c
btt/args.c
btt/bt_timeline.c
btt/devs.c
btt/doc/btt.tex
btt/globals.h
btt/latency.c
btt/plat.c [new file with mode: 0644]
doc/btt.1

index 8c4d882aa095fc1ac4efe6ab39b15dabf50e8eda..1f6dacc25c89261f440a79d044f21afc1e8c9327 100644 (file)
@@ -17,7 +17,7 @@ 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 q2d.o \
-         aqd.o
+         aqd.o plat.o
 
 all: depend $(PROGS)
 
index 036a0d33786e5e71b9bbff2e3a6d975d46b27ac9..775fca68c67a9b8e5d32f7295a188798ab0dbcbe 100644 (file)
--- a/btt/aqd.c
+++ b/btt/aqd.c
@@ -53,6 +53,16 @@ void *aqd_init(char *str)
 
 }
 
+void aqd_exit(void *info)
+{
+       free(info);
+}
+
+void aqd_clean(void)
+{
+       clean_files(&aqd_files);
+}
+
 void aqd_issue(void *info, double ts)
 {
        struct aqd_info *ap = info;
index 2cbbf543cf62839a0816c6e444ed1eb17efb4791..db4186eea088cbc7f5fc522c0f249dd6e4a53d37 100644 (file)
@@ -29,7 +29,7 @@
 
 #define SETBUFFER_SIZE (64 * 1024)
 
-#define S_OPTS "aAB:d:D:e:hi:I:l:m:M:o:p:q:Q:s:S:t:T:u:VvX"
+#define S_OPTS "aAB:d:D:e:hi:I:l:L:m:M:o:p:q:Q:s:S:t:T:u:VvX"
 static struct option l_opts[] = {
        {
                .name = "seek-absolute",
@@ -91,6 +91,12 @@ static struct option l_opts[] = {
                .flag = NULL,
                .val = 'l'
        },
+       {
+               .name = "periodic-latencies",
+               .has_arg = required_argument,
+               .flag = NULL,
+               .val = 'L'
+       },
        {
                .name = "seeks-per-second",
                .has_arg = required_argument,
@@ -191,6 +197,7 @@ static char usage_str[] = \
        "[ -i <input name>  | --input-file=<input name> ]\n" \
        "[ -I <output name> | --iostat=<output name> ]\n" \
        "[ -l <output name> | --d2c-latencies=<output name> ]\n" \
+       "[ -L <freq>        | --periodic-latencies=<freq> ]\n" \
        "[ -m <output name> | --seeks-per-second=<output name> ]\n" \
        "[ -M <dev map>     | --dev-maps=<dev map>\n" \
        "[ -o <output name> | --output-file=<output name> ]\n" \
@@ -275,6 +282,9 @@ void handle_args(int argc, char *argv[])
                case 'l':
                        d2c_name = strdup(optarg);
                        break;
+               case 'L':
+                       plat_freq = atof(optarg);
+                       break;
                case 'I':
                        iostat_name = strdup(optarg);
                        break;
index c4bbfbfe7d34a614d4299a1321f17236e092545b..75e41ca11e836278ce9347d01e9971baa6435293 100644 (file)
@@ -45,6 +45,7 @@ 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;
 
@@ -82,6 +83,7 @@ int main(int argc, char *argv[])
        dip_exit();
        seek_clean();
        pip_exit();
+       aqd_clean();
        io_free_all();
        region_exit(&all_regions);
 
index 2127cde2eddd969ec690c77c65a1bc050c3c80de..b7943d3ec9c34539121b0ba77c5e891977c33708 100644 (file)
@@ -85,6 +85,9 @@ void dip_exit(void)
                region_exit(&dip->regions);
                seeki_exit(dip->seek_handle);
                seeki_exit(dip->q2q_handle);
+               aqd_exit(dip->aqd_handle);
+               plat_exit(dip->q2c_plat_handle);
+               plat_exit(dip->d2c_plat_handle);
                bno_dump_exit(dip->bno_dump_handle);
                unplug_hist_exit(dip->unplug_hist_handle);
                if (output_all_data)
@@ -121,6 +124,10 @@ struct d_info *dip_add(__u32 device, struct io *iop)
                dip->seek_handle = seeki_init(mkhandle(str, device, "_d2d"));
                dip->q2q_handle = seeki_init(mkhandle(str, device, "_q2q"));
                dip->aqd_handle = aqd_init(mkhandle(str, device, "_aqd"));
+               dip->q2c_plat_handle =
+                               plat_init(mkhandle(str, device, "_q2c_plat"));
+               dip->d2c_plat_handle =
+                               plat_init(mkhandle(str, device, "_d2c_plat"));
                latency_init(dip);
                list_add_tail(&dip->hash_head, &dev_heads[DEV_HASH(device)]);
                list_add_tail(&dip->all_head, &all_devs);
index aa7db8c07dd33b24651ae93a6e0aea2ebd445346..eb4d29a64c8edad84c7776fb95be0fab3746d595 100644 (file)
@@ -809,6 +809,7 @@ Usage: btt 2.05
 [ -i <input name>  | --input-file=<input name> ]
 [ -I <output name> | --iostat=<output name> ]
 [ -l <output name> | --d2c-latencies=<output name> ]
+[ -L <freq>        | --periodic-latencies=<freq> ]
 [ -m <output name> | --seeks-per-second=<output name> ]
 [ -M <dev map>     | --dev-maps=<dev map>
 [ -o <output name> | --output-file=<output name> ]
@@ -907,6 +908,12 @@ Usage: btt 2.05
   This option instructs \texttt{btt} to generate the D2C latency file
   discussed in section~\ref{sec:lat-d2c}.
 
+\subsection{\label{sec:o-L}\texttt{--periodic-latencies}/\texttt{-L}}
+
+  When given a value greater than 0, this option will create two data
+  files (q2c \& d2c) per device containing a periodic timestamp \&
+  average latency over that period.
+
 \subsection{\label{sec:o-m}\texttt{--seeks-per-second}\texttt{-m}}
 
   Tells \texttt{btt} to output seeks per second information.  Each device
index bf1d656f37167462e7ad88e267f3aaa03abe11bd..8b804ee690d64c0c51d13af8c1aeac040923a7b8 100644 (file)
@@ -146,7 +146,7 @@ struct d_info {
        struct region_info regions;
        struct devmap *map;
        void *q2q_handle, *seek_handle, *bno_dump_handle, *unplug_hist_handle;
-       void *q2d_priv, *aqd_handle;
+       void *q2d_priv, *aqd_handle, *q2c_plat_handle, *d2c_plat_handle;
        FILE *d2c_ofp, *q2c_ofp;
        struct avgs_info avgs;
        struct stats stats, all_stats;
@@ -181,7 +181,7 @@ struct io {
 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;
-extern double range_delta;
+extern double range_delta, plat_freq;
 extern FILE *ranges_ofp, *avgs_ofp, *xavgs_ofp, *iostat_ofp, *per_io_ofp;
 extern FILE *msgs_ofp;
 extern int verbose, done, time_bounded, output_all_data, seek_absolute;
@@ -204,6 +204,8 @@ void clean_args();
 
 /* aqd.c */
 void *aqd_init(char *str);
+void aqd_exit(void *info);
+void aqd_clean(void);
 void aqd_issue(void *info, double ts);
 void aqd_complete(void *info, double ts);
 
@@ -282,6 +284,12 @@ void bno_dump_exit(void *param);
 void bno_dump_add(void *handle, struct io *iop);
 void bno_dump_clean(void);
 
+/* plat.c */
+void *plat_init(char *str);
+void plat_exit(void *info);
+void plat_clean(void);
+void plat_x2c(void *info, __u64 ts, __u64 latency);
+
 /* q2d.c */
 void q2d_histo_add(void *priv, __u64 q2d);
 void *q2d_init(void);
index 916f566e7e7f3a28cca9867b15934ef3a6bf784f..4fb02d5c27da772045211b696017f8858c8d3451 100644 (file)
@@ -62,10 +62,12 @@ void latency_clean(void)
 
 void latency_d2c(struct d_info *dip, __u64 tstamp, __u64 latency)
 {
+       plat_x2c(dip->d2c_plat_handle, tstamp, latency);
        latency_out(dip->d2c_ofp, tstamp, latency);
 }
 
 void latency_q2c(struct d_info *dip, __u64 tstamp, __u64 latency)
 {
+       plat_x2c(dip->q2c_plat_handle, tstamp, latency);
        latency_out(dip->q2c_ofp, tstamp, latency);
 }
diff --git a/btt/plat.c b/btt/plat.c
new file mode 100644 (file)
index 0000000..9b7a2a1
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * blktrace output analysis: generate a timeline & gather statistics
+ *
+ * (C) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ *     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 "globals.h"
+
+struct plat_info {
+       long nl;
+       FILE *fp;
+       double first_ts, last_ts, tl;
+};
+
+static struct file_info *plat_files = NULL;
+
+void *plat_init(char *str)
+{
+       char *oname;
+       struct plat_info *pp;
+
+       if (plat_freq <= 0.0) return NULL;
+
+       pp = malloc(sizeof(*pp));
+       pp->nl = 0;
+       pp->first_ts = pp->last_ts = pp->tl = -1.0;
+
+       oname = malloc(strlen(str) + 32);
+       sprintf(oname, "%s.dat", str);
+       if ((pp->fp = fopen(oname, "w")) == NULL) {
+               perror(oname);
+               return NULL;
+       }
+       add_file(&plat_files, pp->fp, oname);
+
+       return pp;
+}
+
+void plat_exit(void *info)
+{
+       struct plat_info *pp = info;
+
+       if (pp == NULL) return;
+
+       if (pp->first_ts != -1.0) {
+               double delta = pp->last_ts - pp->first_ts;
+
+               fprintf(pp->fp, "%lf %lf\n",
+                       pp->first_ts + (delta / 2), pp->tl / pp->nl);
+       }
+       free(info);
+}
+
+void plat_clean(void)
+{
+       clean_files(&plat_files);
+}
+
+void plat_x2c(void *info, __u64 ts, __u64 latency)
+{
+       double now = TO_SEC(ts);
+       double lat = TO_SEC(latency);
+       struct plat_info *pp = info;
+
+       if (pp == NULL) return;
+
+       if (pp->first_ts == -1.0) {
+               pp->first_ts = pp->last_ts = now;
+               pp->nl = 1;
+               pp->tl = lat;
+       }
+       else if ((now - pp->first_ts) >= plat_freq) {
+               double delta = pp->last_ts - pp->first_ts;
+
+               fprintf(pp->fp, "%lf %lf\n",
+                       pp->first_ts + (delta / 2), pp->tl / pp->nl);
+
+               pp->first_ts = pp->last_ts = now;
+               pp->nl = 1;
+               pp->tl = lat;
+       }
+       else {
+               pp->last_ts = now;
+               pp->nl += 1;
+               pp->tl += lat;
+       }
+}
index 84275a53e22e1b81bb23042d91fa80e2ad3747f9..55bc62aacf3935b0aef6f684fdf401e4b3cd9ed6 100644 (file)
--- a/doc/btt.1
+++ b/doc/btt.1
@@ -27,6 +27,8 @@ btt \- analyse block i/o traces produces by blktrace
 .br
 [ \-l <\fIoutput name\fR> | \-\-d2c\-latencies=<\fIoutput name\fR> ]
 .br
+[ \-L <\fIfreq\fR>        | \-\-periodic\-latencies=<\fIfreq\fR> ]
+.br
 [ \-M <\fIdev map\fR>     | \-\-dev\-maps=<\fIdev map\fR>
 .br
 [ \-o <\fIoutput name\fR> | \-\-output\-file=<\fIoutput name\fR> ]
@@ -181,6 +183,15 @@ respectively. The supplied argument provides the basis for the output
 name for each device.
 .RE
 
+.B \-L <\fIfreq\fR>
+.br
+.B \-\-periodic\-latencies=<\fIfreq\fR>
+.RS 4
+The \-L option allows one to output periodic latency information for both
+Q2C and D2C latencies. The frequency specified will regulate how often
+an average latency is output -- a floating point value expressing seconds.
+.RE
+
 .B \-M <\fIdev map\fR>
 .br
 .B \-\-dev\-maps=<\fIdev map\fR>