[sheepdog] [PATCH 5/5] collie: rework debug trace funtions to use subcommand mechanism
Liu Yuan
namei.unix at gmail.com
Thu Aug 30 08:59:14 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 | 179 ++++++++++++++++++++++++++++++++++++++++++-------------
include/sheep.h | 1 -
2 files changed, 136 insertions(+), 44 deletions(-)
diff --git a/collie/debug.c b/collie/debug.c
index 2be873f..1e87a36 100644
--- a/collie/debug.c
+++ b/collie/debug.c
@@ -1,112 +1,181 @@
#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 * 4)
+ char *buf = xzalloc(TRACE_BUF_LEN);
+
+ tfd = open(tracefile, O_CREAT | O_RDWR | O_APPEND, 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 +184,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