From: Alan David Brunelle Date: Thu, 21 Sep 2006 07:17:43 +0000 (+0200) Subject: [PATCH] Added in Q2C and D2C latency output option. X-Git-Tag: blktrace-0.99.2~18 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=b2ecdd0fc9f93e7a2bea09dcd7b2c472eb4e0d94;p=blktrace.git [PATCH] Added in Q2C and D2C latency output option. Also: cleaned up empty seek and latency files on exit. Signed-off-by: Alan D. Brunelle Signed-off-by: Jens Axboe --- diff --git a/btt/Makefile b/btt/Makefile index b86e828..2d60eed 100644 --- a/btt/Makefile +++ b/btt/Makefile @@ -1,14 +1,14 @@ CC = gcc MYFLAGS = -DLVM_REMAP_WORKAROUND -CFLAGS = -Wall -O2 -W -g -#CFLAGS = -Wall -g -W -UDO_INLINE -DDEBUG +#CFLAGS = -Wall -O2 -W -g +CFLAGS = -Wall -g -W -UDO_INLINE -DDEBUG ALL_CFLAGS = $(CFLAGS) -I.. -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PROGS = btt #ELIBS = -lefence #PLIBS = -lpthread LIBS = $(PLIBS) $(ELIBS) OBJS = bt_timeline.o args.o output.o proc.o trace.o misc.o devs.o \ - traverse.o iofree.o devmap.o cylist.o seek.o iostat.o + traverse.o iofree.o devmap.o cylist.o seek.o iostat.o latency.o all: depend $(PROGS) diff --git a/btt/README b/btt/README index 41ecdc4..938f9ce 100644 --- a/btt/README +++ b/btt/README @@ -13,8 +13,10 @@ Usage: btt [ -h | --help ] [ -i | --input-file= ] [ -I | --iostat= ] + [ -l | --d2c-latencies= ] [ -M | --dev-maps= [ -o | --output-file= ] + [ -q | --q2c-latencies= ] [ -s | --seeks= ] [ -S | --iostat-interval= ] [ -V | --version ] @@ -41,6 +43,10 @@ file. Refer to the iostat (sysstat) documentation for details on the data columns. The -S option specifies the interval to use between data output, it defaults to once per second. +The -l and -q options allow one to output per-IO D2C and Q2C latencies +respectively. The supplied argument provides the basis for the output +name for each device. + The -M option takes in a file generated by the provided script (gen_disk_info.py), and allows for better output of device names. diff --git a/btt/args.c b/btt/args.c index 7b4d0ee..9dcb694 100644 --- a/btt/args.c +++ b/btt/args.c @@ -28,7 +28,7 @@ #include "globals.h" -#define S_OPTS "d:D:e:hi:I:M:o:s:S:Vv" +#define S_OPTS "d:D:e:hi:I:l:M:o:q:s:S:Vv" static struct option l_opts[] = { { .name = "range-delta", @@ -66,6 +66,12 @@ static struct option l_opts[] = { .flag = NULL, .val = 'I' }, + { + .name = "d2c-latencies", + .has_arg = required_argument, + .flag = NULL, + .val = 'l' + }, { .name = "dev-maps", .has_arg = required_argument, @@ -78,6 +84,12 @@ static struct option l_opts[] = { .flag = NULL, .val = 'o' }, + { + .name = "q2c-latencies", + .has_arg = required_argument, + .flag = NULL, + .val = 'q' + }, { .name = "seeks", .has_arg = required_argument, @@ -114,8 +126,10 @@ static char usage_str[] = \ "[ -h | --help ]\n" \ "[ -i | --input-file= ]\n" \ "[ -I | --iostat= ]\n" \ + "[ -l | --d2c-latencies= ]\n" \ "[ -M | --dev-maps=\n" \ "[ -o | --output-file= ]\n" \ + "[ -q | --q2c-latencies= ]\n" \ "[ -s | --seeks= ]\n" \ "[ -S | --iostat-interval= ]\n" \ "[ -V | --version ]\n" \ @@ -149,6 +163,9 @@ void handle_args(int argc, char *argv[]) case 'i': input_name = optarg; break; + case 'l': + d2c_name = optarg; + break; case 'I': iostat_name = optarg; break; @@ -158,6 +175,9 @@ void handle_args(int argc, char *argv[]) case 'o': output_name = optarg; break; + case 'q': + q2c_name = optarg; + break; case 's': seek_name = optarg; break; diff --git a/btt/bt_timeline.c b/btt/bt_timeline.c index 9e69fe5..9d07382 100644 --- a/btt/bt_timeline.c +++ b/btt/bt_timeline.c @@ -31,6 +31,8 @@ char *exes = NULL; char *input_name = NULL; char *output_name = NULL; char *seek_name = NULL; +char *d2c_name = NULL; +char *q2c_name = NULL; double range_delta = 0.1; FILE *ranges_ofp, *avgs_ofp; int verbose = 0; @@ -97,6 +99,9 @@ int process(void) iostat_dump_stats(iostat_last_stamp, 1); } + seek_clean(); + latency_clean(); + if (verbose) printf("\n%10lu traces, %10lu mallocs %1lu frees\n", n_traces, n_io_allocs, n_io_frees); diff --git a/btt/devs.c b/btt/devs.c index 2801804..1d41ee9 100644 --- a/btt/devs.c +++ b/btt/devs.c @@ -69,6 +69,7 @@ struct d_info *dip_add(__u32 device, struct io *iop) init_region(&dip->regions); dip->map = dev_map_find(device); dip->seek_handle = seeki_init(device); + latency_init(dip); memset(&dip->stats, 0, sizeof(dip->stats)); memset(&dip->all_stats, 0, sizeof(dip->all_stats)); diff --git a/btt/globals.h b/btt/globals.h index de67e04..4a53140 100644 --- a/btt/globals.h +++ b/btt/globals.h @@ -34,6 +34,9 @@ #define IOP_READ(iop) ((iop)->t.action & BLK_TC_ACT(BLK_TC_READ)) #define IOP_RW(iop) (IOP_READ(iop) ? 1 : 0) +#define TO_SEC(nanosec) ((double)(nanosec) / 1.0e9) +#define TO_MSEC(nanosec) (1000.0 * TO_SEC(nanosec)) + #if defined(DEBUG) #define ASSERT(truth) do { \ if (!(truth)) { \ @@ -72,6 +75,12 @@ enum iop_type { }; #define N_IOP_TYPES (IOP_Y + 1) +struct file_info { + struct file_info *next; + FILE *ofp; + char *oname; +}; + struct my_mem { struct my_mem *next; }; @@ -157,6 +166,7 @@ struct d_info { __u64 n_ds; struct devmap *map; void *seek_handle; + FILE *d2c_ofp, *q2c_ofp; struct stats stats, all_stats; }; @@ -204,7 +214,7 @@ struct io { }; extern char bt_timeline_version[], *devices, *exes, *input_name, *output_name; -extern char *seek_name, *iostat_name; +extern char *seek_name, *iostat_name, *d2c_name, *q2c_name; extern double range_delta; extern FILE *ranges_ofp, *avgs_ofp, *iostat_ofp; extern int verbose, ifd; @@ -240,11 +250,14 @@ struct d_info *dip_add(__u32 device, struct io *iop); void traverse(struct io *iop); void io_free_resources(struct io *iop); void *seeki_init(__u32 device); +void seek_clean(void); void seeki_add(void *handle, struct io *iop); double seeki_mean(void *handle); long long seeki_nseeks(void *handle); long long seeki_median(void *handle); int seeki_mode(void *handle, long long **modes_p, int *nseeks_p); +void add_file(struct file_info **fipp, FILE *fp, char *oname); +void clean_files(struct file_info **fipp); void iostat_init(void); void iostat_insert(struct io *iop); @@ -254,4 +267,9 @@ void iostat_complete(struct io *iop); void iostat_check_time(__u64 stamp); void iostat_dump_stats(__u64 stamp, int all); +void latency_init(struct d_info *dip); +void latency_clean(void); +void latency_d2c(struct d_info *dip, __u64 tstamp, __u64 latency); +void latency_q2c(struct d_info *dip, __u64 tstamp, __u64 latency); + #include "inlines.h" diff --git a/btt/latency.c b/btt/latency.c new file mode 100644 index 0000000..916f566 --- /dev/null +++ b/btt/latency.c @@ -0,0 +1,71 @@ +/* + * blktrace output analysis: generate a timeline & gather statistics + * + * Copyright (C) 2006 Alan D. Brunelle + * + * 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" + +static struct file_info *all_files = NULL; + +static inline void latency_out(FILE *ofp, __u64 tstamp, __u64 latency) +{ + if (ofp) + fprintf(ofp, "%lf %lf\n", TO_SEC(tstamp), TO_SEC(latency)); +} + +FILE *latency_open(__u32 device, char *name, char *post) +{ + FILE *fp; + char *oname; + int mjr, mnr; + + if (name == NULL) return NULL; + + mjr = device >> MINORBITS; + mnr = device & ((1 << MINORBITS) - 1); + + oname = malloc(strlen(name)+32); + sprintf(oname, "%s_%03d,%03d_%s.dat", name, mjr, mnr, post); + if ((fp = fopen(oname, "w")) == NULL) + perror(oname); + else + add_file(&all_files, fp, oname); + + return fp; +} + +void latency_init(struct d_info *dip) +{ + dip->d2c_ofp = latency_open(dip->device, d2c_name, "d2c"); + dip->q2c_ofp = latency_open(dip->device, q2c_name, "q2c"); +} + +void latency_clean(void) +{ + clean_files(&all_files); +} + +void latency_d2c(struct d_info *dip, __u64 tstamp, __u64 latency) +{ + latency_out(dip->d2c_ofp, tstamp, latency); +} + +void latency_q2c(struct d_info *dip, __u64 tstamp, __u64 latency) +{ + latency_out(dip->q2c_ofp, tstamp, latency); +} diff --git a/btt/misc.c b/btt/misc.c index 8659db7..e0e396c 100644 --- a/btt/misc.c +++ b/btt/misc.c @@ -20,6 +20,8 @@ */ #include #include +#include +#include #include #define INLINE_DECLARE @@ -82,3 +84,29 @@ unsigned int do_read(int ifd, void *buf, int len) return 0; } + +void add_file(struct file_info **fipp, FILE *fp, char *oname) +{ + struct file_info *fip = malloc(sizeof(struct file_info)); + + fip->ofp = fp; + fip->oname = oname; + fip->next = *fipp; + *fipp = fip; +} + +void clean_files(struct file_info **fipp) +{ + struct stat buf; + struct file_info *fip; + + while ((fip = *fipp) != NULL) { + *fipp = fip->next; + + fclose(fip->ofp); + if (!stat(fip->oname, &buf) && (buf.st_size == 0)) + unlink(fip->oname); + free(fip->oname); + free(fip); + } +} diff --git a/btt/seek.c b/btt/seek.c index 9ee8eec..3003611 100644 --- a/btt/seek.c +++ b/btt/seek.c @@ -20,6 +20,8 @@ */ #include "globals.h" +static struct file_info *all_files = NULL; + struct seek_bkt { long long sectors; int nseeks; @@ -45,14 +47,21 @@ FILE *seek_open(__u32 device, char rw) mjr = device >> MINORBITS; mnr = device & ((1 << MINORBITS) - 1); - oname = malloc(strlen(seek_name + 32)); + oname = malloc(strlen(seek_name)+32); sprintf(oname, "%s_%03d,%03d_%c.dat", seek_name, mjr, mnr, rw); if ((fp = fopen(oname, "w")) == NULL) perror(oname); + else + add_file(&all_files, fp, oname); return fp; } +void seek_clean(void) +{ + clean_files(&all_files); +} + long long seek_dist(struct seeki *sip, struct io *iop) { long long dist; diff --git a/btt/traverse.c b/btt/traverse.c index fd4a847..d48755a 100644 --- a/btt/traverse.c +++ b/btt/traverse.c @@ -74,7 +74,10 @@ void traverse(struct io *iop) void iop_q_update(__u64 *timeline, struct io *iop, __u64 q_time) { - update_q2c(iop, timeline[IOP_C] - q_time); + __u64 q2c = timeline[IOP_C] - q_time; + + update_q2c(iop, q2c); + latency_q2c(iop->dip, iop->t.time, q2c); if (timeline[IOP_A] > 0.0) // IOP_X too update_q2a(iop, timeline[IOP_A] - q_time); @@ -82,7 +85,6 @@ void iop_q_update(__u64 *timeline, struct io *iop, __u64 q_time) update_q2i(iop, timeline[IOP_I] - q_time); update_i2d(iop, timeline[IOP_D] - timeline[IOP_I]); - update_d2c(iop, timeline[IOP_C] - timeline[IOP_D]); } void iop_q_func(__u64 *timeline, struct io *iop) @@ -127,11 +129,15 @@ void iop_d_func(__u64 *timeline, struct io *iop) { struct list_head *p; struct io_list *iolp; + __u64 d2c = timeline[IOP_C] - iop->t.time; __list_for_each(p, &iop->u.d.d_im_head) { iolp = list_entry(p, struct io_list, head); __traverse(timeline, iolp->iop); } + + update_d2c(iop, d2c); + latency_d2c(iop->dip, iop->t.time, d2c); } void iop_c_func(__u64 *timeline, struct io *iop)