[sheepdog] [PATCH v2 5/7] collie: rework debug trace funtions to use subcommand mechanism

Liu Yuan namei.unix at gmail.com
Thu Aug 30 11:39:02 CEST 2012


From: Liu Yuan <tailai.ly at taobao.com>

The new look is:

tailai.ly at taobao:~/sheepdog$ collie/collie debug trace
Usage: collie debug trace {start|stop|cat} [-a address] [-p port] [-h]
Available subcommands:
  start                   start the trace
  stop                    stop the trace
  cat                     cat the trace
Options:
  -a, --address           specify the daemon address (default: localhost)
  -p, --port              specify the daemon port
  -h, --help              display this help and exit

The change is that 'stop' command actually read all the buffer to /tmp/tracefile
then we can 'cat' this file until it is overridden by next trace.

Signed-off-by: Liu Yuan <tailai.ly at taobao.com>
---
 collie/debug.c  |  192 ++++++++++++++++++++++++++++++++++++++++++-------------
 include/sheep.h |    1 -
 2 files changed, 149 insertions(+), 44 deletions(-)

diff --git a/collie/debug.c b/collie/debug.c
index 2be873f..f16a8dc 100644
--- a/collie/debug.c
+++ b/collie/debug.c
@@ -1,112 +1,194 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
 
 #include "collie.h"
 
-static void print_trace_item(struct trace_graph_item *item)
+static inline void print_thread_name(struct trace_graph_item *item)
 {
-	int i;
+	printf("%-20s|", item->tname);
+}
 
-	if (item->type == TRACE_GRAPH_ENTRY) {
-		printf("             |  ");
-		for (i = 0; i < item->depth; i++)
-			printf("   ");
-		printf("%s() {\n", item->fname);
-	} else {
+static inline void print_time(struct trace_graph_item *item)
+{
+	if (item->type == TRACE_GRAPH_RETURN) {
 		unsigned duration = item->return_time - item->entry_time;
 		unsigned quot = duration / 1000, rem = duration % 1000;
-		printf("%8u.%-3u |  ", quot, rem);
-		for (i = 0; i < item->depth; i++)
-			printf("   ");
-		printf("}\n");
+
+		printf("%8u.%-3u|", quot, rem);
+	} else if (item->type == TRACE_GRAPH_ENTRY) {
+		printf("            |");
 	}
 }
 
+static inline void print_finale(struct trace_graph_item *item)
+{
+	int i;
+
+	for (i = 0; i < item->depth; i++)
+		printf("   ");
+	if (item->type == TRACE_GRAPH_ENTRY)
+		printf("%s() {\n", item->fname);
+	else
+		printf("}\n");
+}
+
+static void print_trace_item(struct trace_graph_item *item)
+{
+	print_thread_name(item);
+	print_time(item);
+	print_finale(item);
+}
+
 static void parse_trace_buffer(char *buf, int size)
 {
 	struct trace_graph_item *item = (struct trace_graph_item *)buf;
 	int sz = size / sizeof(struct trace_graph_item), i;
 
-	printf("   Time(us)  |  Function Graph\n");
-	printf("-------------------------------\n");
+	printf("   Thread Name      |  Time(us)  |  Function Graph\n");
+	printf("--------------------------------------------------\n");
 	for (i = 0; i < sz; i++)
 		print_trace_item(item++);
 	return;
 }
 
-static int do_trace_cat(void)
+const char *tracefile = "/tmp/tracefile";
+
+static int trace_read_buffer(void)
 {
-	int fd, ret;
+	int fd, ret, tfd;
 	struct sd_req hdr;
 	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
 	unsigned rlen, wlen;
-	char *buf = xzalloc(TRACE_BUF_LEN * 12);
+#define TRACE_BUF_LEN      (1024 * 1024 * 20)
+	char *buf = xzalloc(TRACE_BUF_LEN);
+
+	tfd = open(tracefile, O_CREAT | O_RDWR | O_APPEND | O_TRUNC, 0644);
+	if (tfd < 0) {
+		fprintf(stderr, "can't create tracefile\n");
+		return EXIT_SYSFAIL;
+	}
 
 	fd = connect_to(sdhost, sdport);
 	if (fd < 0)
 		return EXIT_SYSFAIL;
 
+read_buffer:
 	sd_init_req(&hdr, SD_OP_TRACE_CAT);
 	hdr.data_length = rlen = TRACE_BUF_LEN;
 	hdr.epoch = sd_epoch;
 
 	wlen = 0;
 	ret = exec_req(fd, &hdr, buf, &wlen, &rlen);
-	close(fd);
 
 	if (ret) {
 		fprintf(stderr, "Failed to connect\n");
+		close(fd);
 		return EXIT_SYSFAIL;
 	}
 
 	if (rsp->result != SD_RES_SUCCESS) {
 		fprintf(stderr, "Trace failed: %s\n",
 				sd_strerror(rsp->result));
+		close(fd);
 		return EXIT_FAILURE;
 	}
 
-	parse_trace_buffer(buf, rlen);
+	xwrite(tfd, buf, rlen);
+	if (rlen == TRACE_BUF_LEN) {
+		memset(buf, 0, TRACE_BUF_LEN);
+		goto read_buffer;
+	}
 
+	close(fd);
 	free(buf);
 	return EXIT_SUCCESS;
 }
 
-static int debug_trace(int argc, char **argv)
+static int trace_start(int argc, char **argv)
 {
-	int ret, i, l;
+	int ret;
 	struct sd_req hdr;
 	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-	char *cmd = argv[optind];
-	int enabled;
-
-	l = strlen(cmd);
-	for (i = 0; i < l; i++)
-		cmd[i] = tolower(cmd[i]);
-
-	if (strcmp(cmd, "start") == 0) {
-		enabled = 1;
-		printf("start the tracing\n");
-	} else if (strcmp(cmd, "stop") == 0) {
-		enabled = 0;
-		printf("stop the tracing\n");
-	} else if (strcmp(cmd, "cat") == 0) {
-		printf("cat the tracing\n\n");
-		return do_trace_cat();
-	} else {
-		printf("unsupported operation\n");
+
+	sd_init_req(&hdr, SD_OP_TRACE);
+	hdr.epoch = sd_epoch;
+	hdr.data_length = 1;
+
+	ret = send_light_req(&hdr, sdhost, sdport);
+	if (ret) {
+		fprintf(stderr, "Trace start failed: %s\n",
+				sd_strerror(rsp->result));
 		return EXIT_FAILURE;
 	}
 
+	return EXIT_SUCCESS;
+}
+
+static int trace_stop(int argc, char **argv)
+{
+	int ret;
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
 	sd_init_req(&hdr, SD_OP_TRACE);
 	hdr.epoch = sd_epoch;
-	hdr.data_length = enabled;
+	hdr.data_length = 0;
 
 	ret = send_light_req(&hdr, sdhost, sdport);
 	if (ret) {
-		fprintf(stderr, "Trace failed: %s\n",
+		fprintf(stderr, "Trace stop failed: %s\n",
 				sd_strerror(rsp->result));
 		return EXIT_FAILURE;
 	}
 
+	return trace_read_buffer();
+}
+
+static int trace_cat(int argc, char **argv)
+{
+	int fd = open(tracefile, O_RDONLY);
+	struct stat st;
+	void *map;
+
+	if (fd < 0) {
+		fprintf(stderr, "%m\n");
+		return EXIT_SYSFAIL;
+	}
+
+	if (fstat(fd, &st) < 0) {
+		fprintf(stderr, "%m\n");
+		close(fd);
+		return EXIT_SYSFAIL;
+	}
+
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	close(fd);
+	if (map == MAP_FAILED) {
+		fprintf(stderr, "%m\n");
+		return EXIT_SYSFAIL;
+	}
+	parse_trace_buffer(map, st.st_size);
+	munmap(map, st.st_size);
+
 	return EXIT_SUCCESS;
 }
 
@@ -115,9 +197,33 @@ static int debug_parser(int ch, char *opt)
 	return 0;
 }
 
+/* Subcommand list of trace */
+static struct subcommand trace_cmd[] = {
+	{"start", NULL, NULL, "start the trace",
+	 NULL, 0, trace_start},
+	{"stop", NULL, NULL, "stop the trace",
+	 NULL, 0, trace_stop},
+	{"cat", NULL, NULL, "cat the trace",
+	 NULL, 0, trace_cat},
+	{NULL},
+};
+
+static int debug_trace(int argc, char **argv)
+{
+	int i;
+
+	for (i = 0; trace_cmd[i].name; i++) {
+		if (!strcmp(trace_cmd[i].name, argv[3]))
+			return trace_cmd[i].fn(argc, argv);
+	}
+
+	subcommand_usage(argv[1], argv[2], EXIT_FAILURE);
+	return EXIT_FAILURE;
+}
+
 static struct subcommand debug_cmd[] = {
-	{"trace", "{start, stop, cat}", "aph", "trace the node",
-	 NULL, 0, debug_trace},
+	{"trace", NULL, "aph", "trace the node",
+	 trace_cmd, SUBCMD_FLAG_NEED_THIRD_ARG, debug_trace},
 	{NULL,},
 };
 
diff --git a/include/sheep.h b/include/sheep.h
index a71b026..a2d0cd9 100644
--- a/include/sheep.h
+++ b/include/sheep.h
@@ -44,7 +44,6 @@ struct vdi_copy {
 #define TRACE_GRAPH_ENTRY  0x01
 #define TRACE_GRAPH_RETURN 0x02
 
-#define TRACE_BUF_LEN      (1024 * 1024 * 8)
 #define TRACE_FNAME_LEN    36
 #define TRACE_THREAD_LEN   20
 
-- 
1.7.10.2




More information about the sheepdog mailing list