[blktrace-tools RFC PATCH 4/5] blktrace: add support for trace extension

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Update blktrace tool to support the trace extensions. The new option
'-E' will allow blktrace to configure trace with newly introduced
IOCTLs for trace extensions. '-Y' and '-y' options are similar to
'-a' and '-A' but can now use the mask for additional operations
which are supported for trace-extension. For tracking the priority we
add '-P' along with the '-X' and '-x' to specify priority value and
mask.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@xxxxxxx>
---
 blktrace.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 315 insertions(+), 27 deletions(-)

diff --git a/blktrace.c b/blktrace.c
index d0d271f..b8b36c2 100644
--- a/blktrace.c
+++ b/blktrace.c
@@ -112,7 +112,7 @@ struct devpath {
 	struct cl_host *ch;
 	u32 cl_id;
 	time_t cl_connect_time;
-	int setup_done;	/* ioctl BLKTRACESETUP done */
+	int setup_done;	/* ioctl BLKTRACESETUP or BLKTRACESETUP_EXT done */
 	struct io_info *ios;
 };
 
@@ -274,12 +274,16 @@ static char blktrace_version[] = "2.0.0";
  */
 int data_is_native = -1;
 
+static bool use_ext = false;
 static int ndevs;
 static int max_cpus;
 static int ncpus;
 static cpu_set_t *online_cpus;
 static int pagesize;
 static int act_mask = ~0U;
+static uint64_t act_mask_ext = -1ULL;
+static uint32_t blktrace_prio_mask = 0;
+bool blktrace_track_prio = false;
 static int kill_running_trace;
 static int stop_watch;
 static int piped_output;
@@ -329,7 +333,7 @@ static int *cl_fds;
 static int (*handle_pfds)(struct tracer *, int, int);
 static int (*handle_list)(struct tracer_devpath_head *, struct list_head *);
 
-#define S_OPTS	"d:a:A:r:o:kw:vVb:n:D:lh:p:sI:"
+#define S_OPTS	"d:a:A:r:o:kw:vVb:n:D:lh:p:sI:Px:X:y:Y:E"
 static struct option l_opts[] = {
 	{
 		.name = "dev",
@@ -355,6 +359,24 @@ static struct option l_opts[] = {
 		.flag = NULL,
 		.val = 'A'
 	},
+	{
+		.name = "act-mask-ext",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'y'
+	},
+	{
+		.name = "set-mask-ext",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'Y'
+	},
+	{
+		.name = "use-extensions",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'E'
+	},
 	{
 		.name = "relay",
 		.has_arg = required_argument,
@@ -427,6 +449,24 @@ static struct option l_opts[] = {
 		.flag = NULL,
 		.val = 'p'
 	},
+	{
+		.name = "track-priority",
+		.has_arg = no_argument,
+		.flag = NULL,
+		.val = 'P'
+	},
+	{
+		.name = "prio-mask",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'x'
+	},
+	{
+		.name = "prio-set-mask",
+		.has_arg = required_argument,
+		.flag = NULL,
+		.val = 'X'
+	},
 	{
 		.name = "no-sendfile",
 		.has_arg = no_argument,
@@ -439,23 +479,30 @@ static struct option l_opts[] = {
 };
 
 static char usage_str[] = "\n\n" \
-	"-d <dev>             | --dev=<dev>\n" \
-        "[ -r <debugfs path>  | --relay=<debugfs path> ]\n" \
-        "[ -o <file>          | --output=<file>]\n" \
-        "[ -D <dir>           | --output-dir=<dir>\n" \
-        "[ -w <time>          | --stopwatch=<time>]\n" \
-        "[ -a <action field>  | --act-mask=<action field>]\n" \
-        "[ -A <action mask>   | --set-mask=<action mask>]\n" \
-        "[ -b <size>          | --buffer-size]\n" \
-        "[ -n <number>        | --num-sub-buffers=<number>]\n" \
-        "[ -l                 | --listen]\n" \
-        "[ -h <hostname>      | --host=<hostname>]\n" \
-        "[ -p <port number>   | --port=<port number>]\n" \
-        "[ -s                 | --no-sendfile]\n" \
-        "[ -I <devs file>     | --input-devs=<devs file>]\n" \
-        "[ -v <version>       | --version]\n" \
-        "[ -V <version>       | --version]\n" \
-
+	"-d <dev>                | --dev=<dev>\n" \
+	"[ -E                    | --use-extensions ]\n" \
+	"[ -r <debugfs path>     | --relay=<debugfs path> ]\n" \
+	"[ -o <file>             | --output=<file>]\n" \
+	"[ -D <dir>              | --output-dir=<dir>\n" \
+	"[ -w <time>             | --stopwatch=<time>]\n" \
+	"[ -a <action field>     | --act-mask=<action field>]\n" \
+	"[ -A <action mask>      | --set-mask-ext=<action mask ext>]\n" \
+	"[ -y <action field ext> | --act-mask-ext=<action field ext>]\n" \
+	"[ -Y <action mask ext>  | --set-mask=<action mask>]\n" \
+	"[ -b <size>             | --buffer-size]\n" \
+	"[ -n <number>           | --num-sub-buffers=<number>]\n" \
+	"[ -l                    | --listen]\n" \
+	"[ -h <hostname>         | --host=<hostname>]\n" \
+	"[ -p <port number>      | --port=<port number>]\n" \
+	"[ -s                    | --no-sendfile]\n" \
+	"[ -I <devs file>        | --input-devs=<devs file>]\n" \
+	"[ -P                    | --track-priority ]\n" \
+	"[ -x <ioprio field>     | --prio-mask=<ioprio field> ]\n" \
+	"[ -X <ioprio mask>      | --set-mask=<ioprio mask> ]\n" \
+	"[ -v <version>          | --version]\n" \
+	"[ -V <version>          | --version]\n" \
+
+	"\t-E Use Blocktrace Extensions\n" \
 	"\t-d Use specified device. May also be given last after options\n" \
 	"\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
 	"\t-o File(s) to send output to\n" \
@@ -470,6 +517,11 @@ static char usage_str[] = "\n\n" \
 	"\t-p Network port to use (default 8462)\n" \
 	"\t-s Make the network client NOT use sendfile() to transfer data\n" \
 	"\t-I Add devices found in <devs file>\n" \
+	"\t-P Enable tracking priorites.\n" \
+	"\t-y Only trace specified actions ext.\n" \
+	"\t-Y Give trace mask as a single value ext.\n" \
+	"\t-x Only priority specified actions.\n" \
+	"\t-X Give priority mask as a single value.\n" \
 	"\t-v Print program version info\n" \
 	"\t-V Print program version info\n\n";
 
@@ -784,7 +836,7 @@ static int setup_mmap(int fd, unsigned int maxlen,
 	return 0;
 }
 
-static int __stop_trace(int fd)
+static int __stop_tear_trace(int fd)
 {
 	/*
 	 * Should be stopped, don't complain if it isn't
@@ -793,6 +845,20 @@ static int __stop_trace(int fd)
 	return ioctl(fd, BLKTRACETEARDOWN);
 }
 
+static int __stop_tear_trace_ext(int fd)
+{
+	/*
+	 * Should be stopped, don't complain if it isn't
+	 */
+	ioctl(fd, BLKTRACESTOP_EXT);
+	return ioctl(fd, BLKTRACETEARDOWN_EXT);
+}
+
+static int __stop_trace(int fd)
+{
+	return use_ext ? __stop_tear_trace_ext(fd) : __stop_tear_trace(fd);
+}
+
 static int write_data(char *buf, int len)
 {
 	int ret;
@@ -1067,7 +1133,7 @@ static void close_client_connections(void)
 	}
 }
 
-static int setup_buts(void)
+static int __setup_buts(void)
 {
 	struct list_head *p;
 	int ret = 0;
@@ -1099,7 +1165,45 @@ static int setup_buts(void)
 	return ret;
 }
 
-static void start_buts(void)
+static int __setup_buts_ext(void)
+{
+	struct list_head *p;
+	int ret = 0;
+
+	__list_for_each(p, &devpaths) {
+		struct blk_user_trace_setup_ext buts;
+		struct devpath *dpp = list_entry(p, struct devpath, head);
+
+		memset(&buts, 0, sizeof(buts));
+		buts.buf_size = buf_size;
+		buts.buf_nr = buf_nr;
+		buts.act_mask = act_mask_ext;
+		buts.prio_mask = blktrace_prio_mask;
+
+		if (ioctl(dpp->fd, BLKTRACESETUP_EXT, &buts) >= 0) {
+			dpp->ncpus = max_cpus;
+			dpp->buts_name = strdup(buts.name);
+			dpp->setup_done = 1;
+			if (dpp->stats)
+				free(dpp->stats);
+			dpp->stats = calloc(dpp->ncpus, sizeof(*dpp->stats));
+			memset(dpp->stats, 0, dpp->ncpus * sizeof(*dpp->stats));
+		} else {
+			fprintf(stderr, "BLKTRACESETUP_EXT(2) %s failed: %d/%s\n",
+				dpp->path, errno, strerror(errno));
+			ret++;
+		}
+	}
+
+	return ret;
+}
+
+static int setup_buts(void)
+{
+	return use_ext ? __setup_buts_ext() : __setup_buts();
+}
+
+static void __start_buts(void)
 {
 	struct list_head *p;
 
@@ -1113,6 +1217,25 @@ static void start_buts(void)
 	}
 }
 
+static void __start_buts_ext(void)
+{
+	struct list_head *p;
+
+	__list_for_each(p, &devpaths) {
+		struct devpath *dpp = list_entry(p, struct devpath, head);
+
+		if (ioctl(dpp->fd, BLKTRACESTART_EXT) < 0) {
+			fprintf(stderr, "BLKTRACESTART_EXT %s failed: %d/%s\n",
+				dpp->path, errno, strerror(errno));
+		}
+	}
+}
+
+static void start_buts(void)
+{
+	use_ext ? __start_buts_ext() : __start_buts();
+}
+
 static int get_drops(struct devpath *dpp)
 {
 	int fd, drops = 0;
@@ -1432,6 +1555,72 @@ static int handle_list_file(struct tracer_devpath_head *hd,
 	return entries_handled;
 }
 
+static int handle_list_file_ext(struct tracer_devpath_head *hd,
+			    struct list_head *list)
+{
+	int off, t_len, nevents;
+	struct blk_io_trace_ext *t;
+	struct list_head *p, *q;
+	int entries_handled = 0;
+	struct trace_buf *tbp, *prev;
+
+	prev = hd->prev;
+
+	list_for_each_safe(p, q, list) {
+		tbp = list_entry(p, struct trace_buf, head);
+		list_del(&tbp->head);
+		entries_handled++;
+
+		/*
+		 * If there was some leftover before, tack this new
+		 * entry onto the tail of the previous one.
+		 */
+		if (prev)
+			tbp = tb_combine(prev, tbp);
+
+		/*
+		 * See how many whole traces there are - send them
+		 * all out in one go.
+		 */
+		off = 0;
+		nevents = 0;
+		while (off + (int)sizeof(*t) <= tbp->len) {
+			t = (struct blk_io_trace_ext *)(tbp->buf + off);
+			t_len = sizeof(*t) + t->pdu_len;
+			if (off + t_len > tbp->len)
+				break;
+
+			off += t_len;
+			nevents++;
+		}
+		if (nevents)
+			pdc_nev_update(tbp->dpp, tbp->cpu, nevents);
+
+		/*
+		 * Write any full set of traces, any remaining data is kept
+		 * for the next pass.
+		 */
+		if (off) {
+			if (write_data(tbp->buf, off) || off == tbp->len) {
+				free(tbp);
+				prev = NULL;
+			}
+			else {
+				/*
+				 * Move valid data to beginning of buffer
+				 */
+				tbp->len -= off;
+				memmove(tbp->buf, tbp->buf + off, tbp->len);
+				prev = tbp;
+			}
+		} else
+			prev = tbp;
+	}
+	hd->prev = prev;
+
+	return entries_handled;
+}
+
 static void __process_trace_bufs(void)
 {
 	int cpu;
@@ -1954,7 +2143,7 @@ static void start_tracers(void)
 	}
 }
 
-static void stop_tracers(void)
+static void __stop_tracers(void)
 {
 	struct list_head *p;
 
@@ -1976,6 +2165,34 @@ static void stop_tracers(void)
 	pthread_cond_broadcast(&mt_cond);
 }
 
+static void __stop_tracers_ext(void)
+{
+	struct list_head *p;
+
+	/*
+	 * Stop the tracing - makes the tracer threads clean up quicker.
+	 */
+	__list_for_each(p, &devpaths) {
+		struct devpath *dpp = list_entry(p, struct devpath, head);
+
+		(void)ioctl(dpp->fd, BLKTRACESTOP_EXT);
+	}
+
+	/*
+	 * Tell each tracer to quit
+	 */
+	__list_for_each(p, &tracers) {
+		struct tracer *tp = list_entry(p, struct tracer, head);
+		tp->is_done = 1;
+	}
+	pthread_cond_broadcast(&mt_cond);
+}
+
+static void stop_tracers(void)
+{
+	use_ext ? __stop_tracers_ext() : __stop_tracers();
+}
+
 static void del_tracers(void)
 {
 	struct list_head *p, *q;
@@ -2063,7 +2280,11 @@ static void show_stats(struct list_head *devpaths)
 			 * Estimate events if not known...
 			 */
 			if (sp->nevents == 0) {
-				sp->nevents = sp->data_read /
+				if (use_ext)
+					sp->nevents = sp->data_read /
+						sizeof(struct blk_io_trace_ext);
+				else
+					sp->nevents = sp->data_read /
 						sizeof(struct blk_io_trace);
 			}
 
@@ -2105,6 +2326,7 @@ static int handle_args(int argc, char *argv[])
 	int c, i;
 	struct statfs st;
 	int act_mask_tmp = 0;
+	uint64_t act_mask_tmp_ext = 0;
 
 	while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) >= 0) {
 		switch (c) {
@@ -2129,11 +2351,35 @@ static int handle_args(int argc, char *argv[])
 			act_mask_tmp = i;
 			break;
 
+		case 'y':
+			i = find_mask_map_ext(optarg);
+			if (i < 0) {
+				fprintf(stderr, "Invalid action mask %s\n",
+					optarg);
+				return 1;
+			}
+			act_mask_tmp_ext |= i;
+			break;
+
+		case 'Y':
+			if ((sscanf(optarg, "%x", &i) != 1) ||
+							!valid_act_opt_ext(i)) {
+				fprintf(stderr,
+					"Invalid set action mask %s/0x%x\n",
+					optarg, i);
+				return 1;
+			}
+			act_mask_tmp_ext = i;
+			break;
+
 		case 'd':
 			if (add_devpath(optarg) != 0)
 				return 1;
 			break;
 
+		case 'E': /* use blktrace extensions */
+			use_ext = true;
+			break;
 		case 'I': {
 			char dev_line[256];
 			FILE *ifp = my_fopen(optarg, "r");
@@ -2211,6 +2457,27 @@ static int handle_args(int argc, char *argv[])
 		case 'p':
 			net_port = atoi(optarg);
 			break;
+		case 'P': /* enable priority tracking */
+			blktrace_track_prio = true;
+			break;
+		case 'x': /* priority mask values in string */
+			i = find_prio_mask_map(optarg);
+			if (i < 0) {
+				fprintf(stderr,"Invalid prio mask %s\n",
+						optarg);
+				return 1;
+			}
+			blktrace_prio_mask |= i;
+			break;
+		case 'X': /* priority mask values in hex */
+			if ((sscanf(optarg, "%x", &i) != 1) ||
+					!valid_prio_opt(i)) {
+				fprintf(stderr, "Invalid prio mask %s/0x%x\n",
+						optarg, i);
+				return 1;
+			}
+			blktrace_prio_mask = i;
+			break;
 		case 's':
 			net_use_sendfile = 0;
 			break;
@@ -2241,8 +2508,28 @@ static int handle_args(int argc, char *argv[])
 		return 1;
 	}
 
-	if (act_mask_tmp != 0)
-		act_mask = act_mask_tmp;
+	if (use_ext) {
+		if (act_mask_tmp) {
+			fprintf(stderr, "please use y or Y with -E\n");
+			return 1;
+		}
+		if (act_mask_tmp_ext != 0)
+			act_mask_ext = act_mask_tmp_ext;
+		/*
+		 * When track-priority is on and user didn't specify prio_mask then
+		 * trace all the classes.
+		 */
+		if (blktrace_track_prio && !blktrace_prio_mask)
+			blktrace_prio_mask = TRACE_ALL_IOPRIO;
+	} else {
+		if (act_mask_tmp != 0)
+			act_mask = act_mask_tmp;
+	}
+
+	if (!use_ext && (blktrace_track_prio || blktrace_prio_mask)) {
+		fprintf(stderr,"please specify -E with -P or -X or -x\n");
+		return 1;
+	}
 
 	if (net_mode == Net_client && net_setup_addr())
 		return 1;
@@ -2692,7 +2979,8 @@ static int run_tracers(void)
 			return 1;
 
 		if (piped_output)
-			handle_list = handle_list_file;
+			handle_list = use_ext ? handle_list_file_ext :
+				handle_list_file;
 		else
 			handle_list = handle_list_net;
 	}
-- 
2.19.1




[Index of Archives]     [Netdev]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux